--- a/drivers/gpio/gpio-realtek-otto.c +++ b/drivers/gpio/gpio-realtek-otto.c @@ -55,9 +55,12 @@ struct realtek_gpio_ctrl { struct gpio_chip gc; void __iomem *base; + void __iomem *cpumap_base; raw_spinlock_t lock; u16 intr_mask[REALTEK_GPIO_PORTS_PER_BANK]; u16 intr_type[REALTEK_GPIO_PORTS_PER_BANK]; + unsigned int (*port_offset_u8)(unsigned int port); + unsigned int (*port_offset_u16)(unsigned int port); }; /* Expand with more flags as devices with other quirks are added */ @@ -69,6 +72,16 @@ enum realtek_gpio_flags { * line the IRQ handler was assigned to, causing uncaught interrupts. */ GPIO_INTERRUPTS_DISABLED = BIT(0), + /* + * Port order is reversed, meaning DCBA register layout for 1-bit + * fields, and [BA, DC] for 2-bit fields. + */ + GPIO_PORTS_REVERSED = BIT(1), + /* + * Interrupts can be enabled per cpu. This requires a secondary IO + * range, where the per-cpu enable masks are located. + */ + GPIO_INTERRUPTS_PER_CPU = BIT(2), }; static struct realtek_gpio_ctrl *irq_data_to_ctrl(struct irq_data *data) @@ -86,21 +99,50 @@ static struct realtek_gpio_ctrl *irq_dat * port. The two interrupt mask registers store two bits per GPIO, so use u16 * values. */ +static unsigned int realtek_gpio_port_offset_u8(unsigned int port) +{ + return port; +} + +static unsigned int realtek_gpio_port_offset_u16(unsigned int port) +{ + return 2 * port; +} + +/* + * Reversed port order register access + * + * For registers with one bit per GPIO, all ports are stored as u8-s in one + * register in reversed order. The two interrupt mask registers store two bits + * per GPIO, so use u16 values. The first register contains ports 1 and 0, the + * second ports 3 and 2. + */ +static unsigned int realtek_gpio_port_offset_u8_rev(unsigned int port) +{ + return 3 - port; +} + +static unsigned int realtek_gpio_port_offset_u16_rev(unsigned int port) +{ + return 2 * (port ^ 1); +} + static void realtek_gpio_write_imr(struct realtek_gpio_ctrl *ctrl, unsigned int port, u16 irq_type, u16 irq_mask) { - iowrite16(irq_type & irq_mask, ctrl->base + REALTEK_GPIO_REG_IMR + 2 * port); + iowrite16(irq_type & irq_mask, + ctrl->base + REALTEK_GPIO_REG_IMR + ctrl->port_offset_u16(port)); } static void realtek_gpio_clear_isr(struct realtek_gpio_ctrl *ctrl, unsigned int port, u8 mask) { - iowrite8(mask, ctrl->base + REALTEK_GPIO_REG_ISR + port); + iowrite8(mask, ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port)); } static u8 realtek_gpio_read_isr(struct realtek_gpio_ctrl *ctrl, unsigned int port) { - return ioread8(ctrl->base + REALTEK_GPIO_REG_ISR + port); + return ioread8(ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port)); } /* Set the rising and falling edge mask bits for a GPIO port pin */ @@ -222,6 +264,12 @@ static int realtek_gpio_irq_init(struct for (port = 0; (port * 8) < gc->ngpio; port++) { realtek_gpio_write_imr(ctrl, port, 0, 0); realtek_gpio_clear_isr(ctrl, port, GENMASK(7, 0)); + + if (ctrl->cpumap_base) { + /* Default CPU affinity to the first CPU */ + iowrite8(GENMASK(7, 0), + ctrl->cpumap_base + ctrl->port_offset_u8(port)); + } } return 0; @@ -246,6 +294,13 @@ static const struct of_device_id realtek { .compatible = "realtek,rtl8390-gpio", }, + { + .compatible = "realtek,rtl9300-gpio", + .data = (void *)(GPIO_PORTS_REVERSED | GPIO_INTERRUPTS_PER_CPU) + }, + { + .compatible = "realtek,rtl9310-gpio", + }, {} }; MODULE_DEVICE_TABLE(of, realtek_gpio_of_match); @@ -253,12 +308,14 @@ MODULE_DEVICE_TABLE(of, realtek_gpio_of_ static int realtek_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + unsigned long bgpio_flags; unsigned int dev_flags; struct gpio_irq_chip *girq; struct realtek_gpio_ctrl *ctrl; u32 ngpios; int err, irq; + pr_info("%s probing RTL GPIO\n", __func__); ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); if (!ctrl) return -ENOMEM; @@ -280,10 +337,21 @@ static int realtek_gpio_probe(struct pla raw_spin_lock_init(&ctrl->lock); + if (dev_flags & GPIO_PORTS_REVERSED) { + bgpio_flags = 0; + ctrl->port_offset_u8 = realtek_gpio_port_offset_u8_rev; + ctrl->port_offset_u16 = realtek_gpio_port_offset_u16_rev; + } + else { + bgpio_flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER; + ctrl->port_offset_u8 = realtek_gpio_port_offset_u8; + ctrl->port_offset_u16 = realtek_gpio_port_offset_u16; + } + err = bgpio_init(&ctrl->gc, dev, 4, ctrl->base + REALTEK_GPIO_REG_DATA, NULL, NULL, ctrl->base + REALTEK_GPIO_REG_DIR, NULL, - BGPIOF_BIG_ENDIAN_BYTE_ORDER); + bgpio_flags); if (err) { dev_err(dev, "unable to init generic GPIO"); return err; @@ -308,6 +376,13 @@ static int realtek_gpio_probe(struct pla girq->init_hw = realtek_gpio_irq_init; } + if (dev_flags & GPIO_INTERRUPTS_PER_CPU) { + ctrl->cpumap_base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(ctrl->cpumap_base)) + return dev_err_probe(dev, PTR_ERR(ctrl->cpumap_base), + "IRQ CPU map registers not defined"); + } + return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl); }