diff options
| -rw-r--r-- | Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt | 5 | ||||
| -rw-r--r-- | drivers/memory/omap-gpmc.c | 106 |
2 files changed, 92 insertions, 19 deletions
diff --git a/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt b/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt index 97e71924dbbb..21055e210234 100644 --- a/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt +++ b/Documentation/devicetree/bindings/memory-controllers/omap-gpmc.txt | |||
| @@ -33,10 +33,13 @@ Required properties: | |||
| 33 | As this will change in the future, filling correct | 33 | As this will change in the future, filling correct |
| 34 | values here is a requirement. | 34 | values here is a requirement. |
| 35 | - interrupt-controller: The GPMC driver implements and interrupt controller for | 35 | - interrupt-controller: The GPMC driver implements and interrupt controller for |
| 36 | the NAND events "fifoevent" and "termcount". | 36 | the NAND events "fifoevent" and "termcount" plus the |
| 37 | rising/falling edges on the GPMC_WAIT pins. | ||
| 37 | The interrupt number mapping is as follows | 38 | The interrupt number mapping is as follows |
| 38 | 0 - NAND_fifoevent | 39 | 0 - NAND_fifoevent |
| 39 | 1 - NAND_termcount | 40 | 1 - NAND_termcount |
| 41 | 2 - GPMC_WAIT0 pin edge | ||
| 42 | 3 - GPMC_WAIT1 pin edge, and so on. | ||
| 40 | - interrupt-cells: Must be set to 2 | 43 | - interrupt-cells: Must be set to 2 |
| 41 | - gpio-controller: The GPMC driver implements a GPIO controller for the | 44 | - gpio-controller: The GPMC driver implements a GPIO controller for the |
| 42 | GPMC WAIT pins that can be used as general purpose inputs. | 45 | GPMC WAIT pins that can be used as general purpose inputs. |
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index 784a64f31a8b..ea9c89747950 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c | |||
| @@ -189,9 +189,7 @@ | |||
| 189 | #define GPMC_ECC_WRITE 1 /* Reset Hardware ECC for write */ | 189 | #define GPMC_ECC_WRITE 1 /* Reset Hardware ECC for write */ |
| 190 | #define GPMC_ECC_READSYN 2 /* Reset before syndrom is read back */ | 190 | #define GPMC_ECC_READSYN 2 /* Reset before syndrom is read back */ |
| 191 | 191 | ||
| 192 | /* XXX: Only NAND irq has been considered,currently these are the only ones used | 192 | #define GPMC_NR_NAND_IRQS 2 /* number of NAND specific IRQs */ |
| 193 | */ | ||
| 194 | #define GPMC_NR_IRQ 2 | ||
| 195 | 193 | ||
| 196 | enum gpmc_clk_domain { | 194 | enum gpmc_clk_domain { |
| 197 | GPMC_CD_FCLK, | 195 | GPMC_CD_FCLK, |
| @@ -239,6 +237,7 @@ struct gpmc_device { | |||
| 239 | int irq; | 237 | int irq; |
| 240 | struct irq_chip irq_chip; | 238 | struct irq_chip irq_chip; |
| 241 | struct gpio_chip gpio_chip; | 239 | struct gpio_chip gpio_chip; |
| 240 | int nirqs; | ||
| 242 | }; | 241 | }; |
| 243 | 242 | ||
| 244 | static struct irq_domain *gpmc_irq_domain; | 243 | static struct irq_domain *gpmc_irq_domain; |
| @@ -1155,7 +1154,8 @@ int gpmc_get_client_irq(unsigned irq_config) | |||
| 1155 | return 0; | 1154 | return 0; |
| 1156 | } | 1155 | } |
| 1157 | 1156 | ||
| 1158 | if (irq_config >= GPMC_NR_IRQ) | 1157 | /* we restrict this to NAND IRQs only */ |
| 1158 | if (irq_config >= GPMC_NR_NAND_IRQS) | ||
| 1159 | return 0; | 1159 | return 0; |
| 1160 | 1160 | ||
| 1161 | return irq_create_mapping(gpmc_irq_domain, irq_config); | 1161 | return irq_create_mapping(gpmc_irq_domain, irq_config); |
| @@ -1165,6 +1165,10 @@ static int gpmc_irq_endis(unsigned long hwirq, bool endis) | |||
| 1165 | { | 1165 | { |
| 1166 | u32 regval; | 1166 | u32 regval; |
| 1167 | 1167 | ||
| 1168 | /* bits GPMC_NR_NAND_IRQS to 8 are reserved */ | ||
| 1169 | if (hwirq >= GPMC_NR_NAND_IRQS) | ||
| 1170 | hwirq += 8 - GPMC_NR_NAND_IRQS; | ||
| 1171 | |||
| 1168 | regval = gpmc_read_reg(GPMC_IRQENABLE); | 1172 | regval = gpmc_read_reg(GPMC_IRQENABLE); |
| 1169 | if (endis) | 1173 | if (endis) |
| 1170 | regval |= BIT(hwirq); | 1174 | regval |= BIT(hwirq); |
| @@ -1185,9 +1189,64 @@ static void gpmc_irq_enable(struct irq_data *p) | |||
| 1185 | gpmc_irq_endis(p->hwirq, true); | 1189 | gpmc_irq_endis(p->hwirq, true); |
| 1186 | } | 1190 | } |
| 1187 | 1191 | ||
| 1188 | static void gpmc_irq_noop(struct irq_data *data) { } | 1192 | static void gpmc_irq_mask(struct irq_data *d) |
| 1193 | { | ||
| 1194 | gpmc_irq_endis(d->hwirq, false); | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | static void gpmc_irq_unmask(struct irq_data *d) | ||
| 1198 | { | ||
| 1199 | gpmc_irq_endis(d->hwirq, true); | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | static void gpmc_irq_edge_config(unsigned long hwirq, bool rising_edge) | ||
| 1203 | { | ||
| 1204 | u32 regval; | ||
| 1205 | |||
| 1206 | /* NAND IRQs polarity is not configurable */ | ||
| 1207 | if (hwirq < GPMC_NR_NAND_IRQS) | ||
| 1208 | return; | ||
| 1209 | |||
| 1210 | /* WAITPIN starts at BIT 8 */ | ||
| 1211 | hwirq += 8 - GPMC_NR_NAND_IRQS; | ||
| 1212 | |||
| 1213 | regval = gpmc_read_reg(GPMC_CONFIG); | ||
| 1214 | if (rising_edge) | ||
| 1215 | regval &= ~BIT(hwirq); | ||
| 1216 | else | ||
| 1217 | regval |= BIT(hwirq); | ||
| 1218 | |||
| 1219 | gpmc_write_reg(GPMC_CONFIG, regval); | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | static void gpmc_irq_ack(struct irq_data *d) | ||
| 1223 | { | ||
| 1224 | unsigned int hwirq = d->hwirq; | ||
| 1225 | |||
| 1226 | /* skip reserved bits */ | ||
| 1227 | if (hwirq >= GPMC_NR_NAND_IRQS) | ||
| 1228 | hwirq += 8 - GPMC_NR_NAND_IRQS; | ||
| 1229 | |||
| 1230 | /* Setting bit to 1 clears (or Acks) the interrupt */ | ||
| 1231 | gpmc_write_reg(GPMC_IRQSTATUS, BIT(hwirq)); | ||
| 1232 | } | ||
| 1233 | |||
| 1234 | static int gpmc_irq_set_type(struct irq_data *d, unsigned int trigger) | ||
| 1235 | { | ||
| 1236 | /* can't set type for NAND IRQs */ | ||
| 1237 | if (d->hwirq < GPMC_NR_NAND_IRQS) | ||
| 1238 | return -EINVAL; | ||
| 1239 | |||
| 1240 | /* We can support either rising or falling edge at a time */ | ||
| 1241 | if (trigger == IRQ_TYPE_EDGE_FALLING) | ||
| 1242 | gpmc_irq_edge_config(d->hwirq, false); | ||
| 1243 | else if (trigger == IRQ_TYPE_EDGE_RISING) | ||
| 1244 | gpmc_irq_edge_config(d->hwirq, true); | ||
| 1245 | else | ||
| 1246 | return -EINVAL; | ||
| 1189 | 1247 | ||
| 1190 | static unsigned int gpmc_irq_noop_ret(struct irq_data *data) { return 0; } | 1248 | return 0; |
| 1249 | } | ||
| 1191 | 1250 | ||
| 1192 | static int gpmc_irq_map(struct irq_domain *d, unsigned int virq, | 1251 | static int gpmc_irq_map(struct irq_domain *d, unsigned int virq, |
| 1193 | irq_hw_number_t hw) | 1252 | irq_hw_number_t hw) |
| @@ -1195,8 +1254,14 @@ static int gpmc_irq_map(struct irq_domain *d, unsigned int virq, | |||
| 1195 | struct gpmc_device *gpmc = d->host_data; | 1254 | struct gpmc_device *gpmc = d->host_data; |
| 1196 | 1255 | ||
| 1197 | irq_set_chip_data(virq, gpmc); | 1256 | irq_set_chip_data(virq, gpmc); |
| 1198 | irq_set_chip_and_handler(virq, &gpmc->irq_chip, handle_simple_irq); | 1257 | if (hw < GPMC_NR_NAND_IRQS) { |
| 1199 | irq_modify_status(virq, IRQ_NOREQUEST, IRQ_NOAUTOEN); | 1258 | irq_modify_status(virq, IRQ_NOREQUEST, IRQ_NOAUTOEN); |
| 1259 | irq_set_chip_and_handler(virq, &gpmc->irq_chip, | ||
| 1260 | handle_simple_irq); | ||
| 1261 | } else { | ||
| 1262 | irq_set_chip_and_handler(virq, &gpmc->irq_chip, | ||
| 1263 | handle_edge_irq); | ||
| 1264 | } | ||
| 1200 | 1265 | ||
| 1201 | return 0; | 1266 | return 0; |
| 1202 | } | 1267 | } |
| @@ -1209,16 +1274,21 @@ static const struct irq_domain_ops gpmc_irq_domain_ops = { | |||
| 1209 | static irqreturn_t gpmc_handle_irq(int irq, void *data) | 1274 | static irqreturn_t gpmc_handle_irq(int irq, void *data) |
| 1210 | { | 1275 | { |
| 1211 | int hwirq, virq; | 1276 | int hwirq, virq; |
| 1212 | u32 regval; | 1277 | u32 regval, regvalx; |
| 1213 | struct gpmc_device *gpmc = data; | 1278 | struct gpmc_device *gpmc = data; |
| 1214 | 1279 | ||
| 1215 | regval = gpmc_read_reg(GPMC_IRQSTATUS); | 1280 | regval = gpmc_read_reg(GPMC_IRQSTATUS); |
| 1281 | regvalx = regval; | ||
| 1216 | 1282 | ||
| 1217 | if (!regval) | 1283 | if (!regval) |
| 1218 | return IRQ_NONE; | 1284 | return IRQ_NONE; |
| 1219 | 1285 | ||
| 1220 | for (hwirq = 0; hwirq < GPMC_NR_IRQ; hwirq++) { | 1286 | for (hwirq = 0; hwirq < gpmc->nirqs; hwirq++) { |
| 1221 | if (regval & BIT(hwirq)) { | 1287 | /* skip reserved status bits */ |
| 1288 | if (hwirq == GPMC_NR_NAND_IRQS) | ||
| 1289 | regvalx >>= 8 - GPMC_NR_NAND_IRQS; | ||
| 1290 | |||
| 1291 | if (regvalx & BIT(hwirq)) { | ||
| 1222 | virq = irq_find_mapping(gpmc_irq_domain, hwirq); | 1292 | virq = irq_find_mapping(gpmc_irq_domain, hwirq); |
| 1223 | if (!virq) { | 1293 | if (!virq) { |
| 1224 | dev_warn(gpmc->dev, | 1294 | dev_warn(gpmc->dev, |
| @@ -1248,16 +1318,15 @@ static int gpmc_setup_irq(struct gpmc_device *gpmc) | |||
| 1248 | gpmc_write_reg(GPMC_IRQSTATUS, regval); | 1318 | gpmc_write_reg(GPMC_IRQSTATUS, regval); |
| 1249 | 1319 | ||
| 1250 | gpmc->irq_chip.name = "gpmc"; | 1320 | gpmc->irq_chip.name = "gpmc"; |
| 1251 | gpmc->irq_chip.irq_startup = gpmc_irq_noop_ret; | ||
| 1252 | gpmc->irq_chip.irq_enable = gpmc_irq_enable; | 1321 | gpmc->irq_chip.irq_enable = gpmc_irq_enable; |
| 1253 | gpmc->irq_chip.irq_disable = gpmc_irq_disable; | 1322 | gpmc->irq_chip.irq_disable = gpmc_irq_disable; |
| 1254 | gpmc->irq_chip.irq_shutdown = gpmc_irq_noop; | 1323 | gpmc->irq_chip.irq_ack = gpmc_irq_ack; |
| 1255 | gpmc->irq_chip.irq_ack = gpmc_irq_noop; | 1324 | gpmc->irq_chip.irq_mask = gpmc_irq_mask; |
| 1256 | gpmc->irq_chip.irq_mask = gpmc_irq_noop; | 1325 | gpmc->irq_chip.irq_unmask = gpmc_irq_unmask; |
| 1257 | gpmc->irq_chip.irq_unmask = gpmc_irq_noop; | 1326 | gpmc->irq_chip.irq_set_type = gpmc_irq_set_type; |
| 1258 | 1327 | ||
| 1259 | gpmc_irq_domain = irq_domain_add_linear(gpmc->dev->of_node, | 1328 | gpmc_irq_domain = irq_domain_add_linear(gpmc->dev->of_node, |
| 1260 | GPMC_NR_IRQ, | 1329 | gpmc->nirqs, |
| 1261 | &gpmc_irq_domain_ops, | 1330 | &gpmc_irq_domain_ops, |
| 1262 | gpmc); | 1331 | gpmc); |
| 1263 | if (!gpmc_irq_domain) { | 1332 | if (!gpmc_irq_domain) { |
| @@ -1282,7 +1351,7 @@ static int gpmc_free_irq(struct gpmc_device *gpmc) | |||
| 1282 | 1351 | ||
| 1283 | free_irq(gpmc->irq, gpmc); | 1352 | free_irq(gpmc->irq, gpmc); |
| 1284 | 1353 | ||
| 1285 | for (hwirq = 0; hwirq < GPMC_NR_IRQ; hwirq++) | 1354 | for (hwirq = 0; hwirq < gpmc->nirqs; hwirq++) |
| 1286 | irq_dispose_mapping(irq_find_mapping(gpmc_irq_domain, hwirq)); | 1355 | irq_dispose_mapping(irq_find_mapping(gpmc_irq_domain, hwirq)); |
| 1287 | 1356 | ||
| 1288 | irq_domain_remove(gpmc_irq_domain); | 1357 | irq_domain_remove(gpmc_irq_domain); |
| @@ -2296,6 +2365,7 @@ static int gpmc_probe(struct platform_device *pdev) | |||
| 2296 | if (rc) | 2365 | if (rc) |
| 2297 | goto gpio_init_failed; | 2366 | goto gpio_init_failed; |
| 2298 | 2367 | ||
| 2368 | gpmc->nirqs = GPMC_NR_NAND_IRQS + gpmc_nr_waitpins; | ||
| 2299 | rc = gpmc_setup_irq(gpmc); | 2369 | rc = gpmc_setup_irq(gpmc); |
| 2300 | if (rc) { | 2370 | if (rc) { |
| 2301 | dev_err(gpmc->dev, "gpmc_setup_irq failed\n"); | 2371 | dev_err(gpmc->dev, "gpmc_setup_irq failed\n"); |
