|
@@ -494,3 +494,185 @@ static struct irq_chip balloon3_irq_chip = {
|
|
|
.name = "FPGA",
|
|
|
.irq_ack = balloon3_mask_irq,
|
|
|
.irq_mask = balloon3_mask_irq,
|
|
|
+ .irq_unmask = balloon3_unmask_irq,
|
|
|
+};
|
|
|
+
|
|
|
+static void balloon3_irq_handler(unsigned int irq, struct irq_desc *desc)
|
|
|
+{
|
|
|
+ unsigned long pending = __raw_readl(BALLOON3_INT_CONTROL_REG) &
|
|
|
+ balloon3_irq_enabled;
|
|
|
+ do {
|
|
|
+ /* clear useless edge notification */
|
|
|
+ if (desc->irq_data.chip->irq_ack) {
|
|
|
+ struct irq_data *d;
|
|
|
+
|
|
|
+ d = irq_get_irq_data(BALLOON3_AUX_NIRQ);
|
|
|
+ desc->irq_data.chip->irq_ack(d);
|
|
|
+ }
|
|
|
+
|
|
|
+ while (pending) {
|
|
|
+ irq = BALLOON3_IRQ(0) + __ffs(pending);
|
|
|
+ generic_handle_irq(irq);
|
|
|
+ pending &= pending - 1;
|
|
|
+ }
|
|
|
+ pending = __raw_readl(BALLOON3_INT_CONTROL_REG) &
|
|
|
+ balloon3_irq_enabled;
|
|
|
+ } while (pending);
|
|
|
+}
|
|
|
+
|
|
|
+static void __init balloon3_init_irq(void)
|
|
|
+{
|
|
|
+ int irq;
|
|
|
+
|
|
|
+ pxa27x_init_irq();
|
|
|
+ /* setup extra Balloon3 irqs */
|
|
|
+ for (irq = BALLOON3_IRQ(0); irq <= BALLOON3_IRQ(7); irq++) {
|
|
|
+ irq_set_chip_and_handler(irq, &balloon3_irq_chip,
|
|
|
+ handle_level_irq);
|
|
|
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
|
|
+ }
|
|
|
+
|
|
|
+ irq_set_chained_handler(BALLOON3_AUX_NIRQ, balloon3_irq_handler);
|
|
|
+ irq_set_irq_type(BALLOON3_AUX_NIRQ, IRQ_TYPE_EDGE_FALLING);
|
|
|
+
|
|
|
+ pr_debug("%s: chained handler installed - irq %d automatically "
|
|
|
+ "enabled\n", __func__, BALLOON3_AUX_NIRQ);
|
|
|
+}
|
|
|
+
|
|
|
+/******************************************************************************
|
|
|
+ * GPIO expander
|
|
|
+ ******************************************************************************/
|
|
|
+#if defined(CONFIG_GPIO_PCF857X) || defined(CONFIG_GPIO_PCF857X_MODULE)
|
|
|
+static struct pcf857x_platform_data balloon3_pcf857x_pdata = {
|
|
|
+ .gpio_base = BALLOON3_PCF_GPIO_BASE,
|
|
|
+ .n_latch = 0,
|
|
|
+ .setup = NULL,
|
|
|
+ .teardown = NULL,
|
|
|
+ .context = NULL,
|
|
|
+};
|
|
|
+
|
|
|
+static struct i2c_board_info __initdata balloon3_i2c_devs[] = {
|
|
|
+ {
|
|
|
+ I2C_BOARD_INFO("pcf8574a", 0x38),
|
|
|
+ .platform_data = &balloon3_pcf857x_pdata,
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+static void __init balloon3_i2c_init(void)
|
|
|
+{
|
|
|
+ pxa_set_i2c_info(NULL);
|
|
|
+ i2c_register_board_info(0, ARRAY_AND_SIZE(balloon3_i2c_devs));
|
|
|
+}
|
|
|
+#else
|
|
|
+static inline void balloon3_i2c_init(void) {}
|
|
|
+#endif
|
|
|
+
|
|
|
+/******************************************************************************
|
|
|
+ * NAND
|
|
|
+ ******************************************************************************/
|
|
|
+#if defined(CONFIG_MTD_NAND_PLATFORM)||defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
|
|
|
+static void balloon3_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
|
|
|
+{
|
|
|
+ struct nand_chip *this = mtd->priv;
|
|
|
+ uint8_t balloon3_ctl_set = 0, balloon3_ctl_clr = 0;
|
|
|
+
|
|
|
+ if (ctrl & NAND_CTRL_CHANGE) {
|
|
|
+ if (ctrl & NAND_CLE)
|
|
|
+ balloon3_ctl_set |= BALLOON3_NAND_CONTROL_FLCLE;
|
|
|
+ else
|
|
|
+ balloon3_ctl_clr |= BALLOON3_NAND_CONTROL_FLCLE;
|
|
|
+
|
|
|
+ if (ctrl & NAND_ALE)
|
|
|
+ balloon3_ctl_set |= BALLOON3_NAND_CONTROL_FLALE;
|
|
|
+ else
|
|
|
+ balloon3_ctl_clr |= BALLOON3_NAND_CONTROL_FLALE;
|
|
|
+
|
|
|
+ if (balloon3_ctl_clr)
|
|
|
+ __raw_writel(balloon3_ctl_clr,
|
|
|
+ BALLOON3_NAND_CONTROL_REG);
|
|
|
+ if (balloon3_ctl_set)
|
|
|
+ __raw_writel(balloon3_ctl_set,
|
|
|
+ BALLOON3_NAND_CONTROL_REG +
|
|
|
+ BALLOON3_FPGA_SETnCLR);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cmd != NAND_CMD_NONE)
|
|
|
+ writeb(cmd, this->IO_ADDR_W);
|
|
|
+}
|
|
|
+
|
|
|
+static void balloon3_nand_select_chip(struct mtd_info *mtd, int chip)
|
|
|
+{
|
|
|
+ if (chip < 0 || chip > 3)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* Assert all nCE lines */
|
|
|
+ __raw_writew(
|
|
|
+ BALLOON3_NAND_CONTROL_FLCE0 | BALLOON3_NAND_CONTROL_FLCE1 |
|
|
|
+ BALLOON3_NAND_CONTROL_FLCE2 | BALLOON3_NAND_CONTROL_FLCE3,
|
|
|
+ BALLOON3_NAND_CONTROL_REG + BALLOON3_FPGA_SETnCLR);
|
|
|
+
|
|
|
+ /* Deassert correct nCE line */
|
|
|
+ __raw_writew(BALLOON3_NAND_CONTROL_FLCE0 << chip,
|
|
|
+ BALLOON3_NAND_CONTROL_REG);
|
|
|
+}
|
|
|
+
|
|
|
+static int balloon3_nand_dev_ready(struct mtd_info *mtd)
|
|
|
+{
|
|
|
+ return __raw_readl(BALLOON3_NAND_STAT_REG) & BALLOON3_NAND_STAT_RNB;
|
|
|
+}
|
|
|
+
|
|
|
+static int balloon3_nand_probe(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ uint16_t ver;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ __raw_writew(BALLOON3_NAND_CONTROL2_16BIT,
|
|
|
+ BALLOON3_NAND_CONTROL2_REG + BALLOON3_FPGA_SETnCLR);
|
|
|
+
|
|
|
+ ver = __raw_readw(BALLOON3_FPGA_VER);
|
|
|
+ if (ver < 0x4f08)
|
|
|
+ pr_warn("The FPGA code, version 0x%04x, is too old. "
|
|
|
+ "NAND support might be broken in this version!", ver);
|
|
|
+
|
|
|
+ /* Power up the NAND chips */
|
|
|
+ ret = gpio_request(BALLOON3_GPIO_RUN_NAND, "NAND");
|
|
|
+ if (ret)
|
|
|
+ goto err1;
|
|
|
+
|
|
|
+ ret = gpio_direction_output(BALLOON3_GPIO_RUN_NAND, 1);
|
|
|
+ if (ret)
|
|
|
+ goto err2;
|
|
|
+
|
|
|
+ gpio_set_value(BALLOON3_GPIO_RUN_NAND, 1);
|
|
|
+
|
|
|
+ /* Deassert all nCE lines and write protect line */
|
|
|
+ __raw_writel(
|
|
|
+ BALLOON3_NAND_CONTROL_FLCE0 | BALLOON3_NAND_CONTROL_FLCE1 |
|
|
|
+ BALLOON3_NAND_CONTROL_FLCE2 | BALLOON3_NAND_CONTROL_FLCE3 |
|
|
|
+ BALLOON3_NAND_CONTROL_FLWP,
|
|
|
+ BALLOON3_NAND_CONTROL_REG + BALLOON3_FPGA_SETnCLR);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err2:
|
|
|
+ gpio_free(BALLOON3_GPIO_RUN_NAND);
|
|
|
+err1:
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static void balloon3_nand_remove(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ /* Power down the NAND chips */
|
|
|
+ gpio_set_value(BALLOON3_GPIO_RUN_NAND, 0);
|
|
|
+ gpio_free(BALLOON3_GPIO_RUN_NAND);
|
|
|
+}
|
|
|
+
|
|
|
+static struct mtd_partition balloon3_partition_info[] = {
|
|
|
+ [0] = {
|
|
|
+ .name = "Boot",
|
|
|
+ .offset = 0,
|
|
|
+ .size = SZ_4M,
|
|
|
+ },
|
|
|
+ [1] = {
|
|
|
+ .name = "RootFS",
|
|
|
+ .offset = MTDPART_OFS_APPEND,
|
|
|
+ .size = MTDPART_SIZ_FULL
|