mirror of
https://github.com/openwrt/openwrt.git
synced 2025-01-18 18:56:37 +00:00
realtek: Add GPIO support for RTL930X and RTL931X
We add support for the RTL930X and RTL931X architectures in the gpio-realtek-otto.c driver. Signed-off-by: Sebastian Gottschall <s.gottschall@dd-wrt.com> Signed-off-by: Birger Koblitz <git@birger-koblitz.de>
This commit is contained in:
parent
58b82e6ca5
commit
2314ba725b
@ -0,0 +1,165 @@
|
||||
--- 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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user