From 1ceb99d8f59164c8737fe98a2e782babf5f96965 Mon Sep 17 00:00:00 2001 From: GuEe-GUI <2991707448@qq.com> Date: Tue, 9 Dec 2025 17:03:52 +0800 Subject: [PATCH 1/3] [dm][pinctrl] new interface for 'pin_gpio_request' Some GPIO should apply GPIO mode by pinctrl, add `pin_ctrl_gpio_request` for GPIO driver to apply it auto. Signed-off-by: GuEe-GUI <2991707448@qq.com> --- components/drivers/include/drivers/dev_pin.h | 1 + components/drivers/pin/dev_pin_dm.c | 17 +++++++++ components/drivers/pin/dev_pin_dm.h | 38 ++++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/components/drivers/include/drivers/dev_pin.h b/components/drivers/include/drivers/dev_pin.h index 7c12879ba7d..2039870983c 100644 --- a/components/drivers/include/drivers/dev_pin.h +++ b/components/drivers/include/drivers/dev_pin.h @@ -224,6 +224,7 @@ struct rt_pin_ops #endif #ifdef RT_USING_PINCTRL rt_err_t (*pin_ctrl_confs_apply)(struct rt_device *device, void *fw_conf_np); + rt_err_t (*pin_ctrl_gpio_request)(struct rt_device *device, rt_base_t gpio, rt_uint32_t flags); #endif /* RT_USING_PINCTRL */ }; diff --git a/components/drivers/pin/dev_pin_dm.c b/components/drivers/pin/dev_pin_dm.c index 31f12042ee7..cd9b9acd1a7 100644 --- a/components/drivers/pin/dev_pin_dm.c +++ b/components/drivers/pin/dev_pin_dm.c @@ -456,3 +456,20 @@ rt_ssize_t rt_pin_get_named_pin_count(struct rt_device *dev, const char *propnam return count; } + +#ifdef RT_USING_PINCTRL +rt_err_t pin_gpio_request(struct rt_device_pin *pinctrl, rt_base_t gpio, rt_uint32_t flags) +{ + if (!pinctrl || gpio < 0) + { + return -RT_EINVAL; + } + + if (pinctrl->ops->pin_ctrl_gpio_request) + { + return pinctrl->ops->pin_ctrl_gpio_request(&pinctrl->parent, gpio, flags); + } + + return RT_EOK; +} +#endif /* RT_USING_PINCTRL */ diff --git a/components/drivers/pin/dev_pin_dm.h b/components/drivers/pin/dev_pin_dm.h index 09374cab5cd..0ec265495b1 100644 --- a/components/drivers/pin/dev_pin_dm.h +++ b/components/drivers/pin/dev_pin_dm.h @@ -15,9 +15,47 @@ #include #include +/** + * Bind GPIO pin to system PIN API + * + * @param gpio Pin device + * @param pin_nr GPIO pin number + * + * @return RT_EOK on success, error code otherwise + */ rt_err_t pin_api_init(struct rt_device_pin *gpio, rt_size_t pin_nr); +/** + * Bind GPIO pin to system PIN PIC + * + * @param gpio Pin device + * @param pin_irq GPIO irqno + * + * @return RT_EOK on success, error code otherwise + */ rt_err_t pin_pic_init(struct rt_device_pin *gpio, int pin_irq); + +/** + * Handle GPIO one pin's ISR + * + * @param gpio Pin device + * @param pin GPIO pin + * + * @return RT_EOK on success, error code otherwise + */ rt_err_t pin_pic_handle_isr(struct rt_device_pin *gpio, rt_base_t pin); +#ifdef RT_USING_PINCTRL +/** + * Request GPIO pin configuration from pinctrl + * + * @param pinctrl Pinctrl device + * @param gpio GPIO pin number + * @param flags GPIO configuration flags + * + * @return RT_EOK on success, error code otherwise + */ +rt_err_t pin_gpio_request(struct rt_device_pin *pinctrl, rt_base_t gpio, rt_uint32_t flags); +#endif + #endif /* __DEV_PIN_DM_H__ */ From 33f469f93c970150a8084f1a234f9596efacc1c0 Mon Sep 17 00:00:00 2001 From: GuEe-GUI <2991707448@qq.com> Date: Tue, 9 Dec 2025 17:06:48 +0800 Subject: [PATCH 2/3] [dm][pin] fixup the DM Kconfig import in DM mode only Signed-off-by: GuEe-GUI <2991707448@qq.com> --- components/drivers/pin/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/drivers/pin/Kconfig b/components/drivers/pin/Kconfig index 2520897834b..5647ab7e053 100755 --- a/components/drivers/pin/Kconfig +++ b/components/drivers/pin/Kconfig @@ -2,6 +2,6 @@ menuconfig RT_USING_PIN bool "Using Generic GPIO device drivers" default y -if RT_USING_PIN +if RT_USING_DM && RT_USING_PIN osource "$(SOC_DM_PIN_DIR)/Kconfig" endif From 2ba6ad977d6f566977680ce7a5d863d0652b754e Mon Sep 17 00:00:00 2001 From: GuEe-GUI <2991707448@qq.com> Date: Tue, 9 Dec 2025 17:09:34 +0800 Subject: [PATCH 3/3] [dm][pin][pinctrl] add new driver 1. ARM PL061 GPIO 2. Single Pinctrl Signed-off-by: GuEe-GUI <2991707448@qq.com> --- components/drivers/pin/Kconfig | 6 + components/drivers/pin/SConscript | 3 + components/drivers/pin/pin-pl061.c | 357 ++++++++++++++++++ components/drivers/pinctrl/Kconfig | 5 + components/drivers/pinctrl/SConscript | 12 +- components/drivers/pinctrl/pinctrl-single.c | 384 ++++++++++++++++++++ 6 files changed, 759 insertions(+), 8 deletions(-) create mode 100644 components/drivers/pin/pin-pl061.c create mode 100644 components/drivers/pinctrl/pinctrl-single.c diff --git a/components/drivers/pin/Kconfig b/components/drivers/pin/Kconfig index 5647ab7e053..092576e4008 100755 --- a/components/drivers/pin/Kconfig +++ b/components/drivers/pin/Kconfig @@ -2,6 +2,12 @@ menuconfig RT_USING_PIN bool "Using Generic GPIO device drivers" 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 osource "$(SOC_DM_PIN_DIR)/Kconfig" endif diff --git a/components/drivers/pin/SConscript b/components/drivers/pin/SConscript index 69e3b533f30..8c5b283e963 100755 --- a/components/drivers/pin/SConscript +++ b/components/drivers/pin/SConscript @@ -16,6 +16,9 @@ if GetDepend(['RT_USING_DM']): if GetDepend(['RT_USING_OFW']): src += ['dev_pin_ofw.c'] +if GetDepend(['RT_PIN_PL061']): + src += ['pin-pl061.c'] + group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) Return('group') diff --git a/components/drivers/pin/pin-pl061.c b/components/drivers/pin/pin-pl061.c new file mode 100644 index 00000000000..44fa26ad4f5 --- /dev/null +++ b/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 +#include +#include + +#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); diff --git a/components/drivers/pinctrl/Kconfig b/components/drivers/pinctrl/Kconfig index 536049b1b58..0a459af218d 100644 --- a/components/drivers/pinctrl/Kconfig +++ b/components/drivers/pinctrl/Kconfig @@ -4,6 +4,11 @@ menuconfig RT_USING_PINCTRL depends on RT_USING_PIN default n +config RT_PINCTRL_SINGLE + bool "Single Pinctrl driver" + depends on RT_USING_PINCTRL + default n + if RT_USING_PINCTRL osource "$(SOC_DM_PINCTRL_DIR)/Kconfig" endif diff --git a/components/drivers/pinctrl/SConscript b/components/drivers/pinctrl/SConscript index 5ea1b1762e6..fb4d53f4208 100644 --- a/components/drivers/pinctrl/SConscript +++ b/components/drivers/pinctrl/SConscript @@ -1,7 +1,6 @@ from building import * group = [] -objs = [] if not GetDepend(['RT_USING_PINCTRL']): Return('group') @@ -12,12 +11,9 @@ CPPPATH = [cwd + '/../include'] 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') diff --git a/components/drivers/pinctrl/pinctrl-single.c b/components/drivers/pinctrl/pinctrl-single.c new file mode 100644 index 00000000000..9224f70e1cc --- /dev/null +++ b/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 +#include + +#define DBG_TAG "pinctrl.single" +#define DBG_LVL DBG_INFO +#include + +#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);