Răsfoiți Sursa

[dm][pin][pinctrl] add new driver

1. ARM PL061 GPIO
2. Single Pinctrl

Signed-off-by: GuEe-GUI <2991707448@qq.com>
GuEe-GUI 2 luni în urmă
părinte
comite
357c9b7b5a

+ 6 - 0
components/drivers/pin/Kconfig

@@ -2,6 +2,12 @@ menuconfig RT_USING_PIN
     bool "Using Generic GPIO device drivers"
     bool "Using Generic GPIO device drivers"
     default y
     default y
 
 
+config RT_PIN_PL061
+    bool "ARM PL061"
+    depends on RT_USING_DM
+    depends on RT_USING_PIN
+    default n
+
 if RT_USING_DM && RT_USING_PIN
 if RT_USING_DM && RT_USING_PIN
     osource "$(SOC_DM_PIN_DIR)/Kconfig"
     osource "$(SOC_DM_PIN_DIR)/Kconfig"
 endif
 endif

+ 3 - 0
components/drivers/pin/SConscript

@@ -16,6 +16,9 @@ if GetDepend(['RT_USING_DM']):
 if GetDepend(['RT_USING_OFW']):
 if GetDepend(['RT_USING_OFW']):
     src += ['dev_pin_ofw.c']
     src += ['dev_pin_ofw.c']
 
 
+if GetDepend(['RT_PIN_PL061']):
+    src += ['pin-pl061.c']
+
 group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
 group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
 
 
 Return('group')
 Return('group')

+ 357 - 0
components/drivers/pin/pin-pl061.c

@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2022-11-26     GuEe-GUI     first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#include "dev_pin_dm.h"
+
+#define PL061_DIR       0x400
+#define PL061_IS        0x404
+#define PL061_IBE       0x408
+#define PL061_IEV       0x40c
+#define PL061_IE        0x410
+#define PL061_RIS       0x414
+#define PL061_MIS       0x418
+#define PL061_IC        0x41c
+
+#define PL061_GPIO_NR   8
+
+struct pl061
+{
+    struct rt_device_pin parent;
+
+    int irq;
+    void *base;
+
+    struct rt_clk *pclk;
+    struct rt_spinlock spinlock;
+};
+
+#define raw_to_pl061(raw) rt_container_of(raw, struct pl061, parent)
+
+rt_inline rt_uint8_t pl061_read(struct pl061 *pl061, int offset)
+{
+    return HWREG8(pl061->base + offset);
+}
+
+rt_inline void pl061_write(struct pl061 *pl061, int offset, rt_uint8_t value)
+{
+    HWREG8(pl061->base + offset) = value;
+}
+
+static void pl061_isr(int irqno, void *param)
+{
+    rt_uint8_t mask = 0;
+    rt_ubase_t pending, level;
+    struct pl061 *pl061 = (struct pl061 *)param;
+
+    level = rt_spin_lock_irqsave(&pl061->spinlock);
+
+    pending = pl061_read(pl061, PL061_MIS);
+
+    rt_spin_unlock_irqrestore(&pl061->spinlock, level);
+
+    if (pending)
+    {
+        for (int pin = 0; pin < PL061_GPIO_NR; ++pin)
+        {
+            if (pending & RT_BIT(pin))
+            {
+                mask |= RT_BIT(pin);
+
+                pin_pic_handle_isr(&pl061->parent, pin);
+            }
+        }
+
+        level = rt_spin_lock_irqsave(&pl061->spinlock);
+
+        pl061_write(pl061, PL061_IC, mask);
+
+        rt_spin_unlock_irqrestore(&pl061->spinlock, level);
+    }
+}
+
+static void pl061_pin_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode)
+{
+    struct pl061 *pl061 = raw_to_pl061(device);
+
+    if (pin >= 0 && pin < PL061_GPIO_NR)
+    {
+        rt_base_t level = rt_spin_lock_irqsave(&pl061->spinlock);
+
+        switch (mode)
+        {
+        case PIN_MODE_OUTPUT:
+
+            pl061_write(pl061, RT_BIT(pin + 2), 1 << pin);
+            pl061_write(pl061, PL061_DIR, pl061_read(pl061, PL061_DIR) | RT_BIT(pin));
+
+            /*
+             * gpio value is set again, because pl061 doesn't allow to set value
+             * of a gpio pin before configuring it in OUT mode.
+             */
+            pl061_write(pl061, RT_BIT(pin + 2), 1 << pin);
+
+            break;
+
+        case PIN_MODE_INPUT:
+
+            pl061_write(pl061, PL061_DIR, pl061_read(pl061, PL061_DIR) & ~RT_BIT(pin));
+
+            break;
+
+        default:
+            break;
+        }
+
+        rt_spin_unlock_irqrestore(&pl061->spinlock, level);
+    }
+}
+
+static void pl061_pin_write(struct rt_device *device, rt_base_t pin, rt_uint8_t value)
+{
+    struct pl061 *pl061 = raw_to_pl061(device);
+
+    if (pin >= 0 && pin < PL061_GPIO_NR)
+    {
+        pl061_write(pl061, RT_BIT(pin + 2), !!value << pin);
+    }
+}
+
+static rt_ssize_t pl061_pin_read(struct rt_device *device, rt_base_t pin)
+{
+    rt_int8_t value = -RT_EINVAL;
+    struct pl061 *pl061 = raw_to_pl061(device);
+
+    if (pin >= 0 && pin < PL061_GPIO_NR)
+    {
+        value = !!pl061_read(pl061, RT_BIT(pin + 2));
+    }
+
+    return value;
+}
+
+static rt_err_t pl061_pin_irq_enable(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled)
+{
+    rt_err_t err = RT_EOK;
+    struct pl061 *pl061 = raw_to_pl061(device);
+
+    if (pin >= 0 && pin < PL061_GPIO_NR)
+    {
+        rt_uint8_t gpioie, mask = RT_BIT(pin);
+        rt_ubase_t level = rt_spin_lock_irqsave(&pl061->spinlock);
+
+        if (enabled)
+        {
+            gpioie = pl061_read(pl061, PL061_IE) | mask;
+        }
+        else
+        {
+            gpioie = pl061_read(pl061, PL061_IE) & ~mask;
+        }
+
+        pl061_write(pl061, PL061_IE, gpioie);
+
+        rt_spin_unlock_irqrestore(&pl061->spinlock, level);
+    }
+    else
+    {
+        err = -RT_EINVAL;
+    }
+
+    return err;
+}
+
+static rt_err_t pl061_pin_irq_mode(struct rt_device *device, rt_base_t pin, rt_uint8_t mode)
+{
+    rt_err_t err = RT_EOK;
+    struct pl061 *pl061 = raw_to_pl061(device);
+
+    if (pin >= 0 && pin < PL061_GPIO_NR)
+    {
+        rt_uint8_t gpiois, gpioibe, gpioiev, bit = RT_BIT(pin);
+        rt_ubase_t level = rt_spin_lock_irqsave(&pl061->spinlock);
+
+        gpioiev = pl061_read(pl061, PL061_IEV);
+        gpiois  = pl061_read(pl061, PL061_IS);
+        gpioibe = pl061_read(pl061, PL061_IBE);
+
+        if (mode == PIN_IRQ_MODE_HIGH_LEVEL || mode == PIN_IRQ_MODE_LOW_LEVEL)
+        {
+            rt_bool_t polarity = (mode == PIN_IRQ_MODE_HIGH_LEVEL);
+
+            /* Disable edge detection */
+            gpioibe &= ~bit;
+            /* Enable level detection */
+            gpiois |= bit;
+
+            /* Select polarity */
+            if (polarity)
+            {
+                gpioiev |= bit;
+            }
+            else
+            {
+                gpioiev &= ~bit;
+            }
+        }
+        else if (mode == PIN_IRQ_MODE_RISING_FALLING)
+        {
+            /* Disable level detection */
+            gpiois &= ~bit;
+            /* Select both edges, setting this makes PL061_EV be ignored */
+            gpioibe |= bit;
+        }
+        else if (mode == PIN_IRQ_MODE_RISING || mode == PIN_IRQ_MODE_FALLING)
+        {
+            rt_bool_t rising = (mode == PIN_IRQ_MODE_RISING);
+
+            /* Disable level detection */
+            gpiois &= ~bit;
+            /* Clear detection on both edges */
+            gpioibe &= ~bit;
+
+            /* Select edge */
+            if (rising)
+            {
+                gpioiev |= bit;
+            }
+            else
+            {
+                gpioiev &= ~bit;
+            }
+        }
+        else
+        {
+            /* No trigger: disable everything */
+            gpiois  &= ~bit;
+            gpioibe &= ~bit;
+            gpioiev &= ~bit;
+        }
+
+        pl061_write(pl061, PL061_IS, gpiois);
+        pl061_write(pl061, PL061_IBE, gpioibe);
+        pl061_write(pl061, PL061_IEV, gpioiev);
+
+        rt_spin_unlock_irqrestore(&pl061->spinlock, level);
+    }
+    else
+    {
+        err = -RT_EINVAL;
+    }
+
+    return err;
+}
+
+static const struct rt_pin_ops pl061_pin_ops =
+{
+    .pin_mode = pl061_pin_mode,
+    .pin_write = pl061_pin_write,
+    .pin_read = pl061_pin_read,
+    .pin_irq_enable = pl061_pin_irq_enable,
+    .pin_irq_mode = pl061_pin_irq_mode,
+};
+
+static rt_err_t pl061_probe(struct rt_platform_device *pdev)
+{
+    rt_err_t err;
+    struct rt_device *dev = &pdev->parent;
+    struct pl061 *pl061 = rt_calloc(1, sizeof(*pl061));
+
+    if (!pl061)
+    {
+        return -RT_ENOMEM;
+    }
+
+    pl061->base = rt_dm_dev_iomap(dev, 0);
+
+    if (!pl061->base)
+    {
+        err = -RT_EIO;
+
+        goto _fail;
+    }
+
+    pl061->irq = rt_dm_dev_get_irq(dev, 0);
+
+    if (pl061->irq < 0)
+    {
+        err = pl061->irq;
+
+        goto _fail;
+    }
+
+    pl061->pclk = rt_clk_get_by_name(dev, "apb_pclk");
+
+    if (rt_is_err(pl061->pclk))
+    {
+        err = rt_ptr_err(pl061->pclk);
+
+        goto _fail;
+    }
+
+    if ((err = rt_clk_prepare_enable(pl061->pclk)))
+    {
+        goto _fail;
+    }
+
+    rt_dm_dev_bind_fwdata(dev, RT_NULL, &pl061->parent);
+
+    rt_spin_lock_init(&pl061->spinlock);
+
+    pl061->parent.ops = &pl061_pin_ops;
+    pin_api_init(&pl061->parent, PL061_GPIO_NR);
+    pin_pic_init(&pl061->parent, pl061->irq);
+
+    rt_hw_interrupt_install(pl061->irq, pl061_isr, pl061, "gpio-pl061");
+    rt_hw_interrupt_umask(pl061->irq);
+
+    return RT_EOK;
+
+_fail:
+    if (pl061->base)
+    {
+        rt_iounmap(pl061->base);
+    }
+
+    if (!rt_is_err_or_null(pl061->pclk))
+    {
+        rt_clk_disable_unprepare(pl061->pclk);
+        rt_clk_put(pl061->pclk);
+    }
+
+    rt_free(pl061);
+
+    return err;
+}
+
+static const struct rt_ofw_node_id pl061_ofw_ids[] =
+{
+    { .compatible = "arm,pl061" },
+    { /* sentinel */ }
+};
+
+static struct rt_platform_driver pl061_driver =
+{
+    .name = "pin-pl061",
+    .ids = pl061_ofw_ids,
+
+    .probe = pl061_probe,
+};
+
+static int pl061_drv_register(void)
+{
+    rt_platform_driver_register(&pl061_driver);
+
+    return 0;
+}
+INIT_SUBSYS_EXPORT(pl061_drv_register);

+ 5 - 0
components/drivers/pinctrl/Kconfig

@@ -4,6 +4,11 @@ menuconfig RT_USING_PINCTRL
     depends on RT_USING_PIN
     depends on RT_USING_PIN
     default n
     default n
 
 
+config RT_PINCTRL_SINGLE
+    bool "Single Pinctrl driver"
+    depends on RT_USING_PINCTRL
+    default n
+
 if RT_USING_PINCTRL
 if RT_USING_PINCTRL
     osource "$(SOC_DM_PINCTRL_DIR)/Kconfig"
     osource "$(SOC_DM_PINCTRL_DIR)/Kconfig"
 endif
 endif

+ 4 - 8
components/drivers/pinctrl/SConscript

@@ -1,7 +1,6 @@
 from building import *
 from building import *
 
 
 group = []
 group = []
-objs = []
 
 
 if not GetDepend(['RT_USING_PINCTRL']):
 if not GetDepend(['RT_USING_PINCTRL']):
     Return('group')
     Return('group')
@@ -12,12 +11,9 @@ CPPPATH = [cwd + '/../include']
 
 
 src = ['pinctrl.c']
 src = ['pinctrl.c']
 
 
-group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
+if GetDepend(['RT_PINCTRL_SINGLE']):
+    src += ['pinctrl-single.c']
 
 
-for d in list:
-    path = os.path.join(cwd, d)
-    if os.path.isfile(os.path.join(path, 'SConscript')):
-        objs = objs + SConscript(os.path.join(d, 'SConscript'))
-objs = objs + group
+group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
 
 
-Return('objs')
+Return('group')

+ 384 - 0
components/drivers/pinctrl/pinctrl-single.c

@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2024-5-1       GuEe-GUI     first version
+ */
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "pinctrl.single"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#define EDGE_CLEAR      6
+#define EDGE_FALL_EN    5
+#define EDGE_RISE_EN    4
+
+#define PCS_F_AIB       RT_BIT(0)
+
+struct pcs_func_vals
+{
+    void *reg;
+    rt_uint32_t val;
+    rt_uint32_t mask;
+};
+
+struct pcs_soc_data
+{
+    rt_uint32_t flags;
+};
+
+struct pcs_device
+{
+    struct rt_device_pin parent;
+
+    struct rt_clk *psc_clk;
+    struct rt_reset_control *psc_rstc;
+
+    void *base;
+    void *gedge_flag_base;
+    rt_size_t size;
+    rt_uint32_t width;
+    rt_uint32_t fmask;
+    rt_uint32_t pinctrl_argc;
+    rt_bool_t bits_per_mux;
+
+    struct rt_spinlock lock;
+
+    unsigned (*read)(void *reg);
+    void (*write)(void *reg, unsigned val);
+
+    const struct pcs_soc_data *soc_data;
+};
+
+#define raw_to_pcs_device(raw) rt_container_of(raw, struct pcs_device, parent)
+
+static unsigned pcs_readb(void *reg)
+{
+    return HWREG8(reg);
+}
+
+static unsigned pcs_readw(void *reg)
+{
+    return HWREG16(reg);
+}
+
+static unsigned pcs_readl(void *reg)
+{
+    return HWREG32(reg);
+}
+
+static void pcs_writeb(void *reg, unsigned val)
+{
+    HWREG8(reg) = val;
+}
+
+static void pcs_writew(void *reg, unsigned val)
+{
+    HWREG16(reg) = val;
+}
+
+static void pcs_writel(void *reg, unsigned val)
+{
+    HWREG32(reg) = val;
+}
+
+static void pcs_confs_apply_once(struct pcs_device *pcs, struct pcs_func_vals *vals)
+{
+    rt_ubase_t level;
+    unsigned val, mask;
+
+    level = rt_spin_lock_irqsave(&pcs->lock);
+
+    val = pcs->read(vals->reg);
+
+    if (pcs->bits_per_mux)
+    {
+        mask = vals->mask;
+    }
+    else
+    {
+        mask = pcs->fmask;
+    }
+
+    val &= ~mask;
+    val |= (vals->val & mask);
+    pcs->write(vals->reg, val);
+
+    rt_spin_unlock_irqrestore(&pcs->lock, level);
+}
+
+static rt_err_t pcs_confs_apply(struct rt_device *device, void *fw_conf_np)
+{
+    rt_uint32_t value;
+    const fdt32_t *cell;
+    struct pcs_func_vals vals;
+    struct rt_ofw_prop *prop;
+    struct rt_ofw_node *conf_np = fw_conf_np;
+    struct pcs_device *pcs = raw_to_pcs_device(device);
+
+    rt_ofw_foreach_prop_u32(conf_np, "pinctrl-single,pins", prop, cell, value)
+    {
+        vals.reg = pcs->base + value;
+
+        cell = rt_ofw_prop_next_u32(prop, cell, &value);
+        vals.val = value;
+
+        if (pcs->pinctrl_argc == 3)
+        {
+            cell = rt_ofw_prop_next_u32(prop, cell, &value);
+
+            if (pcs->bits_per_mux)
+            {
+                vals.mask = value;
+            }
+            else
+            {
+                vals.val |= value;
+                vals.mask = pcs->fmask;
+            }
+        }
+        else
+        {
+            vals.mask = 0;
+        }
+
+        pcs_confs_apply_once(pcs, &vals);
+    }
+
+    return RT_EOK;
+}
+
+static rt_err_t pcs_gpio_request(struct rt_device *device, rt_base_t gpio, rt_uint32_t flags)
+{
+    rt_base_t gpio_start;
+    struct pcs_func_vals vals;
+    struct rt_ofw_cell_args gpio_range;
+    struct rt_ofw_node *np = device->ofw_node;
+    struct pcs_device *pcs = raw_to_pcs_device(device);
+
+    for (int i = 0;; ++i)
+    {
+        if (rt_ofw_parse_phandle_cells(np, "pinctrl-single,gpio-range",
+            "#pinctrl-single,gpio-range-cells", i, &gpio_range))
+        {
+            break;
+        }
+
+        gpio_start = gpio_range.args[0];
+
+        if (gpio < gpio_start || gpio >= gpio_start + gpio_range.args[1])
+        {
+            rt_ofw_node_put(gpio_range.data);
+            continue;
+        }
+
+        vals.reg = pcs->base + gpio * (pcs->width / 8);
+        vals.val = gpio_range.args[2];
+        vals.mask = pcs->fmask;
+
+        pcs_confs_apply_once(pcs, &vals);
+
+        rt_ofw_node_put(gpio_range.data);
+        break;
+    }
+
+    return RT_EOK;
+}
+
+static const struct rt_pin_ops pcs_ops =
+{
+    .pin_ctrl_confs_apply = pcs_confs_apply,
+    .pin_ctrl_gpio_request = pcs_gpio_request,
+};
+
+static rt_err_t pcs_probe(struct rt_platform_device *pdev)
+{
+    rt_err_t err;
+    rt_uint64_t address, size;
+    struct rt_device *dev = &pdev->parent;
+    struct pcs_device *pcs = rt_calloc(1, sizeof(*pcs));
+
+    if (!pcs)
+    {
+        return -RT_ENOMEM;
+    }
+    pcs->soc_data = pdev->id->data;
+
+    if ((err = rt_dm_dev_get_address(dev, 0, &address, &size)))
+    {
+        goto _fail;
+    }
+
+    pcs->size = size;
+    pcs->base = rt_ioremap((void *)address, size);
+    if (!pcs->base)
+    {
+        err = -RT_EIO;
+        goto _fail;
+    }
+
+    pcs->psc_rstc = rt_reset_control_get_by_name(dev, "aib_rst");
+    if (rt_is_err(pcs->psc_rstc))
+    {
+        err = rt_ptr_err(pcs->psc_rstc);
+        goto _fail;
+    }
+
+    if ((err = rt_reset_control_deassert(pcs->psc_rstc)))
+    {
+        goto _fail;
+    }
+
+    pcs->psc_clk = rt_clk_get_by_index(dev, 0);
+    if (rt_is_err(pcs->psc_clk))
+    {
+        err = rt_ptr_err(pcs->psc_clk);
+        goto _fail;
+    }
+
+    if ((err = rt_clk_prepare_enable(pcs->psc_clk)))
+    {
+        goto _fail;
+    }
+
+    if ((err = rt_dm_dev_prop_read_u32(dev, "#pinctrl-cells", &pcs->pinctrl_argc)))
+    {
+        goto _fail;
+    }
+    ++pcs->pinctrl_argc;
+
+    if ((err = rt_dm_dev_prop_read_u32(dev, "pinctrl-single,register-width", &pcs->width)))
+    {
+        goto _fail;
+    }
+
+    rt_dm_dev_prop_read_u32(dev, "pinctrl-single,function-mask", &pcs->fmask);
+
+    pcs->bits_per_mux = rt_dm_dev_prop_read_bool(dev, "pinctrl-single,bit-per-mux");
+
+    if (pcs->soc_data->flags & PCS_F_AIB)
+    {
+        if (!(pcs->gedge_flag_base = rt_dm_dev_iomap(dev, 1)))
+        {
+            err = -RT_EIO;
+            goto _fail;
+        }
+    }
+
+    switch (pcs->width)
+    {
+    case 8:
+        pcs->read = pcs_readb;
+        pcs->write = pcs_writeb;
+        break;
+    case 16:
+        pcs->read = pcs_readw;
+        pcs->write = pcs_writew;
+        break;
+    case 32:
+        pcs->read = pcs_readl;
+        pcs->write = pcs_writel;
+        break;
+    default:
+        err = -RT_EINVAL;
+        goto _fail;
+    }
+
+    if (pcs->soc_data->flags & PCS_F_AIB)
+    {
+        unsigned regval;
+        void *base = pcs->base + 4;
+
+        for (int i = 4; i < pcs->size; i += 4, base += 4)
+        {
+            regval = pcs->read(base);
+            regval |= (1 << EDGE_CLEAR);
+            regval &= ~(1 << EDGE_FALL_EN);
+            regval &= ~(1 << EDGE_RISE_EN);
+            pcs->write(base, regval);
+        }
+    }
+
+    rt_spin_lock_init(&pcs->lock);
+
+    pcs->parent.ops = &pcs_ops;
+    pcs->parent.parent.ofw_node = dev->ofw_node;
+
+    rt_ofw_data(dev->ofw_node) = &pcs->parent;
+
+    return RT_EOK;
+
+_fail:
+    if (pcs->base)
+    {
+        rt_iounmap(pcs->base);
+    }
+
+    if (!rt_is_err_or_null(pcs->psc_rstc))
+    {
+        rt_reset_control_assert(pcs->psc_rstc);
+        rt_reset_control_put(pcs->psc_rstc);
+    }
+
+    if (!rt_is_err_or_null(pcs->psc_clk))
+    {
+        rt_clk_put(pcs->psc_clk);
+    }
+
+    if (pcs->soc_data->flags & PCS_F_AIB)
+    {
+        if (pcs->gedge_flag_base)
+        {
+            rt_iounmap(pcs->gedge_flag_base);
+        }
+    }
+
+    rt_free(pcs);
+
+    return err;
+}
+
+static const struct pcs_soc_data pinctrl_single =
+{
+};
+
+static const struct pcs_soc_data pinconf_single_aib =
+{
+    .flags = PCS_F_AIB,
+};
+
+static const struct rt_ofw_node_id pcs_ofw_ids[] =
+{
+    { .compatible = "ti,am437-padconf", .data = &pinctrl_single },
+    { .compatible = "ti,am654-padconf", .data = &pinctrl_single },
+    { .compatible = "ti,dra7-padconf", .data = &pinctrl_single },
+    { .compatible = "ti,omap3-padconf", .data = &pinctrl_single },
+    { .compatible = "ti,omap4-padconf", .data = &pinctrl_single },
+    { .compatible = "ti,omap5-padconf", .data = &pinctrl_single },
+    { .compatible = "pinctrl-single", .data = &pinctrl_single },
+    { .compatible = "pinconf-single", .data = &pinctrl_single },
+    { .compatible = "pinconf-single-aib", .data = &pinconf_single_aib },
+    { /* sentinel */ }
+};
+
+static struct rt_platform_driver pcs_driver =
+{
+    .name = "pinctrl-single",
+    .ids = pcs_ofw_ids,
+
+    .probe = pcs_probe,
+};
+
+static int pcs_register(void)
+{
+    rt_platform_driver_register(&pcs_driver);
+
+    return 0;
+}
+INIT_SUBSYS_EXPORT(pcs_register);