Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Jacky Huang | 6015 | 99.95% | 1 | 50.00% |
Dan Carpenter | 3 | 0.05% | 1 | 50.00% |
Total | 6018 | 2 |
// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2024 Nuvoton Technology Corp. * * Author: Shan-Chun Hung <schung@nuvoton.com> * * Jacky Huang <ychuang3@nuvoton.com> */ #include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/cleanup.h> #include <linux/clk.h> #include <linux/gpio/driver.h> #include <linux/mfd/syscon.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/property.h> #include <linux/regmap.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinctrl.h> #include "../core.h" #include "../pinconf.h" #include "pinctrl-ma35.h" #define MA35_MFP_REG_BASE 0x80 #define MA35_MFP_REG_SZ_PER_BANK 8 #define MA35_MFP_BITS_PER_PORT 4 #define MA35_GPIO_BANK_MAX 14 #define MA35_GPIO_PORT_MAX 16 /* GPIO control registers */ #define MA35_GP_REG_MODE 0x00 #define MA35_GP_REG_DINOFF 0x04 #define MA35_GP_REG_DOUT 0x08 #define MA35_GP_REG_DATMSK 0x0c #define MA35_GP_REG_PIN 0x10 #define MA35_GP_REG_DBEN 0x14 #define MA35_GP_REG_INTTYPE 0x18 #define MA35_GP_REG_INTEN 0x1c #define MA35_GP_REG_INTSRC 0x20 #define MA35_GP_REG_SMTEN 0x24 #define MA35_GP_REG_SLEWCTL 0x28 #define MA35_GP_REG_SPW 0x2c #define MA35_GP_REG_PUSEL 0x30 #define MA35_GP_REG_DSL 0x38 #define MA35_GP_REG_DSH 0x3c /* GPIO mode control */ #define MA35_GP_MODE_INPUT 0x0 #define MA35_GP_MODE_OUTPUT 0x1 #define MA35_GP_MODE_OPEN_DRAIN 0x2 #define MA35_GP_MODE_QUASI 0x3 #define MA35_GP_MODE_MASK(n) GENMASK(n * 2 + 1, n * 2) #define MA35_GP_SLEWCTL_MASK(n) GENMASK(n * 2 + 1, n * 2) /* GPIO pull-up and pull-down selection control */ #define MA35_GP_PUSEL_DISABLE 0x0 #define MA35_GP_PUSEL_PULL_UP 0x1 #define MA35_GP_PUSEL_PULL_DOWN 0x2 #define MA35_GP_PUSEL_MASK(n) GENMASK(n * 2 + 1, n * 2) /* * The MA35_GP_REG_INTEN bits 0 ~ 15 control low-level or falling edge trigger, * while bits 16 ~ 31 control high-level or rising edge trigger. */ #define MA35_GP_INTEN_L(n) BIT(n) #define MA35_GP_INTEN_H(n) BIT(n + 16) #define MA35_GP_INTEN_BOTH(n) (MA35_GP_INTEN_H(n) | MA35_GP_INTEN_L(n)) /* * The MA35_GP_REG_DSL register controls ports 0 to 7, while the MA35_GP_REG_DSH * register controls ports 8 to 15. Each port occupies a width of 4 bits, with 3 * bits being effective. */ #define MA35_GP_DS_REG(n) (n < 8 ? MA35_GP_REG_DSL : MA35_GP_REG_DSH) #define MA35_GP_DS_MASK(n) GENMASK((n % 8) * 4 + 3, (n % 8) * 4) #define MVOLT_1800 0 #define MVOLT_3300 1 /* Non-constant mask variant of FIELD_GET() and FIELD_PREP() */ #define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1)) #define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask)) static const char * const gpio_group_name[] = { "gpioa", "gpiob", "gpioc", "gpiod", "gpioe", "gpiof", "gpiog", "gpioh", "gpioi", "gpioj", "gpiok", "gpiol", "gpiom", "gpion", }; static const u32 ds_1800mv_tbl[] = { 2900, 4400, 5800, 7300, 8600, 10100, 11500, 13000, }; static const u32 ds_3300mv_tbl[] = { 17100, 25600, 34100, 42800, 48000, 56000, 77000, 82000, }; struct ma35_pin_func { const char *name; const char **groups; u32 ngroups; }; struct ma35_pin_setting { u32 offset; u32 shift; u32 muxval; unsigned long *configs; unsigned int nconfigs; }; struct ma35_pin_group { const char *name; unsigned int npins; unsigned int *pins; struct ma35_pin_setting *settings; }; struct ma35_pin_bank { void __iomem *reg_base; struct clk *clk; int irq; u8 bank_num; u8 nr_pins; bool valid; const char *name; struct fwnode_handle *fwnode; struct gpio_chip chip; u32 irqtype; u32 irqinten; struct regmap *regmap; struct device *dev; }; struct ma35_pin_ctrl { struct ma35_pin_bank *pin_banks; u32 nr_banks; u32 nr_pins; }; struct ma35_pinctrl { struct device *dev; struct ma35_pin_ctrl *ctrl; struct pinctrl_dev *pctl; const struct ma35_pinctrl_soc_info *info; struct regmap *regmap; struct ma35_pin_group *groups; unsigned int ngroups; struct ma35_pin_func *functions; unsigned int nfunctions; }; static DEFINE_RAW_SPINLOCK(ma35_lock); static int ma35_get_groups_count(struct pinctrl_dev *pctldev) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); return npctl->ngroups; } static const char *ma35_get_group_name(struct pinctrl_dev *pctldev, unsigned int selector) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); return npctl->groups[selector].name; } static int ma35_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, const unsigned int **pins, unsigned int *npins) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); if (selector >= npctl->ngroups) return -EINVAL; *pins = npctl->groups[selector].pins; *npins = npctl->groups[selector].npins; return 0; } static struct ma35_pin_group *ma35_pinctrl_find_group_by_name( const struct ma35_pinctrl *npctl, const char *name) { int i; for (i = 0; i < npctl->ngroups; i++) { if (!strcmp(npctl->groups[i].name, name)) return &npctl->groups[i]; } return NULL; } static int ma35_pinctrl_dt_node_to_map_func(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **map, unsigned int *num_maps) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); struct ma35_pin_group *grp; struct pinctrl_map *new_map; struct device_node *parent; int map_num = 1; int i; /* * first find the group of this node and check if we need create * config maps for pins */ grp = ma35_pinctrl_find_group_by_name(npctl, np->name); if (!grp) { dev_err(npctl->dev, "unable to find group for node %s\n", np->name); return -EINVAL; } map_num += grp->npins; new_map = devm_kcalloc(pctldev->dev, map_num, sizeof(*new_map), GFP_KERNEL); if (!new_map) return -ENOMEM; *map = new_map; *num_maps = map_num; /* create mux map */ parent = of_get_parent(np); if (!parent) return -EINVAL; new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; new_map[0].data.mux.function = parent->name; new_map[0].data.mux.group = np->name; of_node_put(parent); new_map++; for (i = 0; i < grp->npins; i++) { new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; new_map[i].data.configs.group_or_pin = pin_get_name(pctldev, grp->pins[i]); new_map[i].data.configs.configs = grp->settings[i].configs; new_map[i].data.configs.num_configs = grp->settings[i].nconfigs; } dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", (*map)->data.mux.function, (*map)->data.mux.group, map_num); return 0; } static const struct pinctrl_ops ma35_pctrl_ops = { .get_groups_count = ma35_get_groups_count, .get_group_name = ma35_get_group_name, .get_group_pins = ma35_get_group_pins, .dt_node_to_map = ma35_pinctrl_dt_node_to_map_func, .dt_free_map = pinconf_generic_dt_free_map, }; static int ma35_pinmux_get_func_count(struct pinctrl_dev *pctldev) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); return npctl->nfunctions; } static const char *ma35_pinmux_get_func_name(struct pinctrl_dev *pctldev, unsigned int selector) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); return npctl->functions[selector].name; } static int ma35_pinmux_get_func_groups(struct pinctrl_dev *pctldev, unsigned int function, const char *const **groups, unsigned int *const num_groups) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); *groups = npctl->functions[function].groups; *num_groups = npctl->functions[function].ngroups; return 0; } static int ma35_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int selector, unsigned int group) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); struct ma35_pin_group *grp = &npctl->groups[group]; struct ma35_pin_setting *setting = grp->settings; u32 i, regval; dev_dbg(npctl->dev, "enable function %s group %s\n", npctl->functions[selector].name, npctl->groups[group].name); for (i = 0; i < grp->npins; i++) { regmap_read(npctl->regmap, setting->offset, ®val); regval &= ~GENMASK(setting->shift + MA35_MFP_BITS_PER_PORT - 1, setting->shift); regval |= setting->muxval << setting->shift; regmap_write(npctl->regmap, setting->offset, regval); setting++; } return 0; } static const struct pinmux_ops ma35_pmx_ops = { .get_functions_count = ma35_pinmux_get_func_count, .get_function_name = ma35_pinmux_get_func_name, .get_function_groups = ma35_pinmux_get_func_groups, .set_mux = ma35_pinmux_set_mux, .strict = true, }; static void ma35_gpio_set_mode(void __iomem *reg_mode, unsigned int gpio, u32 mode) { u32 regval = readl(reg_mode); regval &= ~MA35_GP_MODE_MASK(gpio); regval |= field_prep(MA35_GP_MODE_MASK(gpio), mode); writel(regval, reg_mode); } static u32 ma35_gpio_get_mode(void __iomem *reg_mode, unsigned int gpio) { u32 regval = readl(reg_mode); return field_get(MA35_GP_MODE_MASK(gpio), regval); } static int ma35_gpio_core_direction_in(struct gpio_chip *gc, unsigned int gpio) { struct ma35_pin_bank *bank = gpiochip_get_data(gc); void __iomem *reg_mode = bank->reg_base + MA35_GP_REG_MODE; guard(raw_spinlock_irqsave)(&ma35_lock); ma35_gpio_set_mode(reg_mode, gpio, MA35_GP_MODE_INPUT); return 0; } static int ma35_gpio_core_direction_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct ma35_pin_bank *bank = gpiochip_get_data(gc); void __iomem *reg_dout = bank->reg_base + MA35_GP_REG_DOUT; void __iomem *reg_mode = bank->reg_base + MA35_GP_REG_MODE; unsigned int regval; guard(raw_spinlock_irqsave)(&ma35_lock); regval = readl(reg_dout); if (val) regval |= BIT(gpio); else regval &= ~BIT(gpio); writel(regval, reg_dout); ma35_gpio_set_mode(reg_mode, gpio, MA35_GP_MODE_OUTPUT); return 0; } static int ma35_gpio_core_get(struct gpio_chip *gc, unsigned int gpio) { struct ma35_pin_bank *bank = gpiochip_get_data(gc); void __iomem *reg_pin = bank->reg_base + MA35_GP_REG_PIN; return !!(readl(reg_pin) & BIT(gpio)); } static void ma35_gpio_core_set(struct gpio_chip *gc, unsigned int gpio, int val) { struct ma35_pin_bank *bank = gpiochip_get_data(gc); void __iomem *reg_dout = bank->reg_base + MA35_GP_REG_DOUT; u32 regval; if (val) regval = readl(reg_dout) | BIT(gpio); else regval = readl(reg_dout) & ~BIT(gpio); writel(regval, reg_dout); } static int ma35_gpio_core_to_request(struct gpio_chip *gc, unsigned int gpio) { struct ma35_pin_bank *bank = gpiochip_get_data(gc); u32 reg_offs, bit_offs, regval; if (gpio < 8) { /* The MFP low register controls port 0 ~ 7 */ reg_offs = bank->bank_num * MA35_MFP_REG_SZ_PER_BANK; bit_offs = gpio * MA35_MFP_BITS_PER_PORT; } else { /* The MFP high register controls port 8 ~ 15 */ reg_offs = bank->bank_num * MA35_MFP_REG_SZ_PER_BANK + 4; bit_offs = (gpio - 8) * MA35_MFP_BITS_PER_PORT; } regmap_read(bank->regmap, MA35_MFP_REG_BASE + reg_offs, ®val); regval &= ~GENMASK(bit_offs + MA35_MFP_BITS_PER_PORT - 1, bit_offs); regmap_write(bank->regmap, MA35_MFP_REG_BASE + reg_offs, regval); return 0; } static void ma35_irq_gpio_ack(struct irq_data *d) { struct ma35_pin_bank *bank = gpiochip_get_data(irq_data_get_irq_chip_data(d)); void __iomem *reg_intsrc = bank->reg_base + MA35_GP_REG_INTSRC; irq_hw_number_t hwirq = irqd_to_hwirq(d); writel(BIT(hwirq), reg_intsrc); } static void ma35_irq_gpio_mask(struct irq_data *d) { struct ma35_pin_bank *bank = gpiochip_get_data(irq_data_get_irq_chip_data(d)); void __iomem *reg_ien = bank->reg_base + MA35_GP_REG_INTEN; irq_hw_number_t hwirq = irqd_to_hwirq(d); u32 regval; regval = readl(reg_ien); regval &= ~MA35_GP_INTEN_BOTH(hwirq); writel(regval, reg_ien); } static void ma35_irq_gpio_unmask(struct irq_data *d) { struct ma35_pin_bank *bank = gpiochip_get_data(irq_data_get_irq_chip_data(d)); void __iomem *reg_itype = bank->reg_base + MA35_GP_REG_INTTYPE; void __iomem *reg_ien = bank->reg_base + MA35_GP_REG_INTEN; irq_hw_number_t hwirq = irqd_to_hwirq(d); u32 bval, regval; bval = bank->irqtype & BIT(hwirq); regval = readl(reg_itype); regval &= ~BIT(hwirq); writel(regval | bval, reg_itype); bval = bank->irqinten & MA35_GP_INTEN_BOTH(hwirq); regval = readl(reg_ien); regval &= ~MA35_GP_INTEN_BOTH(hwirq); writel(regval | bval, reg_ien); } static int ma35_irq_irqtype(struct irq_data *d, unsigned int type) { struct ma35_pin_bank *bank = gpiochip_get_data(irq_data_get_irq_chip_data(d)); irq_hw_number_t hwirq = irqd_to_hwirq(d); switch (type) { case IRQ_TYPE_EDGE_BOTH: irq_set_handler_locked(d, handle_edge_irq); bank->irqtype &= ~BIT(hwirq); bank->irqinten |= MA35_GP_INTEN_BOTH(hwirq); break; case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_LEVEL_HIGH: irq_set_handler_locked(d, handle_edge_irq); bank->irqtype &= ~BIT(hwirq); bank->irqinten |= MA35_GP_INTEN_H(hwirq); bank->irqinten &= ~MA35_GP_INTEN_L(hwirq); break; case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_LEVEL_LOW: irq_set_handler_locked(d, handle_edge_irq); bank->irqtype &= ~BIT(hwirq); bank->irqinten |= MA35_GP_INTEN_L(hwirq); bank->irqinten &= ~MA35_GP_INTEN_H(hwirq); break; default: return -EINVAL; } writel(bank->irqtype, bank->reg_base + MA35_GP_REG_INTTYPE); writel(bank->irqinten, bank->reg_base + MA35_GP_REG_INTEN); return 0; } static struct irq_chip ma35_gpio_irqchip = { .name = "MA35-GPIO-IRQ", .irq_disable = ma35_irq_gpio_mask, .irq_enable = ma35_irq_gpio_unmask, .irq_ack = ma35_irq_gpio_ack, .irq_mask = ma35_irq_gpio_mask, .irq_unmask = ma35_irq_gpio_unmask, .irq_set_type = ma35_irq_irqtype, .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE, GPIOCHIP_IRQ_RESOURCE_HELPERS, }; static void ma35_irq_demux_intgroup(struct irq_desc *desc) { struct ma35_pin_bank *bank = gpiochip_get_data(irq_desc_get_handler_data(desc)); struct irq_domain *irqdomain = bank->chip.irq.domain; struct irq_chip *irqchip = irq_desc_get_chip(desc); unsigned long isr; int offset; chained_irq_enter(irqchip, desc); isr = readl(bank->reg_base + MA35_GP_REG_INTSRC); for_each_set_bit(offset, &isr, bank->nr_pins) generic_handle_irq(irq_find_mapping(irqdomain, offset)); chained_irq_exit(irqchip, desc); } static int ma35_gpiolib_register(struct platform_device *pdev, struct ma35_pinctrl *npctl) { struct ma35_pin_ctrl *ctrl = npctl->ctrl; struct ma35_pin_bank *bank = ctrl->pin_banks; int ret; int i; for (i = 0; i < ctrl->nr_banks; i++, bank++) { if (!bank->valid) { dev_warn(&pdev->dev, "%pfw: bank is not valid\n", bank->fwnode); continue; } bank->irqtype = 0; bank->irqinten = 0; bank->chip.label = bank->name; bank->chip.of_gpio_n_cells = 2; bank->chip.parent = &pdev->dev; bank->chip.request = ma35_gpio_core_to_request; bank->chip.direction_input = ma35_gpio_core_direction_in; bank->chip.direction_output = ma35_gpio_core_direction_out; bank->chip.get = ma35_gpio_core_get; bank->chip.set = ma35_gpio_core_set; bank->chip.base = -1; bank->chip.ngpio = bank->nr_pins; bank->chip.can_sleep = false; if (bank->irq > 0) { struct gpio_irq_chip *girq; girq = &bank->chip.irq; gpio_irq_chip_set_chip(girq, &ma35_gpio_irqchip); girq->parent_handler = ma35_irq_demux_intgroup; girq->num_parents = 1; girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, sizeof(*girq->parents), GFP_KERNEL); if (!girq->parents) return -ENOMEM; girq->parents[0] = bank->irq; girq->default_type = IRQ_TYPE_NONE; girq->handler = handle_bad_irq; } ret = devm_gpiochip_add_data(&pdev->dev, &bank->chip, bank); if (ret) { dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n", bank->chip.label, ret); return ret; } } return 0; } static int ma35_get_bank_data(struct ma35_pin_bank *bank) { bank->reg_base = fwnode_iomap(bank->fwnode, 0); if (!bank->reg_base) return -ENOMEM; bank->irq = fwnode_irq_get(bank->fwnode, 0); bank->nr_pins = MA35_GPIO_PORT_MAX; bank->clk = of_clk_get(to_of_node(bank->fwnode), 0); if (IS_ERR(bank->clk)) return PTR_ERR(bank->clk); return clk_prepare_enable(bank->clk); } static int ma35_pinctrl_get_soc_data(struct ma35_pinctrl *pctl, struct platform_device *pdev) { struct fwnode_handle *child; struct ma35_pin_ctrl *ctrl; struct ma35_pin_bank *bank; int i, id = 0; ctrl = pctl->ctrl; ctrl->nr_banks = MA35_GPIO_BANK_MAX; ctrl->pin_banks = devm_kcalloc(&pdev->dev, ctrl->nr_banks, sizeof(*ctrl->pin_banks), GFP_KERNEL); if (!ctrl->pin_banks) return -ENOMEM; for (i = 0; i < ctrl->nr_banks; i++) { ctrl->pin_banks[i].bank_num = i; ctrl->pin_banks[i].name = gpio_group_name[i]; } for_each_gpiochip_node(&pdev->dev, child) { bank = &ctrl->pin_banks[id]; bank->fwnode = child; bank->regmap = pctl->regmap; bank->dev = &pdev->dev; if (!ma35_get_bank_data(bank)) bank->valid = true; id++; } return 0; } static void ma35_gpio_cla_port(unsigned int gpio_num, unsigned int *group, unsigned int *num) { *group = gpio_num / MA35_GPIO_PORT_MAX; *num = gpio_num % MA35_GPIO_PORT_MAX; } static int ma35_pinconf_set_pull(struct ma35_pinctrl *npctl, unsigned int pin, int pull_up) { unsigned int port, group_num; void __iomem *base; u32 regval, pull_sel = MA35_GP_PUSEL_DISABLE; ma35_gpio_cla_port(pin, &group_num, &port); base = npctl->ctrl->pin_banks[group_num].reg_base; regval = readl(base + MA35_GP_REG_PUSEL); regval &= ~MA35_GP_PUSEL_MASK(port); switch (pull_up) { case PIN_CONFIG_BIAS_PULL_UP: pull_sel = MA35_GP_PUSEL_PULL_UP; break; case PIN_CONFIG_BIAS_PULL_DOWN: pull_sel = MA35_GP_PUSEL_PULL_DOWN; break; case PIN_CONFIG_BIAS_DISABLE: pull_sel = MA35_GP_PUSEL_DISABLE; break; } regval |= field_prep(MA35_GP_PUSEL_MASK(port), pull_sel); writel(regval, base + MA35_GP_REG_PUSEL); return 0; } static int ma35_pinconf_get_output(struct ma35_pinctrl *npctl, unsigned int pin) { unsigned int port, group_num; void __iomem *base; u32 mode; ma35_gpio_cla_port(pin, &group_num, &port); base = npctl->ctrl->pin_banks[group_num].reg_base; mode = ma35_gpio_get_mode(base + MA35_GP_REG_MODE, port); if (mode == MA35_GP_MODE_OUTPUT) return 1; return 0; } static int ma35_pinconf_get_pull(struct ma35_pinctrl *npctl, unsigned int pin) { unsigned int port, group_num; void __iomem *base; u32 regval, pull_sel; ma35_gpio_cla_port(pin, &group_num, &port); base = npctl->ctrl->pin_banks[group_num].reg_base; regval = readl(base + MA35_GP_REG_PUSEL); pull_sel = field_get(MA35_GP_PUSEL_MASK(port), regval); switch (pull_sel) { case MA35_GP_PUSEL_PULL_UP: return PIN_CONFIG_BIAS_PULL_UP; case MA35_GP_PUSEL_PULL_DOWN: return PIN_CONFIG_BIAS_PULL_DOWN; case MA35_GP_PUSEL_DISABLE: return PIN_CONFIG_BIAS_DISABLE; } return PIN_CONFIG_BIAS_DISABLE; } static int ma35_pinconf_set_output(struct ma35_pinctrl *npctl, unsigned int pin, bool out) { unsigned int port, group_num; void __iomem *base; ma35_gpio_cla_port(pin, &group_num, &port); base = npctl->ctrl->pin_banks[group_num].reg_base; ma35_gpio_set_mode(base + MA35_GP_REG_MODE, port, MA35_GP_MODE_OUTPUT); return 0; } static int ma35_pinconf_get_power_source(struct ma35_pinctrl *npctl, unsigned int pin) { unsigned int port, group_num; void __iomem *base; u32 regval; ma35_gpio_cla_port(pin, &group_num, &port); base = npctl->ctrl->pin_banks[group_num].reg_base; regval = readl(base + MA35_GP_REG_SPW); if (regval & BIT(port)) return MVOLT_3300; else return MVOLT_1800; } static int ma35_pinconf_set_power_source(struct ma35_pinctrl *npctl, unsigned int pin, int arg) { unsigned int port, group_num; void __iomem *base; u32 regval; if ((arg != MVOLT_1800) && (arg != MVOLT_3300)) return -EINVAL; ma35_gpio_cla_port(pin, &group_num, &port); base = npctl->ctrl->pin_banks[group_num].reg_base; regval = readl(base + MA35_GP_REG_SPW); if (arg == MVOLT_1800) regval &= ~BIT(port); else regval |= BIT(port); writel(regval, base + MA35_GP_REG_SPW); return 0; } static int ma35_pinconf_get_drive_strength(struct ma35_pinctrl *npctl, unsigned int pin, u32 *strength) { unsigned int port, group_num; void __iomem *base; u32 regval, ds_val; ma35_gpio_cla_port(pin, &group_num, &port); base = npctl->ctrl->pin_banks[group_num].reg_base; regval = readl(base + MA35_GP_DS_REG(port)); ds_val = field_get(MA35_GP_DS_MASK(port), regval); if (ma35_pinconf_get_power_source(npctl, pin) == MVOLT_1800) *strength = ds_1800mv_tbl[ds_val]; else *strength = ds_3300mv_tbl[ds_val]; return 0; } static int ma35_pinconf_set_drive_strength(struct ma35_pinctrl *npctl, unsigned int pin, int strength) { unsigned int port, group_num; void __iomem *base; int i, ds_val = -1; u32 regval; if (ma35_pinconf_get_power_source(npctl, pin) == MVOLT_1800) { for (i = 0; i < ARRAY_SIZE(ds_1800mv_tbl); i++) { if (ds_1800mv_tbl[i] == strength) { ds_val = i; break; } } } else { for (i = 0; i < ARRAY_SIZE(ds_3300mv_tbl); i++) { if (ds_3300mv_tbl[i] == strength) { ds_val = i; break; } } } if (ds_val == -1) return -EINVAL; ma35_gpio_cla_port(pin, &group_num, &port); base = npctl->ctrl->pin_banks[group_num].reg_base; regval = readl(base + MA35_GP_DS_REG(port)); regval &= ~MA35_GP_DS_MASK(port); regval |= field_prep(MA35_GP_DS_MASK(port), ds_val); writel(regval, base + MA35_GP_DS_REG(port)); return 0; } static int ma35_pinconf_get_schmitt_enable(struct ma35_pinctrl *npctl, unsigned int pin) { unsigned int port, group_num; void __iomem *base; u32 regval; ma35_gpio_cla_port(pin, &group_num, &port); base = npctl->ctrl->pin_banks[group_num].reg_base; regval = readl(base + MA35_GP_REG_SMTEN); return !!(regval & BIT(port)); } static int ma35_pinconf_set_schmitt(struct ma35_pinctrl *npctl, unsigned int pin, int enable) { unsigned int port, group_num; void __iomem *base; u32 regval; ma35_gpio_cla_port(pin, &group_num, &port); base = npctl->ctrl->pin_banks[group_num].reg_base; regval = readl(base + MA35_GP_REG_SMTEN); if (enable) regval |= BIT(port); else regval &= ~BIT(port); writel(regval, base + MA35_GP_REG_SMTEN); return 0; } static int ma35_pinconf_get_slew_rate(struct ma35_pinctrl *npctl, unsigned int pin) { unsigned int port, group_num; void __iomem *base; u32 regval; ma35_gpio_cla_port(pin, &group_num, &port); base = npctl->ctrl->pin_banks[group_num].reg_base; regval = readl(base + MA35_GP_REG_SLEWCTL); return field_get(MA35_GP_SLEWCTL_MASK(port), regval); } static int ma35_pinconf_set_slew_rate(struct ma35_pinctrl *npctl, unsigned int pin, int rate) { unsigned int port, group_num; void __iomem *base; u32 regval; ma35_gpio_cla_port(pin, &group_num, &port); base = npctl->ctrl->pin_banks[group_num].reg_base; regval = readl(base + MA35_GP_REG_SLEWCTL); regval &= ~MA35_GP_SLEWCTL_MASK(port); regval |= field_prep(MA35_GP_SLEWCTL_MASK(port), rate); writel(regval, base + MA35_GP_REG_SLEWCTL); return 0; } static int ma35_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, unsigned long *config) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); enum pin_config_param param = pinconf_to_config_param(*config); u32 arg; int ret; switch (param) { case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_UP: if (ma35_pinconf_get_pull(npctl, pin) != param) return -EINVAL; arg = 1; break; case PIN_CONFIG_DRIVE_STRENGTH: ret = ma35_pinconf_get_drive_strength(npctl, pin, &arg); if (ret) return ret; break; case PIN_CONFIG_INPUT_SCHMITT_ENABLE: arg = ma35_pinconf_get_schmitt_enable(npctl, pin); break; case PIN_CONFIG_SLEW_RATE: arg = ma35_pinconf_get_slew_rate(npctl, pin); break; case PIN_CONFIG_OUTPUT_ENABLE: arg = ma35_pinconf_get_output(npctl, pin); break; case PIN_CONFIG_POWER_SOURCE: arg = ma35_pinconf_get_power_source(npctl, pin); break; default: return -EINVAL; } *config = pinconf_to_config_packed(param, arg); return 0; } static int ma35_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, unsigned long *configs, unsigned int num_configs) { struct ma35_pinctrl *npctl = pinctrl_dev_get_drvdata(pctldev); enum pin_config_param param; unsigned int arg = 0; int i, ret = 0; for (i = 0; i < num_configs; i++) { param = pinconf_to_config_param(configs[i]); arg = pinconf_to_config_argument(configs[i]); switch (param) { case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_DOWN: ret = ma35_pinconf_set_pull(npctl, pin, param); break; case PIN_CONFIG_DRIVE_STRENGTH: ret = ma35_pinconf_set_drive_strength(npctl, pin, arg); break; case PIN_CONFIG_INPUT_SCHMITT_ENABLE: ret = ma35_pinconf_set_schmitt(npctl, pin, 1); break; case PIN_CONFIG_INPUT_SCHMITT: ret = ma35_pinconf_set_schmitt(npctl, pin, arg); break; case PIN_CONFIG_SLEW_RATE: ret = ma35_pinconf_set_slew_rate(npctl, pin, arg); break; case PIN_CONFIG_OUTPUT_ENABLE: ret = ma35_pinconf_set_output(npctl, pin, arg); break; case PIN_CONFIG_POWER_SOURCE: ret = ma35_pinconf_set_power_source(npctl, pin, arg); break; default: return -EINVAL; } if (ret) break; } return ret; } static const struct pinconf_ops ma35_pinconf_ops = { .pin_config_get = ma35_pinconf_get, .pin_config_set = ma35_pinconf_set, .is_generic = true, }; static int ma35_pinctrl_parse_groups(struct device_node *np, struct ma35_pin_group *grp, struct ma35_pinctrl *npctl, u32 index) { struct ma35_pin_setting *pin; unsigned long *configs; unsigned int nconfigs; int i, j, count, ret; u32 *elems; grp->name = np->name; ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &nconfigs); if (ret) return ret; count = of_property_count_elems_of_size(np, "nuvoton,pins", sizeof(u32)); if (!count || count % 3) return -EINVAL; elems = devm_kmalloc_array(npctl->dev, count, sizeof(u32), GFP_KERNEL); if (!elems) return -ENOMEM; ret = of_property_read_u32_array(np, "nuvoton,pins", elems, count); if (ret) return -EINVAL; grp->npins = count / 3; grp->pins = devm_kcalloc(npctl->dev, grp->npins, sizeof(*grp->pins), GFP_KERNEL); if (!grp->pins) return -ENOMEM; grp->settings = devm_kcalloc(npctl->dev, grp->npins, sizeof(*grp->settings), GFP_KERNEL); if (!grp->settings) return -ENOMEM; pin = grp->settings; for (i = 0, j = 0; i < count; i += 3, j++) { pin->offset = elems[i] * MA35_MFP_REG_SZ_PER_BANK + MA35_MFP_REG_BASE; pin->shift = (elems[i + 1] * MA35_MFP_BITS_PER_PORT) % 32; pin->muxval = elems[i + 2]; pin->configs = configs; pin->nconfigs = nconfigs; grp->pins[j] = npctl->info->get_pin_num(pin->offset, pin->shift); pin++; } return 0; } static int ma35_pinctrl_parse_functions(struct device_node *np, struct ma35_pinctrl *npctl, u32 index) { struct device_node *child; struct ma35_pin_func *func; struct ma35_pin_group *grp; static u32 grp_index; u32 ret, i = 0; dev_dbg(npctl->dev, "parse function(%d): %s\n", index, np->name); func = &npctl->functions[index]; func->name = np->name; func->ngroups = of_get_child_count(np); if (func->ngroups <= 0) return 0; func->groups = devm_kcalloc(npctl->dev, func->ngroups, sizeof(char *), GFP_KERNEL); if (!func->groups) return -ENOMEM; for_each_child_of_node(np, child) { func->groups[i] = child->name; grp = &npctl->groups[grp_index++]; ret = ma35_pinctrl_parse_groups(child, grp, npctl, i++); if (ret) { of_node_put(child); return ret; } } return 0; } static int ma35_pinctrl_probe_dt(struct platform_device *pdev, struct ma35_pinctrl *npctl) { struct fwnode_handle *child; u32 idx = 0; int ret; device_for_each_child_node(&pdev->dev, child) { if (fwnode_property_present(child, "gpio-controller")) continue; npctl->nfunctions++; npctl->ngroups += of_get_child_count(to_of_node(child)); } if (!npctl->nfunctions) return -EINVAL; npctl->functions = devm_kcalloc(&pdev->dev, npctl->nfunctions, sizeof(*npctl->functions), GFP_KERNEL); if (!npctl->functions) return -ENOMEM; npctl->groups = devm_kcalloc(&pdev->dev, npctl->ngroups, sizeof(*npctl->groups), GFP_KERNEL); if (!npctl->groups) return -ENOMEM; device_for_each_child_node(&pdev->dev, child) { if (fwnode_property_present(child, "gpio-controller")) continue; ret = ma35_pinctrl_parse_functions(to_of_node(child), npctl, idx++); if (ret) { fwnode_handle_put(child); dev_err(&pdev->dev, "failed to parse function\n"); return ret; } } return 0; } int ma35_pinctrl_probe(struct platform_device *pdev, const struct ma35_pinctrl_soc_info *info) { struct pinctrl_desc *ma35_pinctrl_desc; struct device *dev = &pdev->dev; struct ma35_pinctrl *npctl; int ret; if (!info || !info->pins || !info->npins) { dev_err(&pdev->dev, "wrong pinctrl info\n"); return -EINVAL; } npctl = devm_kzalloc(&pdev->dev, sizeof(*npctl), GFP_KERNEL); if (!npctl) return -ENOMEM; ma35_pinctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*ma35_pinctrl_desc), GFP_KERNEL); if (!ma35_pinctrl_desc) return -ENOMEM; npctl->ctrl = devm_kzalloc(&pdev->dev, sizeof(*npctl->ctrl), GFP_KERNEL); if (!npctl->ctrl) return -ENOMEM; ma35_pinctrl_desc->name = dev_name(&pdev->dev); ma35_pinctrl_desc->pins = info->pins; ma35_pinctrl_desc->npins = info->npins; ma35_pinctrl_desc->pctlops = &ma35_pctrl_ops; ma35_pinctrl_desc->pmxops = &ma35_pmx_ops; ma35_pinctrl_desc->confops = &ma35_pinconf_ops; ma35_pinctrl_desc->owner = THIS_MODULE; npctl->info = info; npctl->dev = &pdev->dev; npctl->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "nuvoton,sys"); if (IS_ERR(npctl->regmap)) return dev_err_probe(&pdev->dev, PTR_ERR(npctl->regmap), "No syscfg phandle specified\n"); ret = ma35_pinctrl_get_soc_data(npctl, pdev); if (ret) return dev_err_probe(&pdev->dev, ret, "fail to get soc data\n"); platform_set_drvdata(pdev, npctl); ret = ma35_pinctrl_probe_dt(pdev, npctl); if (ret) return dev_err_probe(&pdev->dev, ret, "fail to probe MA35 pinctrl dt\n"); ret = devm_pinctrl_register_and_init(dev, ma35_pinctrl_desc, npctl, &npctl->pctl); if (ret) return dev_err_probe(&pdev->dev, ret, "fail to register MA35 pinctrl\n"); ret = pinctrl_enable(npctl->pctl); if (ret) return dev_err_probe(&pdev->dev, ret, "fail to enable MA35 pinctrl\n"); return ma35_gpiolib_register(pdev, npctl); } int ma35_pinctrl_suspend(struct device *dev) { struct ma35_pinctrl *npctl = dev_get_drvdata(dev); return pinctrl_force_sleep(npctl->pctl); } int ma35_pinctrl_resume(struct device *dev) { struct ma35_pinctrl *npctl = dev_get_drvdata(dev); return pinctrl_force_default(npctl->pctl); }
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1