From 97c5edf947b0c1b02ad39fd5bedb1853a9140c2d Mon Sep 17 00:00:00 2001 From: zms123456 <85141075+zmshahaha@users.noreply.github.com> Date: Thu, 29 Feb 2024 22:27:27 +0800 Subject: [PATCH] [component][drivers]add pinctrl/pin-irqchip (#8383) --- components/drivers/Kconfig | 6 +- components/drivers/include/drivers/pin.h | 83 +++++++ .../drivers/include/dt-bindings/pin/pin.h | 42 ++++ .../drivers/include/dt-bindings/pin/state.h | 29 +++ components/drivers/misc/SConscript | 3 - components/drivers/pin/Kconfig | 3 + components/drivers/pin/SConscript | 21 ++ components/drivers/{misc => pin}/pin.c | 0 components/drivers/pin/pin_dm.c | 220 +++++++++++++++++ components/drivers/pin/pin_dm.h | 21 ++ components/drivers/pin/pin_ofw.c | 170 +++++++++++++ components/drivers/pinctrl/Kconfig | 6 + components/drivers/pinctrl/SConscript | 23 ++ components/drivers/pinctrl/pinctrl.c | 227 ++++++++++++++++++ 14 files changed, 847 insertions(+), 7 deletions(-) create mode 100644 components/drivers/include/dt-bindings/pin/pin.h create mode 100644 components/drivers/include/dt-bindings/pin/state.h create mode 100755 components/drivers/pin/Kconfig create mode 100755 components/drivers/pin/SConscript rename components/drivers/{misc => pin}/pin.c (100%) create mode 100644 components/drivers/pin/pin_dm.c create mode 100644 components/drivers/pin/pin_dm.h create mode 100644 components/drivers/pin/pin_ofw.c create mode 100644 components/drivers/pinctrl/Kconfig create mode 100644 components/drivers/pinctrl/SConscript create mode 100644 components/drivers/pinctrl/pinctrl.c diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index 8b9467008e..b77eda40d1 100755 --- a/components/drivers/Kconfig +++ b/components/drivers/Kconfig @@ -344,10 +344,6 @@ config RT_USING_PHY bool "Using ethernet phy device drivers" default n -config RT_USING_PIN - bool "Using generic GPIO device drivers" - default n - config RT_USING_ADC bool "Using ADC device drivers" default n @@ -970,6 +966,8 @@ menuconfig RT_USING_VIRTIO source "$RTT_DIR/components/drivers/ofw/Kconfig" source "$RTT_DIR/components/drivers/pic/Kconfig" +source "$RTT_DIR/components/drivers/pin/Kconfig" +source "$RTT_DIR/components/drivers/pinctrl/Kconfig" source "$RTT_DIR/components/drivers/ktime/Kconfig" source "$RTT_DIR/components/drivers/clk/Kconfig" diff --git a/components/drivers/include/drivers/pin.h b/components/drivers/include/drivers/pin.h index 4b369d5b8d..53e4465f8d 100644 --- a/components/drivers/include/drivers/pin.h +++ b/components/drivers/include/drivers/pin.h @@ -18,10 +18,25 @@ extern "C" { #endif +#ifdef RT_USING_DM +#include + +struct rt_pin_irqchip +{ + struct rt_pic parent; + + int irq; + rt_base_t pin_range[2]; +}; +#endif /* RT_USING_DM */ + /* pin device and operations for RT-Thread */ struct rt_device_pin { struct rt_device parent; +#ifdef RT_USING_DM + struct rt_pin_irqchip irqchip; +#endif /* RT_USING_DM */ const struct rt_pin_ops *ops; }; @@ -36,6 +51,39 @@ struct rt_device_pin #define PIN_MODE_INPUT_PULLDOWN 0x03 #define PIN_MODE_OUTPUT_OD 0x04 +#ifdef RT_USING_PINCTRL +enum +{ + PIN_CONFIG_BIAS_BUS_HOLD, + PIN_CONFIG_BIAS_DISABLE, + PIN_CONFIG_BIAS_HIGH_IMPEDANCE, + PIN_CONFIG_BIAS_PULL_DOWN, + PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, + PIN_CONFIG_BIAS_PULL_UP, + PIN_CONFIG_DRIVE_OPEN_DRAIN, + PIN_CONFIG_DRIVE_OPEN_SOURCE, + PIN_CONFIG_DRIVE_PUSH_PULL, + PIN_CONFIG_DRIVE_STRENGTH, + PIN_CONFIG_DRIVE_STRENGTH_UA, + PIN_CONFIG_INPUT_DEBOUNCE, + PIN_CONFIG_INPUT_ENABLE, + PIN_CONFIG_INPUT_SCHMITT, + PIN_CONFIG_INPUT_SCHMITT_ENABLE, + PIN_CONFIG_MODE_LOW_POWER, + PIN_CONFIG_MODE_PWM, + PIN_CONFIG_OUTPUT, + PIN_CONFIG_OUTPUT_ENABLE, + PIN_CONFIG_OUTPUT_IMPEDANCE_OHMS, + PIN_CONFIG_PERSIST_STATE, + PIN_CONFIG_POWER_SOURCE, + PIN_CONFIG_SKEW_DELAY, + PIN_CONFIG_SLEEP_HARDWARE_STATE, + PIN_CONFIG_SLEW_RATE, + PIN_CONFIG_END = 0x7f, + PIN_CONFIG_MAX = 0xff, +}; +#endif /* RT_USING_PINCTRL */ + #define PIN_IRQ_MODE_RISING 0x00 #define PIN_IRQ_MODE_FALLING 0x01 #define PIN_IRQ_MODE_RISING_FALLING 0x02 @@ -66,6 +114,16 @@ struct rt_pin_irq_hdr void (*hdr)(void *args); void *args; }; + +#ifdef RT_USING_PINCTRL +struct rt_pin_ctrl_conf_params +{ + const char *propname; + rt_uint32_t param; + rt_uint32_t default_value; +}; +#endif /* RT_USING_PINCTRL */ + struct rt_pin_ops { void (*pin_mode)(struct rt_device *device, rt_base_t pin, rt_uint8_t mode); @@ -76,6 +134,13 @@ struct rt_pin_ops rt_err_t (*pin_detach_irq)(struct rt_device *device, rt_base_t pin); rt_err_t (*pin_irq_enable)(struct rt_device *device, rt_base_t pin, rt_uint8_t enabled); rt_base_t (*pin_get)(const char *name); +#ifdef RT_USING_DM + rt_err_t (*pin_irq_mode)(struct rt_device *device, rt_base_t pin, rt_uint8_t mode); + rt_ssize_t (*pin_parse)(struct rt_device *device, struct rt_ofw_cell_args *args, rt_uint32_t *flags); +#endif +#ifdef RT_USING_PINCTRL + rt_err_t (*pin_ctrl_confs_apply)(struct rt_device *device, void *fw_conf_np); +#endif /* RT_USING_PINCTRL */ }; int rt_device_pin_register(const char *name, const struct rt_pin_ops *ops, void *user_data); @@ -88,6 +153,24 @@ rt_err_t rt_pin_attach_irq(rt_base_t pin, rt_uint8_t mode, rt_err_t rt_pin_detach_irq(rt_base_t pin); rt_err_t rt_pin_irq_enable(rt_base_t pin, rt_uint8_t enabled); +#ifdef RT_USING_DM +rt_ssize_t rt_pin_get_named_pin(struct rt_device *dev, const char *propname, int index, + rt_uint8_t *out_mode, rt_uint8_t *out_value); +rt_ssize_t rt_pin_get_named_pin_count(struct rt_device *dev, const char *propname); + +#ifdef RT_USING_OFW +rt_ssize_t rt_ofw_get_named_pin(struct rt_ofw_node *np, const char *propname, int index, + rt_uint8_t *out_mode, rt_uint8_t *out_value); +rt_ssize_t rt_ofw_get_named_pin_count(struct rt_ofw_node *np, const char *propname); +#endif +#endif /* RT_USING_DM */ + +#ifdef RT_USING_PINCTRL +rt_ssize_t rt_pin_ctrl_confs_lookup(struct rt_device *device, const char *name); +rt_err_t rt_pin_ctrl_confs_apply(struct rt_device *device, int index); +rt_err_t rt_pin_ctrl_confs_apply_by_name(struct rt_device *device, const char *name); +#endif /* RT_USING_PINCTRL */ + #ifdef __cplusplus } #endif diff --git a/components/drivers/include/dt-bindings/pin/pin.h b/components/drivers/include/dt-bindings/pin/pin.h new file mode 100644 index 0000000000..00df8e17d0 --- /dev/null +++ b/components/drivers/include/dt-bindings/pin/pin.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_PIN_PIN_H__ +#define __DT_BINDINGS_PIN_PIN_H__ + +/* Bit 0 express polarity */ +#define PIN_ACTIVE_HIGH 0 +#define PIN_ACTIVE_LOW 1 + +/* Bit 1 express single-endedness */ +#define PIN_PUSH_PULL 0 +#define PIN_SINGLE_ENDED 2 + +/* Bit 2 express Open drain or open source */ +#define PIN_LINE_OPEN_SOURCE 0 +#define PIN_LINE_OPEN_DRAIN 4 + +/* + * Open Drain/Collector is the combination of single-ended open drain interface. + * Open Source/Emitter is the combination of single-ended open source interface. + */ +#define PIN_OPEN_DRAIN (PIN_SINGLE_ENDED | PIN_LINE_OPEN_DRAIN) +#define PIN_OPEN_SOURCE (PIN_SINGLE_ENDED | PIN_LINE_OPEN_SOURCE) + +/* Bit 3 express PIN suspend/resume and reset persistence */ +#define PIN_PERSISTENT 0 +#define PIN_TRANSITORY 8 + +/* Bit 4 express pull up */ +#define PIN_PULL_UP 16 + +/* Bit 5 express pull down */ +#define PIN_PULL_DOWN 32 + +/* Bit 6 express pull disable */ +#define PIN_PULL_DISABLE 64 + +#endif /* __DT_BINDINGS_PIN_PIN_H__ */ diff --git a/components/drivers/include/dt-bindings/pin/state.h b/components/drivers/include/dt-bindings/pin/state.h new file mode 100644 index 0000000000..6a0475d3b6 --- /dev/null +++ b/components/drivers/include/dt-bindings/pin/state.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __DT_BINDINGS_PIN_STATE_H__ +#define __DT_BINDINGS_PIN_STATE_H__ + +#define PIND_FLAGS_BIT_DIR_SET (1 << 0) +#define PIND_FLAGS_BIT_DIR_OUT (1 << 1) +#define PIND_FLAGS_BIT_DIR_VAL (1 << 2) +#define PIND_FLAGS_BIT_OPEN_DRAIN (1 << 3) +#define PIND_FLAGS_BIT_NONEXCLUSIVE (1 << 4) + +/* Don't change anything */ +#define PIND_ASIS 0 +/* Set lines to input mode */ +#define PIND_IN PIND_FLAGS_BIT_DIR_SET +/* Set lines to output and drive them low */ +#define PIND_OUT_LOW (PIND_FLAGS_BIT_DIR_SET | PIND_FLAGS_BIT_DIR_OUT) +/* Set lines to output and drive them high */ +#define PIND_OUT_HIGH (PIND_FLAGS_BIT_DIR_SET | PIND_FLAGS_BIT_DIR_OUT | PIND_FLAGS_BIT_DIR_VAL) +/* Set lines to open-drain output and drive them low */ +#define PIND_OUT_LOW_OPEN_DRAIN (PIND_OUT_LOW | PIND_FLAGS_BIT_OPEN_DRAIN) +/* Set lines to open-drain output and drive them high */ +#define PIND_OUT_HIGH_OPEN_DRAIN (PIND_OUT_HIGH | PIND_FLAGS_BIT_OPEN_DRAIN) + +#endif /* __DT_BINDINGS_PIN_STATE_H__ */ diff --git a/components/drivers/misc/SConscript b/components/drivers/misc/SConscript index 927e662b19..5b74ac93e5 100644 --- a/components/drivers/misc/SConscript +++ b/components/drivers/misc/SConscript @@ -5,9 +5,6 @@ src = [] CPPPATH = [cwd + '/../include'] group = [] -if GetDepend(['RT_USING_PIN']): - src = src + ['pin.c'] - if GetDepend(['RT_USING_ADC']): src = src + ['adc.c'] diff --git a/components/drivers/pin/Kconfig b/components/drivers/pin/Kconfig new file mode 100755 index 0000000000..24a2c02bf8 --- /dev/null +++ b/components/drivers/pin/Kconfig @@ -0,0 +1,3 @@ +menuconfig RT_USING_PIN + bool "Using Generic GPIO device drivers" + default y diff --git a/components/drivers/pin/SConscript b/components/drivers/pin/SConscript new file mode 100755 index 0000000000..bdad84827f --- /dev/null +++ b/components/drivers/pin/SConscript @@ -0,0 +1,21 @@ +from building import * + +group = [] + +if not GetDepend(['RT_USING_PIN']): + Return('group') + +cwd = GetCurrentDir() +CPPPATH = [cwd + '/../include'] + +src = ['pin.c'] + +if GetDepend(['RT_USING_DM']): + src += ['pin_dm.c'] + +if GetDepend(['RT_USING_OFW']): + src += ['pin_ofw.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/misc/pin.c b/components/drivers/pin/pin.c similarity index 100% rename from components/drivers/misc/pin.c rename to components/drivers/pin/pin.c diff --git a/components/drivers/pin/pin_dm.c b/components/drivers/pin/pin_dm.c new file mode 100644 index 0000000000..52dd47fd97 --- /dev/null +++ b/components/drivers/pin/pin_dm.c @@ -0,0 +1,220 @@ +/* + * 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 "pin_dm.h" + +static void pin_dm_irq_mask(struct rt_pic_irq *pirq) +{ + struct rt_device_pin *gpio = pirq->pic->priv_data; + + gpio->ops->pin_irq_enable(&gpio->parent, pirq->hwirq, 0); +} + +static void pin_dm_irq_unmask(struct rt_pic_irq *pirq) +{ + struct rt_device_pin *gpio = pirq->pic->priv_data; + + gpio->ops->pin_irq_enable(&gpio->parent, pirq->hwirq, 1); +} + +static rt_err_t pin_dm_irq_set_triger_mode(struct rt_pic_irq *pirq, rt_uint32_t mode) +{ + rt_uint8_t pin_mode; + struct rt_device_pin *gpio = pirq->pic->priv_data; + + switch (mode) + { + case RT_IRQ_MODE_EDGE_RISING: + pin_mode = PIN_IRQ_MODE_RISING; + break; + + case RT_IRQ_MODE_EDGE_FALLING: + pin_mode = PIN_IRQ_MODE_FALLING; + break; + + case RT_IRQ_MODE_EDGE_BOTH: + pin_mode = PIN_IRQ_MODE_RISING_FALLING; + break; + + case RT_IRQ_MODE_LEVEL_HIGH: + pin_mode = PIN_IRQ_MODE_HIGH_LEVEL; + break; + + case RT_IRQ_MODE_LEVEL_LOW: + pin_mode = PIN_IRQ_MODE_LOW_LEVEL; + break; + + default: + return -RT_ENOSYS; + } + + return gpio->ops->pin_irq_mode(&gpio->parent, pirq->hwirq, pin_mode); +} + +static int pin_dm_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) +{ + int irq = -1; + struct rt_device_pin *gpio = pic->priv_data; + struct rt_pic_irq *pirq = rt_pic_find_irq(pic, hwirq); + + if (pirq) + { + irq = rt_pic_config_irq(pic, hwirq, hwirq); + + if (irq >= 0) + { + rt_pic_cascade(pirq, gpio->irqchip.irq); + rt_pic_irq_set_triger_mode(irq, mode); + } + } + + return irq; +} + +static rt_err_t pin_dm_irq_parse(struct rt_pic *pic, struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq) +{ + rt_err_t err = RT_EOK; + + if (args->args_count == 2) + { + out_pirq->hwirq = args->args[0]; + out_pirq->mode = args->args[1] & RT_IRQ_MODE_MASK; + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +static struct rt_pic_ops pin_dm_ops = +{ + .name = "GPIO", + .irq_enable = pin_dm_irq_mask, + .irq_disable = pin_dm_irq_unmask, + .irq_mask = pin_dm_irq_mask, + .irq_unmask = pin_dm_irq_unmask, + .irq_set_triger_mode = pin_dm_irq_set_triger_mode, + .irq_map = pin_dm_irq_map, + .irq_parse = pin_dm_irq_parse, +}; + +rt_err_t pin_pic_handle_isr(struct rt_device_pin *gpio, rt_base_t pin) +{ + rt_err_t err; + + if (gpio) + { + struct rt_pin_irqchip *irqchip = &gpio->irqchip; + + if (pin >= irqchip->pin_range[0] && pin <= irqchip->pin_range[1]) + { + struct rt_pic_irq *pirq; + + pirq = rt_pic_find_irq(&irqchip->parent, pin - irqchip->pin_range[0]); + + if (pirq->irq >= 0) + { + err = rt_pic_handle_isr(pirq); + } + else + { + err = -RT_EINVAL; + } + } + else + { + err = -RT_EINVAL; + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t pin_pic_init(struct rt_device_pin *gpio) +{ + rt_err_t err; + + if (gpio) + { + struct rt_pin_irqchip *irqchip = &gpio->irqchip; + + if (irqchip->pin_range[0] >= 0 && irqchip->pin_range[1] >= irqchip->pin_range[0]) + { + struct rt_pic *pic = &irqchip->parent; + rt_size_t pin_nr = irqchip->pin_range[1] - irqchip->pin_range[0] + 1; + + pic->priv_data = gpio; + pic->ops = &pin_dm_ops; + /* Make sure the type of gpio for pic */ + gpio->parent.parent.type = RT_Object_Class_Device; + rt_pic_default_name(&irqchip->parent); + + err = rt_pic_linear_irq(pic, pin_nr); + rt_pic_user_extends(pic); + } + else + { + err = -RT_EINVAL; + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_ssize_t rt_pin_get_named_pin(struct rt_device *dev, const char *propname, int index, + rt_uint8_t *out_mode, rt_uint8_t *out_value) +{ + rt_ssize_t res = -RT_ENOSYS; + + RT_ASSERT(dev != RT_NULL); + +#ifdef RT_USING_OFW + if (dev->ofw_node) + { + res = rt_ofw_get_named_pin(dev->ofw_node, propname, index, out_mode, out_value); + } + else + { + res = -RT_EINVAL; + } +#endif /* RT_USING_OFW */ + + return res; +} + +rt_ssize_t rt_pin_get_named_pin_count(struct rt_device *dev, const char *propname) +{ + rt_ssize_t count = -RT_ENOSYS; + + RT_ASSERT(dev != RT_NULL); + +#ifdef RT_USING_OFW + if (dev->ofw_node) + { + count = rt_ofw_get_named_pin_count(dev->ofw_node, propname); + } + else + { + count = -RT_EINVAL; + } +#endif /* RT_USING_OFW */ + + return count; +} diff --git a/components/drivers/pin/pin_dm.h b/components/drivers/pin/pin_dm.h new file mode 100644 index 0000000000..b5146a2795 --- /dev/null +++ b/components/drivers/pin/pin_dm.h @@ -0,0 +1,21 @@ +/* + * 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 + */ + +#ifndef __PIN_DM_H__ +#define __PIN_DM_H__ + +#include +#include +#include + +rt_err_t pin_pic_handle_isr(struct rt_device_pin *gpio, rt_base_t pin); +rt_err_t pin_pic_init(struct rt_device_pin *gpio); + +#endif /* __PIN_DM_H__ */ diff --git a/components/drivers/pin/pin_ofw.c b/components/drivers/pin/pin_ofw.c new file mode 100644 index 0000000000..e4c18b1759 --- /dev/null +++ b/components/drivers/pin/pin_ofw.c @@ -0,0 +1,170 @@ +/* + * 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 "pin_dm.h" + +static const char * const gpio_suffixes[] = +{ + "gpios", "gpio" +}; + +rt_ssize_t rt_ofw_get_named_pin(struct rt_ofw_node *np, const char *propname, int index, + rt_uint8_t *out_mode, rt_uint8_t *out_value) +{ + rt_ssize_t pin; + rt_uint8_t mode; + rt_uint8_t value; + rt_uint32_t flags; + char gpios_name[64]; + struct rt_device_pin *pin_dev; + struct rt_ofw_node *pin_dev_np; + struct rt_ofw_cell_args pin_args; + + if (!np && index < 0) + { + return -RT_EINVAL; + } + + for (int i = 0; i < RT_ARRAY_SIZE(gpio_suffixes); ++i) + { + if (propname) + { + rt_snprintf(gpios_name, sizeof(gpios_name), "%s-%s", propname, gpio_suffixes[i]); + } + else + { + rt_snprintf(gpios_name, sizeof(gpios_name), "%s", gpio_suffixes[i]); + } + + pin = rt_ofw_parse_phandle_cells(np, gpios_name, "#gpio-cells", index, &pin_args); + + if (pin >= 0) + { + break; + } + } + + if (pin < 0) + { + return pin; + } + + pin_dev_np = pin_args.data; + pin_dev = rt_ofw_data(pin_dev_np); + + if (!pin_dev) + { + pin = -RT_ERROR; + + goto _out_converts; + } + + value = PIN_LOW; + mode = PIN_MODE_OUTPUT; + + if (pin_dev->ops->pin_parse) + { + pin = pin_dev->ops->pin_parse(&pin_dev->parent, &pin_args, &flags); + } + else + { + /* + * We always assume that the args[0] is the pin number if driver not + * implemented `pin_parse`. + */ + pin = pin_args.args[0]; + + goto _out_converts; + } + + if (out_mode) + { + if (flags & PIN_OPEN_DRAIN) + { + mode = PIN_MODE_OUTPUT_OD; + } + + switch (flags & RT_GENMASK(6, 4)) + { + case PIN_PULL_UP: + mode = PIN_MODE_INPUT_PULLUP; + break; + + case PIN_PULL_DOWN: + mode = PIN_MODE_INPUT_PULLDOWN; + break; + + case PIN_PULL_DISABLE: + mode = PIN_MODE_INPUT; + break; + } + } + + if (out_value) + { + if (flags == (PIN_ACTIVE_HIGH | PIN_PUSH_PULL)) + { + value = PIN_HIGH; + } + else if (flags == (PIN_ACTIVE_LOW | PIN_PUSH_PULL)) + { + value = PIN_LOW; + } + } + +_out_converts: + rt_ofw_node_put(pin_dev_np); + + if (out_mode) + { + *out_mode = mode; + } + + if (out_value) + { + *out_value = value; + } + + return pin; +} + +rt_ssize_t rt_ofw_get_named_pin_count(struct rt_ofw_node *np, const char *propname) +{ + char gpios_name[64]; + rt_ssize_t count = 0; + + if (!np || !propname) + { + return -RT_EINVAL; + } + + for (int i = 0; i < RT_ARRAY_SIZE(gpio_suffixes); ++i) + { + if (propname) + { + rt_snprintf(gpios_name, sizeof(gpios_name), "%s-%s", propname, gpio_suffixes[i]); + } + else + { + rt_snprintf(gpios_name, sizeof(gpios_name), "%s", gpio_suffixes[i]); + } + + count = rt_ofw_count_phandle_cells(np, propname, "#gpio-cells"); + + if (count > 0) + { + break; + } + } + + return count; +} diff --git a/components/drivers/pinctrl/Kconfig b/components/drivers/pinctrl/Kconfig new file mode 100644 index 0000000000..227c8a903b --- /dev/null +++ b/components/drivers/pinctrl/Kconfig @@ -0,0 +1,6 @@ +menuconfig RT_USING_PINCTRL + bool "Using Pin controllers device drivers" + depends on RT_USING_DM + depends on RT_USING_PIN + default n + diff --git a/components/drivers/pinctrl/SConscript b/components/drivers/pinctrl/SConscript new file mode 100644 index 0000000000..5ea1b1762e --- /dev/null +++ b/components/drivers/pinctrl/SConscript @@ -0,0 +1,23 @@ +from building import * + +group = [] +objs = [] + +if not GetDepend(['RT_USING_PINCTRL']): + Return('group') + +cwd = GetCurrentDir() +list = os.listdir(cwd) +CPPPATH = [cwd + '/../include'] + +src = ['pinctrl.c'] + +group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH) + +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 + +Return('objs') diff --git a/components/drivers/pinctrl/pinctrl.c b/components/drivers/pinctrl/pinctrl.c new file mode 100644 index 0000000000..f32749248f --- /dev/null +++ b/components/drivers/pinctrl/pinctrl.c @@ -0,0 +1,227 @@ +/* + * 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 + +#define DBG_TAG "rtdm.pinctrl" +#define DBG_LVL DBG_INFO +#include + +#ifdef RT_USING_OFW +static rt_err_t ofw_pin_ctrl_confs_apply(struct rt_ofw_node *np, int index) +{ + rt_err_t err = -RT_EEMPTY; + rt_phandle phandle; + const fdt32_t *cell; + struct rt_ofw_prop *prop; + char pinctrl_n_name[sizeof("pinctrl-0")]; + + rt_sprintf(pinctrl_n_name, "pinctrl-%d", index); + index = 0; + + rt_ofw_foreach_prop_u32(np, pinctrl_n_name, prop, cell, phandle) + { + struct rt_device_pin *pinctrl = RT_NULL; + struct rt_ofw_node *conf_np, *pinctrl_np; + + conf_np = pinctrl_np = rt_ofw_find_node_by_phandle(phandle); + + if (!conf_np) + { + err = -RT_EIO; + + break; + } + /* + * We always assume the phandle in pinctrl-N is the pinctrl-device + * node's child node. If not, we need a better way to find it: + * + * / { + * serial@4600 { + * device_type = "serial"; + * reg = <0x4600 0x100>; + * clock-frequency = <0>; + * pinctrl-names = "default"; + * pinctrl-0 = <&uart_pin>; + * }; + * + * i2c@4700 { + * reg = <0x4700 0x100>; + * pinctrl-names = "default"; + * pinctrl-0 = <&i2c_pin_scl, &i2c_pin_sda>; + * }; + * + * pinctrl: pinctrl { + * + * uart_pin { + * multi,pins = + * <0 PD0 1 &uart_rx_pull_up>, + * <0 PD1 1 &uart_tx_pull_up>; + * }; + * + * i2c_pin_scl { + * single,pins = <0 PB1>; + * pull = <&i2c_pull_none_smt>; + * function = <1>; + * }; + * + * i2c_pin_sda { + * single,pins = <0 PB2>; + * pull = <&i2c_pull_none_smt>; + * function = <1>; + * }; + * }; + * } + */ + rt_ofw_foreach_parent_node(pinctrl_np) + { + if (rt_ofw_prop_read_bool(pinctrl_np, "compatible")) + { + break; + } + } + + if (pinctrl_np) + { + pinctrl = rt_ofw_data(pinctrl_np); + + rt_ofw_node_put(pinctrl_np); + } + + if (!pinctrl || !pinctrl->ops || !pinctrl->ops->pin_ctrl_confs_apply) + { + if (index) + { + err = -RT_EEMPTY; + } + else + { + err = -RT_ERROR; + } + + rt_ofw_node_put(conf_np); + + break; + } + + err = pinctrl->ops->pin_ctrl_confs_apply(&pinctrl->parent, conf_np); + rt_ofw_node_put(conf_np); + + if (err) + { + break; + } + + ++index; + } + + return err; +} + +static int ofw_pin_ctrl_confs_lookup(struct rt_ofw_node *np, const char *name) +{ + return rt_ofw_prop_index_of_string(np, "pinctrl-names", name); +} + +static rt_err_t ofw_pin_ctrl_confs_apply_by_name(struct rt_ofw_node *np, const char *name) +{ + int index; + rt_err_t err; + + index = ofw_pin_ctrl_confs_lookup(np, name); + + if (index >= 0) + { + err = ofw_pin_ctrl_confs_apply(np, index); + } + else + { + err = -RT_EEMPTY; + } + + return err; +} +#endif /* RT_USING_OFW */ + +rt_ssize_t rt_pin_ctrl_confs_lookup(struct rt_device *device, const char *name) +{ + rt_ssize_t res; + + if (device && name) + { + res = -RT_ENOSYS; + + #ifdef RT_USING_OFW + if (device->ofw_node) + { + res = ofw_pin_ctrl_confs_lookup(device->ofw_node, name); + } + #endif /* RT_USING_OFW */ + } + else + { + res = -RT_EINVAL; + } + + return res; +} + +rt_err_t rt_pin_ctrl_confs_apply(struct rt_device *device, int index) +{ + rt_err_t err; + + if (device && index >= 0) + { + err = -RT_ENOSYS; + + #ifdef RT_USING_OFW + if (device->ofw_node) + { + err = ofw_pin_ctrl_confs_apply(device->ofw_node, index); + } + #endif /* RT_USING_OFW */ + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_pin_ctrl_confs_apply_by_name(struct rt_device *device, const char *name) +{ + rt_err_t err; + + if (device) + { + if (!name) + { + name = "default"; + } + + err = -RT_ENOSYS; + + #ifdef RT_USING_OFW + if (device->ofw_node) + { + err = ofw_pin_ctrl_confs_apply_by_name(device->ofw_node, name); + } + #endif /* RT_USING_OFW */ + } + else + { + err = -RT_EINVAL; + } + + return err; +}