diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 93f3631ba238..c03815d27e7d 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -20,10 +20,10 @@ #include #include #include -#include -#include +#include #include #include +#include #include #include #include @@ -33,79 +33,12 @@ #include #include #include +#include #include #include "core.h" #include "pinconf.h" - -struct rockchip_gpio_regs { - u32 port_dr; - u32 port_ddr; - u32 int_en; - u32 int_mask; - u32 int_type; - u32 int_polarity; - u32 int_bothedge; - u32 int_status; - u32 int_rawstatus; - u32 debounce; - u32 dbclk_div_en; - u32 dbclk_div_con; - u32 port_eoi; - u32 ext_port; - u32 version_id; -}; - -static const struct rockchip_gpio_regs gpio_regs_v1 = { - .port_dr = 0x00, - .port_ddr = 0x04, - .int_en = 0x30, - .int_mask = 0x34, - .int_type = 0x38, - .int_polarity = 0x3c, - .int_status = 0x40, - .int_rawstatus = 0x44, - .debounce = 0x48, - .port_eoi = 0x4c, - .ext_port = 0x50, -}; - -static const struct rockchip_gpio_regs gpio_regs_v2 = { - .port_dr = 0x00, - .port_ddr = 0x08, - .int_en = 0x10, - .int_mask = 0x18, - .int_type = 0x20, - .int_polarity = 0x28, - .int_bothedge = 0x30, - .int_status = 0x50, - .int_rawstatus = 0x58, - .debounce = 0x38, - .dbclk_div_en = 0x40, - .dbclk_div_con = 0x48, - .port_eoi = 0x60, - .ext_port = 0x70, - .version_id = 0x78, -}; - -enum rockchip_pinctrl_type { - PX30, - RV1108, - RV1126, - RK1808, - RK2928, - RK3066B, - RK3128, - RK3188, - RK3288, - RK3308, - RK3368, - RK3399, - RK3568, -}; - -#define GPIO_TYPE_V1 (0) /* GPIO Version ID reserved */ -#define GPIO_TYPE_V2 (0x01000C2B) /* GPIO Version ID 0x01000C2B */ +#include "pinctrl-rockchip.h" /** * Generate a bitmask for setting a value (v) with a write mask bit in hiword @@ -126,109 +59,6 @@ enum rockchip_pinctrl_type { #define IOMUX_WRITABLE_32BIT BIT(6) #define IOMUX_L_SOURCE_PMU BIT(7) -/** - * struct rockchip_iomux - * @type: iomux variant using IOMUX_* constants - * @offset: if initialized to -1 it will be autocalculated, by specifying - * an initial offset value the relevant source offset can be reset - * to a new value for autocalculating the following iomux registers. - */ -struct rockchip_iomux { - int type; - int offset; -}; - -/* - * enum type index corresponding to rockchip_perpin_drv_list arrays index. - */ -enum rockchip_pin_drv_type { - DRV_TYPE_IO_DEFAULT = 0, - DRV_TYPE_IO_1V8_OR_3V0, - DRV_TYPE_IO_1V8_ONLY, - DRV_TYPE_IO_1V8_3V0_AUTO, - DRV_TYPE_IO_3V3_ONLY, - DRV_TYPE_MAX -}; - -/* - * enum type index corresponding to rockchip_pull_list arrays index. - */ -enum rockchip_pin_pull_type { - PULL_TYPE_IO_DEFAULT = 0, - PULL_TYPE_IO_1V8_ONLY, - PULL_TYPE_MAX -}; - -/** - * struct rockchip_drv - * @drv_type: drive strength variant using rockchip_perpin_drv_type - * @offset: if initialized to -1 it will be autocalculated, by specifying - * an initial offset value the relevant source offset can be reset - * to a new value for autocalculating the following drive strength - * registers. if used chips own cal_drv func instead to calculate - * registers offset, the variant could be ignored. - */ -struct rockchip_drv { - enum rockchip_pin_drv_type drv_type; - int offset; -}; - -/** - * struct rockchip_pin_bank - * @reg_base: register base of the gpio bank - * @regmap_pull: optional separate register for additional pull settings - * @clk: clock of the gpio bank - * @db_clk: clock of the gpio debounce - * @irq: interrupt of the gpio bank - * @saved_masks: Saved content of GPIO_INTEN at suspend time. - * @pin_base: first pin number - * @nr_pins: number of pins in this bank - * @name: name of the bank - * @bank_num: number of the bank, to account for holes - * @iomux: array describing the 4 iomux sources of the bank - * @drv: array describing the 4 drive strength sources of the bank - * @pull_type: array describing the 4 pull type sources of the bank - * @valid: is all necessary information present - * @of_node: dt node of this bank - * @drvdata: common pinctrl basedata - * @domain: irqdomain of the gpio bank - * @gpio_chip: gpiolib chip - * @grange: gpio range - * @slock: spinlock for the gpio bank - * @rockchip_gpio_regs: gpio register offset - * @gpio_type: gpio version id - * @toggle_edge_mode: bit mask to toggle (falling/rising) edge mode - * @recalced_mask: bit mask to indicate a need to recalulate the mask - * @route_mask: bits describing the routing pins of per bank - */ -struct rockchip_pin_bank { - void __iomem *reg_base; - struct regmap *regmap_pull; - struct clk *clk; - struct clk *db_clk; - int irq; - u32 saved_masks; - u32 pin_base; - u8 nr_pins; - char *name; - u8 bank_num; - struct rockchip_iomux iomux[4]; - struct rockchip_drv drv[4]; - enum rockchip_pin_pull_type pull_type[4]; - bool valid; - struct device_node *of_node; - struct rockchip_pinctrl *drvdata; - struct irq_domain *domain; - struct gpio_chip gpio_chip; - struct pinctrl_gpio_range grange; - raw_spinlock_t slock; - const struct rockchip_gpio_regs *gpio_regs; - u32 gpio_type; - u32 toggle_edge_mode; - u32 recalced_mask; - u32 route_mask; -}; - #define PIN_BANK(id, pins, label) \ { \ .bank_num = id, \ @@ -383,205 +213,12 @@ struct rockchip_pin_bank { #define RK_MUXROUTE_PMU(ID, PIN, FUNC, REG, VAL) \ PIN_BANK_MUX_ROUTE_FLAGS(ID, PIN, FUNC, REG, VAL, ROCKCHIP_ROUTE_PMU) -/** - * struct rockchip_mux_recalced_data: represent a pin iomux data. - * @num: bank number. - * @pin: pin number. - * @bit: index at register. - * @reg: register offset. - * @mask: mask bit - */ -struct rockchip_mux_recalced_data { - u8 num; - u8 pin; - u32 reg; - u8 bit; - u8 mask; -}; - -enum rockchip_mux_route_location { - ROCKCHIP_ROUTE_SAME = 0, - ROCKCHIP_ROUTE_PMU, - ROCKCHIP_ROUTE_GRF, -}; - -/** - * struct rockchip_mux_recalced_data: represent a pin iomux data. - * @bank_num: bank number. - * @pin: index at register or used to calc index. - * @func: the min pin. - * @route_location: the mux route location (same, pmu, grf). - * @route_offset: the max pin. - * @route_val: the register offset. - */ -struct rockchip_mux_route_data { - u8 bank_num; - u8 pin; - u8 func; - enum rockchip_mux_route_location route_location; - u32 route_offset; - u32 route_val; -}; - -struct rockchip_pin_ctrl { - struct rockchip_pin_bank *pin_banks; - u32 nr_banks; - u32 nr_pins; - char *label; - enum rockchip_pinctrl_type type; - int grf_mux_offset; - int pmu_mux_offset; - int grf_drv_offset; - int pmu_drv_offset; - struct rockchip_mux_recalced_data *iomux_recalced; - u32 niomux_recalced; - struct rockchip_mux_route_data *iomux_routes; - u32 niomux_routes; - - int (*soc_data_init)(struct rockchip_pinctrl *info); - - void (*pull_calc_reg)(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit); - void (*drv_calc_reg)(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit); - int (*schmitt_calc_reg)(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit); - int (*slew_rate_calc_reg)(struct rockchip_pin_bank *bank, - int pin_num, struct regmap **regmap, - int *reg, u8 *bit); -}; - -struct rockchip_pin_config { - unsigned int func; - unsigned long *configs; - unsigned int nconfigs; -}; - -/** - * struct rockchip_pin_group: represent group of pins of a pinmux function. - * @name: name of the pin group, used to lookup the group. - * @pins: the pins included in this group. - * @npins: number of pins included in this group. - * @data: local pin configuration - */ -struct rockchip_pin_group { - const char *name; - unsigned int npins; - unsigned int *pins; - struct rockchip_pin_config *data; -}; - -/** - * struct rockchip_pmx_func: represent a pin function. - * @name: name of the pin function, used to lookup the function. - * @groups: one or more names of pin groups that provide this function. - * @ngroups: number of groups included in @groups. - */ -struct rockchip_pmx_func { - const char *name; - const char **groups; - u8 ngroups; -}; - -struct rockchip_pinctrl { - struct regmap *regmap_base; - int reg_size; - struct regmap *regmap_pull; - struct regmap *regmap_pmu; - struct device *dev; - struct rockchip_pin_ctrl *ctrl; - struct pinctrl_desc pctl; - struct pinctrl_dev *pctl_dev; - struct rockchip_pin_group *groups; - unsigned int ngroups; - struct rockchip_pmx_func *functions; - unsigned int nfunctions; -}; - static struct regmap_config rockchip_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, }; -static inline void gpio_writel_v2(u32 val, void __iomem *reg) -{ - writel((val & 0xffff) | 0xffff0000, reg); - writel((val >> 16) | 0xffff0000, reg + 0x4); -} - -static inline u32 gpio_readl_v2(void __iomem *reg) -{ - return readl(reg + 0x4) << 16 | readl(reg); -} - -static inline void rockchip_gpio_writel(struct rockchip_pin_bank *bank, - u32 value, unsigned int offset) -{ - void __iomem *reg = bank->reg_base + offset; - - if (bank->gpio_type == GPIO_TYPE_V2) - gpio_writel_v2(value, reg); - else - writel(value, reg); -} - -static inline u32 rockchip_gpio_readl(struct rockchip_pin_bank *bank, - unsigned int offset) -{ - void __iomem *reg = bank->reg_base + offset; - u32 value; - - if (bank->gpio_type == GPIO_TYPE_V2) - value = gpio_readl_v2(reg); - else - value = readl(reg); - - return value; -} - -static inline void rockchip_gpio_writel_bit(struct rockchip_pin_bank *bank, - u32 bit, u32 value, - unsigned int offset) -{ - void __iomem *reg = bank->reg_base + offset; - u32 data; - - if (bank->gpio_type == GPIO_TYPE_V2) { - if (value) - data = BIT(bit % 16) | BIT(bit % 16 + 16); - else - data = BIT(bit % 16 + 16); - writel(data, bit >= 16 ? reg + 0x4 : reg); - } else { - data = readl(reg); - data &= ~BIT(bit); - if (value) - data |= BIT(bit); - writel(data, reg); - } -} - -static inline u32 rockchip_gpio_readl_bit(struct rockchip_pin_bank *bank, - u32 bit, unsigned int offset) -{ - void __iomem *reg = bank->reg_base + offset; - u32 data; - - if (bank->gpio_type == GPIO_TYPE_V2) { - data = readl(bit >= 16 ? reg + 0x4 : reg); - data >>= bit % 16; - } else { - data = readl(reg); - data >>= bit; - } - - return data & (0x1); -} - static inline const struct rockchip_pin_group *pinctrl_name_to_group( const struct rockchip_pinctrl *info, const char *name) @@ -1516,6 +1153,9 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) if (bank->recalced_mask & BIT(pin)) rockchip_get_recalced_mux(bank, pin, ®, &bit, &mask); + if (mux > mask) + return -EINVAL; + if (bank->route_mask & BIT(pin)) { if (rockchip_get_mux_route(bank, pin, mux, &route_location, &route_reg, &route_val)) { @@ -2377,6 +2017,12 @@ static void rk3568_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, *bit = (pin_num % RK3568_DRV_PINS_PER_REG); *bit *= RK3568_DRV_BITS_PER_PIN; } + + if (rockchip_get_cpu_version() == 0) + if ((bank->bank_num == 1 && (pin_num == 15 || pin_num == 23 || pin_num == 31)) || + ((bank->bank_num == 2 || bank->bank_num == 3 || bank->bank_num == 4) && + (pin_num == 7 || pin_num == 15 || pin_num == 23 || pin_num == 31))) + *bit -= RK3568_DRV_BITS_PER_PIN; } static int rockchip_perpin_drv_list[DRV_TYPE_MAX][8] = { @@ -2564,8 +2210,35 @@ config: data |= (ret << bit); ret = regmap_update_bits(regmap, reg, rmask, data); + if (ret) + return ret; - return ret; + if (ctrl->type == RK3568 && rockchip_get_cpu_version() == 0) { + if (bank->bank_num == 1 && pin_num == 21) + reg = 0x0840; + else if (bank->bank_num == 2 && pin_num == 2) + reg = 0x0844; + else if (bank->bank_num == 2 && pin_num == 8) + reg = 0x0848; + else if (bank->bank_num == 3 && pin_num == 0) + reg = 0x084c; + else if (bank->bank_num == 3 && pin_num == 6) + reg = 0x0850; + else if (bank->bank_num == 4 && pin_num == 0) + reg = 0x0854; + else + return 0; + + data = ((1 << rmask_bits) - 1) << 16; + rmask = data | (data >> 16); + data |= (1 << (strength + 1)) - 1; + + ret = regmap_update_bits(regmap, reg, rmask, data); + if (ret) + return ret; + } + + return 0; } static int rockchip_pull_list[PULL_TYPE_MAX][4] = { @@ -2617,6 +2290,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num) case RK3308: case RK3368: case RK3399: + case RK3568: pull_type = bank->pull_type[pin_num / 8]; data >>= bit; data &= (1 << RK3188_PULL_BITS_PER_PIN) - 1; @@ -2946,9 +2620,9 @@ static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, break; } - if (ret) { + if (ret && cnt) { /* revert the already done pin settings */ - for (cnt--; cnt >= 0; cnt--) + for (cnt--; cnt >= 0 && !data[cnt].func; cnt--) rockchip_set_mux(bank, pins[cnt] - bank->pin_base, 0); return ret; @@ -2957,82 +2631,11 @@ static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, return 0; } -static int rockchip_gpio_get_direction(struct gpio_chip *chip, unsigned offset) -{ - struct rockchip_pin_bank *bank = gpiochip_get_data(chip); - u32 data; - int ret; - - ret = clk_enable(bank->clk); - if (ret < 0) { - dev_err(bank->drvdata->dev, - "failed to enable clock for bank %s\n", bank->name); - return ret; - } - - data = rockchip_gpio_readl_bit(bank, offset, bank->gpio_regs->port_ddr); - clk_disable(bank->clk); - - if (data & BIT(offset)) - return GPIO_LINE_DIRECTION_OUT; - - return GPIO_LINE_DIRECTION_IN; -} - -/* - * The calls to gpio_direction_output() and gpio_direction_input() - * leads to this function call (via the pinctrl_gpio_direction_{input|output}() - * function called from the gpiolib interface). - */ -static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip, - int pin, bool input) -{ - struct rockchip_pin_bank *bank; - int ret; - unsigned long flags; - - bank = gpiochip_get_data(chip); - - ret = rockchip_set_mux(bank, pin, RK_FUNC_GPIO); - if (ret < 0) - return ret; - - clk_enable(bank->clk); - raw_spin_lock_irqsave(&bank->slock, flags); - - /* set bit to 1 for output, 0 for input */ - rockchip_gpio_writel_bit(bank, pin, (u32)!input, - bank->gpio_regs->port_ddr); - - raw_spin_unlock_irqrestore(&bank->slock, flags); - clk_disable(bank->clk); - - return 0; -} - -static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, - unsigned offset, bool input) -{ - struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); - struct gpio_chip *chip; - int pin; - - chip = range->gc; - pin = offset - chip->base; - dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n", - offset, range->name, pin, input ? "input" : "output"); - - return _rockchip_pmx_gpio_set_direction(chip, offset - chip->base, - input); -} - static const struct pinmux_ops rockchip_pmx_ops = { .get_functions_count = rockchip_pmx_get_funcs_count, .get_function_name = rockchip_pmx_get_func_name, .get_function_groups = rockchip_pmx_get_groups, .set_mux = rockchip_pmx_set, - .gpio_set_direction = rockchip_pmx_gpio_set_direction, }; /* @@ -3065,15 +2668,13 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl, return false; } -static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value); -static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset); - /* set the pin config settings for a specified pin */ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, unsigned long *configs, unsigned num_configs) { struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); struct rockchip_pin_bank *bank = pin_to_bank(info, pin); + struct gpio_chip *gpio = &bank->gpio_chip; enum pin_config_param param; u32 arg; int i; @@ -3106,10 +2707,13 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, return rc; break; case PIN_CONFIG_OUTPUT: - rockchip_gpio_set(&bank->gpio_chip, - pin - bank->pin_base, arg); - rc = _rockchip_pmx_gpio_set_direction(&bank->gpio_chip, - pin - bank->pin_base, false); + rc = rockchip_get_mux(bank, pin - bank->pin_base); + if (rc != 0) { + dev_err(info->dev, "pin-%d has been mux to func%d\n", pin, rc); + return -EINVAL; + } + + rc = gpio->direction_output(gpio, pin - bank->pin_base, arg); if (rc) return rc; break; @@ -3143,7 +2747,6 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, break; default: return -ENOTSUPP; - break; } } /* for each config */ @@ -3156,6 +2759,7 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, { struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); struct rockchip_pin_bank *bank = pin_to_bank(info, pin); + struct gpio_chip *gpio = &bank->gpio_chip; enum pin_config_param param = pinconf_to_config_param(*config); u16 arg; int rc; @@ -3181,10 +2785,12 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, break; case PIN_CONFIG_OUTPUT: rc = rockchip_get_mux(bank, pin - bank->pin_base); - if (rc != RK_FUNC_GPIO) + if (rc != 0) { + dev_err(info->dev, "pin-%d has been mux to func%d\n", pin, rc); return -EINVAL; + } - rc = rockchip_gpio_get(&bank->gpio_chip, pin - bank->pin_base); + rc = gpio->get(gpio, pin - bank->pin_base); if (rc < 0) return rc; @@ -3223,7 +2829,6 @@ static int rockchip_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, break; default: return -ENOTSUPP; - break; } *config = pinconf_to_config_packed(param, arg); @@ -3432,7 +3037,7 @@ static int rockchip_pinctrl_register(struct platform_device *pdev, ctrldesc->npins = info->ctrl->nr_pins; pdesc = pindesc; - for (bank = 0 , k = 0; bank < info->ctrl->nr_banks; bank++) { + for (bank = 0, k = 0; bank < info->ctrl->nr_banks; bank++) { pin_bank = &info->ctrl->pin_banks[bank]; for (pin = 0; pin < pin_bank->nr_pins; pin++, k++) { pdesc->number = k; @@ -3452,626 +3057,6 @@ static int rockchip_pinctrl_register(struct platform_device *pdev, return PTR_ERR(info->pctl_dev); } - for (bank = 0; bank < info->ctrl->nr_banks; ++bank) { - pin_bank = &info->ctrl->pin_banks[bank]; - pin_bank->grange.name = pin_bank->name; - pin_bank->grange.id = bank; - pin_bank->grange.pin_base = pin_bank->pin_base; - pin_bank->grange.base = pin_bank->gpio_chip.base; - pin_bank->grange.npins = pin_bank->gpio_chip.ngpio; - pin_bank->grange.gc = &pin_bank->gpio_chip; - pinctrl_add_gpio_range(info->pctl_dev, &pin_bank->grange); - } - - return 0; -} - -/* - * GPIO handling - */ - -static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value) -{ - struct rockchip_pin_bank *bank = gpiochip_get_data(gc); - unsigned long flags; - - clk_enable(bank->clk); - raw_spin_lock_irqsave(&bank->slock, flags); - - rockchip_gpio_writel_bit(bank, offset, value, bank->gpio_regs->port_dr); - - raw_spin_unlock_irqrestore(&bank->slock, flags); - clk_disable(bank->clk); -} - -/* - * Returns the level of the pin for input direction and setting of the DR - * register for output gpios. - */ -static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset) -{ - struct rockchip_pin_bank *bank = gpiochip_get_data(gc); - u32 data; - - clk_enable(bank->clk); - data = readl(bank->reg_base + bank->gpio_regs->ext_port); - clk_disable(bank->clk); - data >>= offset; - data &= 1; - return data; -} - -/* - * gpiolib gpio_direction_input callback function. The setting of the pin - * mux function as 'gpio input' will be handled by the pinctrl subsystem - * interface. - */ -static int rockchip_gpio_direction_input(struct gpio_chip *gc, unsigned offset) -{ - return pinctrl_gpio_direction_input(gc->base + offset); -} - -/* - * gpiolib gpio_direction_output callback function. The setting of the pin - * mux function as 'gpio output' will be handled by the pinctrl subsystem - * interface. - */ -static int rockchip_gpio_direction_output(struct gpio_chip *gc, - unsigned offset, int value) -{ - rockchip_gpio_set(gc, offset, value); - return pinctrl_gpio_direction_output(gc->base + offset); -} - -static int rockchip_gpio_set_debounce(struct gpio_chip *gc, - unsigned int offset, unsigned int debounce) -{ - struct rockchip_pin_bank *bank = gpiochip_get_data(gc); - const struct rockchip_gpio_regs *reg = bank->gpio_regs; - unsigned long flags, div_reg, freq, max_debounce; - bool div_debounce_support; - unsigned int cur_div_reg; - u64 div; - - clk_enable(bank->clk); - - if (!IS_ERR(bank->db_clk)) { - div_debounce_support = true; - freq = clk_get_rate(bank->db_clk); - max_debounce = (GENMASK(23, 0) + 1) * 2 * 1000000 / freq; - if (debounce > max_debounce) { - clk_disable(bank->clk); - return -EINVAL; - } - - div = debounce * freq; - div_reg = DIV_ROUND_CLOSEST_ULL(div, 2 * USEC_PER_SEC) - 1; - } else { - div_debounce_support = false; - } - - raw_spin_lock_irqsave(&bank->slock, flags); - - /* Only the v1 needs to configure div_en and div_con for dbclk */ - if (debounce) { - if (div_debounce_support) { - /* Configure the max debounce from consumers */ - cur_div_reg = readl(bank->reg_base + reg->dbclk_div_con); - if (cur_div_reg < div_reg) - writel(div_reg, bank->reg_base + reg->dbclk_div_con); - rockchip_gpio_writel_bit(bank, offset, 1, - reg->dbclk_div_en); - } - - rockchip_gpio_writel_bit(bank, offset, 1, reg->debounce); - } else { - if (div_debounce_support) - rockchip_gpio_writel_bit(bank, offset, 0, - reg->dbclk_div_en); - - rockchip_gpio_writel_bit(bank, offset, 0, reg->debounce); - } - - raw_spin_unlock_irqrestore(&bank->slock, flags); - - /* Enable or disable dbclk at last */ - if (div_debounce_support) { - if (debounce) - clk_enable(bank->db_clk); - else - clk_disable(bank->db_clk); - } - - clk_disable(bank->clk); - - return 0; -} - -/* - * gpiolib set_config callback function. The setting of the pin - * mux function as 'gpio output' will be handled by the pinctrl subsystem - * interface. - */ -static int rockchip_gpio_set_config(struct gpio_chip *gc, unsigned int offset, - unsigned long config) -{ - enum pin_config_param param = pinconf_to_config_param(config); - unsigned int debounce = pinconf_to_config_argument(config); - - switch (param) { - case PIN_CONFIG_INPUT_DEBOUNCE: - rockchip_gpio_set_debounce(gc, offset, debounce); - /* - * Rockchip's gpio could only support up to one period - * of the debounce clock(pclk), which is far away from - * satisftying the requirement, as pclk is usually near - * 100MHz shared by all peripherals. So the fact is it - * has crippled debounce capability could only be useful - * to prevent any spurious glitches from waking up the system - * if the gpio is conguired as wakeup interrupt source. Let's - * still return -ENOTSUPP as before, to make sure the caller - * of gpiod_set_debounce won't change its behaviour. - */ - return -ENOTSUPP; - default: - return -ENOTSUPP; - } -} - -/* - * gpiolib gpio_to_irq callback function. Creates a mapping between a GPIO pin - * and a virtual IRQ, if not already present. - */ -static int rockchip_gpio_to_irq(struct gpio_chip *gc, unsigned offset) -{ - struct rockchip_pin_bank *bank = gpiochip_get_data(gc); - unsigned int virq; - - if (!bank->domain) - return -ENXIO; - - clk_enable(bank->clk); - virq = irq_create_mapping(bank->domain, offset); - clk_disable(bank->clk); - - return (virq) ? : -ENXIO; -} - -static const struct gpio_chip rockchip_gpiolib_chip = { - .request = gpiochip_generic_request, - .free = gpiochip_generic_free, - .set = rockchip_gpio_set, - .get = rockchip_gpio_get, - .get_direction = rockchip_gpio_get_direction, - .direction_input = rockchip_gpio_direction_input, - .direction_output = rockchip_gpio_direction_output, - .set_config = rockchip_gpio_set_config, - .to_irq = rockchip_gpio_to_irq, - .owner = THIS_MODULE, -}; - -/* - * Interrupt handling - */ - -static void rockchip_irq_demux(struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - struct rockchip_pin_bank *bank = irq_desc_get_handler_data(desc); - const struct rockchip_gpio_regs *reg = bank->gpio_regs; - u32 pend; - - dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name); - - chained_irq_enter(chip, desc); - - pend = readl_relaxed(bank->reg_base + reg->int_status); - - while (pend) { - unsigned int irq, virq; - - irq = __ffs(pend); - pend &= ~BIT(irq); - virq = irq_find_mapping(bank->domain, irq); - - if (!virq) { - dev_err(bank->drvdata->dev, "unmapped irq %d\n", irq); - continue; - } - - dev_dbg(bank->drvdata->dev, "handling irq %d\n", irq); - - /* - * Triggering IRQ on both rising and falling edge - * needs manual intervention. - */ - if (bank->toggle_edge_mode & BIT(irq)) { - u32 data, data_old, polarity; - unsigned long flags; - - data = readl_relaxed(bank->reg_base + reg->ext_port); - do { - raw_spin_lock_irqsave(&bank->slock, flags); - - polarity = readl_relaxed(bank->reg_base + - reg->int_polarity); - if (data & BIT(irq)) - polarity &= ~BIT(irq); - else - polarity |= BIT(irq); - writel(polarity, bank->reg_base + - reg->int_polarity); - - raw_spin_unlock_irqrestore(&bank->slock, flags); - - data_old = data; - data = readl_relaxed(bank->reg_base + - reg->ext_port); - } while ((data & BIT(irq)) != (data_old & BIT(irq))); - } - - generic_handle_irq(virq); - } - - chained_irq_exit(chip, desc); -} - -static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) -{ - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct rockchip_pin_bank *bank = gc->private; - u32 mask = BIT(d->hwirq); - u32 polarity; - u32 level; - u32 data; - unsigned long flags; - int ret; - - /* make sure the pin is configured as gpio input */ - ret = rockchip_set_mux(bank, d->hwirq, RK_FUNC_GPIO); - if (ret < 0) - return ret; - - clk_enable(bank->clk); - raw_spin_lock_irqsave(&bank->slock, flags); - - rockchip_gpio_writel_bit(bank, d->hwirq, 0, - bank->gpio_regs->port_ddr); - - raw_spin_unlock_irqrestore(&bank->slock, flags); - - if (type & IRQ_TYPE_EDGE_BOTH) - irq_set_handler_locked(d, handle_edge_irq); - else - irq_set_handler_locked(d, handle_level_irq); - - raw_spin_lock_irqsave(&bank->slock, flags); - irq_gc_lock(gc); - - level = rockchip_gpio_readl(bank, bank->gpio_regs->int_type); - polarity = rockchip_gpio_readl(bank, bank->gpio_regs->int_polarity); - - switch (type) { - case IRQ_TYPE_EDGE_BOTH: - if (bank->gpio_type == GPIO_TYPE_V2) { - bank->toggle_edge_mode &= ~mask; - rockchip_gpio_writel_bit(bank, d->hwirq, 1, - bank->gpio_regs->int_bothedge); - irq_gc_unlock(gc); - raw_spin_unlock_irqrestore(&bank->slock, flags); - clk_disable(bank->clk); - - return 0; - } else { - bank->toggle_edge_mode |= mask; - level |= mask; - - /* - * Determine gpio state. If 1 next interrupt should be falling - * otherwise rising. - */ - data = readl(bank->reg_base + bank->gpio_regs->ext_port); - if (data & mask) - polarity &= ~mask; - else - polarity |= mask; - - break; - } - case IRQ_TYPE_EDGE_RISING: - bank->toggle_edge_mode &= ~mask; - level |= mask; - polarity |= mask; - break; - case IRQ_TYPE_EDGE_FALLING: - bank->toggle_edge_mode &= ~mask; - level |= mask; - polarity &= ~mask; - break; - case IRQ_TYPE_LEVEL_HIGH: - bank->toggle_edge_mode &= ~mask; - level &= ~mask; - polarity |= mask; - break; - case IRQ_TYPE_LEVEL_LOW: - bank->toggle_edge_mode &= ~mask; - level &= ~mask; - polarity &= ~mask; - break; - default: - irq_gc_unlock(gc); - raw_spin_unlock_irqrestore(&bank->slock, flags); - clk_disable(bank->clk); - return -EINVAL; - } - - rockchip_gpio_writel(bank, level, bank->gpio_regs->int_type); - rockchip_gpio_writel(bank, polarity, bank->gpio_regs->int_polarity); - - irq_gc_unlock(gc); - raw_spin_unlock_irqrestore(&bank->slock, flags); - clk_disable(bank->clk); - - return 0; -} - -static void rockchip_irq_suspend(struct irq_data *d) -{ - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct rockchip_pin_bank *bank = gc->private; - - clk_enable(bank->clk); - bank->saved_masks = irq_reg_readl(gc, bank->gpio_regs->int_mask); - irq_reg_writel(gc, ~gc->wake_active, bank->gpio_regs->int_mask); - clk_disable(bank->clk); -} - -static void rockchip_irq_resume(struct irq_data *d) -{ - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct rockchip_pin_bank *bank = gc->private; - - clk_enable(bank->clk); - irq_reg_writel(gc, bank->saved_masks, bank->gpio_regs->int_mask); - clk_disable(bank->clk); -} - -static void rockchip_irq_enable(struct irq_data *d) -{ - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct rockchip_pin_bank *bank = gc->private; - - clk_enable(bank->clk); - irq_gc_mask_clr_bit(d); -} - -static void rockchip_irq_disable(struct irq_data *d) -{ - struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - struct rockchip_pin_bank *bank = gc->private; - - irq_gc_mask_set_bit(d); - clk_disable(bank->clk); -} - -static int rockchip_interrupts_register(struct platform_device *pdev, - struct rockchip_pinctrl *info) -{ - struct rockchip_pin_ctrl *ctrl = info->ctrl; - struct rockchip_pin_bank *bank = ctrl->pin_banks; - unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; - struct irq_chip_generic *gc; - int ret; - int i; - - for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { - if (!bank->valid) { - dev_warn(&pdev->dev, "bank %s is not valid\n", - bank->name); - continue; - } - - ret = clk_enable(bank->clk); - if (ret) { - dev_err(&pdev->dev, "failed to enable clock for bank %s\n", - bank->name); - continue; - } - - bank->domain = irq_domain_add_linear(bank->of_node, 32, - &irq_generic_chip_ops, NULL); - if (!bank->domain) { - dev_warn(&pdev->dev, "could not initialize irq domain for bank %s\n", - bank->name); - clk_disable(bank->clk); - continue; - } - - ret = irq_alloc_domain_generic_chips(bank->domain, 32, 1, - "rockchip_gpio_irq", handle_level_irq, - clr, 0, 0); - if (ret) { - dev_err(&pdev->dev, "could not alloc generic chips for bank %s\n", - bank->name); - irq_domain_remove(bank->domain); - clk_disable(bank->clk); - continue; - } - - gc = irq_get_domain_generic_chip(bank->domain, 0); - if (bank->gpio_type == GPIO_TYPE_V2) { - gc->reg_writel = gpio_writel_v2; - gc->reg_readl = gpio_readl_v2; - } - gc->reg_base = bank->reg_base; - gc->private = bank; - gc->chip_types[0].regs.mask = bank->gpio_regs->int_mask; - gc->chip_types[0].regs.ack = bank->gpio_regs->port_eoi; - gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; - gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit; - gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit; - gc->chip_types[0].chip.irq_enable = rockchip_irq_enable; - gc->chip_types[0].chip.irq_disable = rockchip_irq_disable; - gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake; - gc->chip_types[0].chip.irq_suspend = rockchip_irq_suspend; - gc->chip_types[0].chip.irq_resume = rockchip_irq_resume; - gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type; - gc->wake_enabled = IRQ_MSK(bank->nr_pins); - - /* - * Linux assumes that all interrupts start out disabled/masked. - * Our driver only uses the concept of masked and always keeps - * things enabled, so for us that's all masked and all enabled. - */ - rockchip_gpio_writel(bank, 0xffffffff, bank->gpio_regs->int_mask); - rockchip_gpio_writel(bank, 0xffffffff, bank->gpio_regs->int_en); - gc->mask_cache = 0xffffffff; - - irq_set_chained_handler_and_data(bank->irq, - rockchip_irq_demux, bank); - clk_disable(bank->clk); - } - - return 0; -} - -static int rockchip_gpiolib_register(struct platform_device *pdev, - struct rockchip_pinctrl *info) -{ - struct rockchip_pin_ctrl *ctrl = info->ctrl; - struct rockchip_pin_bank *bank = ctrl->pin_banks; - struct gpio_chip *gc; - int ret; - int i; - - for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { - if (!bank->valid) { - dev_warn(&pdev->dev, "bank %s is not valid\n", - bank->name); - continue; - } - - bank->gpio_chip = rockchip_gpiolib_chip; - - gc = &bank->gpio_chip; - gc->base = bank->pin_base; - gc->ngpio = bank->nr_pins; - gc->parent = &pdev->dev; - gc->of_node = bank->of_node; - gc->label = bank->name; - - ret = gpiochip_add_data(gc, bank); - if (ret) { - dev_err(&pdev->dev, "failed to register gpio_chip %s, error code: %d\n", - gc->label, ret); - goto fail; - } - } - - rockchip_interrupts_register(pdev, info); - - return 0; - -fail: - for (--i, --bank; i >= 0; --i, --bank) { - if (!bank->valid) - continue; - gpiochip_remove(&bank->gpio_chip); - } - return ret; -} - -static int rockchip_gpiolib_unregister(struct platform_device *pdev, - struct rockchip_pinctrl *info) -{ - struct rockchip_pin_ctrl *ctrl = info->ctrl; - struct rockchip_pin_bank *bank = ctrl->pin_banks; - int i; - - for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { - if (!bank->valid) - continue; - gpiochip_remove(&bank->gpio_chip); - } - - return 0; -} - -static int rockchip_get_bank_data(struct rockchip_pin_bank *bank, - struct rockchip_pinctrl *info) -{ - struct resource res; - void __iomem *base; - u32 ver_reg; - - if (of_address_to_resource(bank->of_node, 0, &res)) { - dev_err(info->dev, "cannot find IO resource for bank\n"); - return -ENOENT; - } - - bank->reg_base = devm_ioremap_resource(info->dev, &res); - if (IS_ERR(bank->reg_base)) - return PTR_ERR(bank->reg_base); - - /* - * special case, where parts of the pull setting-registers are - * part of the PMU register space - */ - if (of_device_is_compatible(bank->of_node, - "rockchip,rk3188-gpio-bank0")) { - struct device_node *node; - - node = of_parse_phandle(bank->of_node->parent, - "rockchip,pmu", 0); - if (!node) { - if (of_address_to_resource(bank->of_node, 1, &res)) { - dev_err(info->dev, "cannot find IO resource for bank\n"); - return -ENOENT; - } - - base = devm_ioremap_resource(info->dev, &res); - if (IS_ERR(base)) - return PTR_ERR(base); - rockchip_regmap_config.max_register = - resource_size(&res) - 4; - rockchip_regmap_config.name = - "rockchip,rk3188-gpio-bank0-pull"; - bank->regmap_pull = devm_regmap_init_mmio(info->dev, - base, - &rockchip_regmap_config); - } - of_node_put(node); - } - - bank->irq = irq_of_parse_and_map(bank->of_node, 0); - - bank->clk = of_clk_get(bank->of_node, 0); - if (IS_ERR(bank->clk)) - return PTR_ERR(bank->clk); - - clk_prepare_enable(bank->clk); - - /* If not gpio v2, that is default to v1. */ - ver_reg = gpio_regs_v2.version_id; - if (readl(bank->reg_base + ver_reg) == GPIO_TYPE_V2) { - bank->gpio_regs = &gpio_regs_v2; - bank->gpio_type = GPIO_TYPE_V2; - bank->db_clk = of_clk_get(bank->of_node, 1); - if (IS_ERR(bank->db_clk)) { - clk_disable_unprepare(bank->clk); - dev_err(info->dev, "cannot find debounce clk\n"); - - return PTR_ERR(bank->db_clk); - } - - clk_prepare(bank->db_clk); - } else { - bank->gpio_regs = &gpio_regs_v1; - bank->gpio_type = GPIO_TYPE_V1; - } - - clk_disable(bank->clk); - return 0; } @@ -4084,7 +3069,6 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data( { const struct of_device_id *match; struct device_node *node = pdev->dev.of_node; - struct device_node *np; struct rockchip_pin_ctrl *ctrl; struct rockchip_pin_bank *bank; int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs, i, j; @@ -4092,23 +3076,6 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data( match = of_match_node(rockchip_pinctrl_dt_match, node); ctrl = (struct rockchip_pin_ctrl *)match->data; - for_each_child_of_node(node, np) { - if (!of_find_property(np, "gpio-controller", NULL)) - continue; - - bank = ctrl->pin_banks; - for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { - if (!strcmp(bank->name, np->name)) { - bank->of_node = np; - - if (!rockchip_get_bank_data(bank, d)) - bank->valid = true; - - break; - } - } - } - grf_offs = ctrl->grf_mux_offset; pmu_offs = ctrl->pmu_mux_offset; drv_pmu_offs = ctrl->pmu_drv_offset; @@ -4377,17 +3344,18 @@ static int rockchip_pinctrl_probe(struct platform_device *pdev) return ret; } - ret = rockchip_gpiolib_register(pdev, info); + ret = rockchip_pinctrl_register(pdev, info); if (ret) return ret; - ret = rockchip_pinctrl_register(pdev, info); + platform_set_drvdata(pdev, info); + + ret = of_platform_populate(np, rockchip_bank_match, NULL, NULL); if (ret) { - rockchip_gpiolib_unregister(pdev, info); + dev_err(&pdev->dev, "failed to register gpio device\n"); return ret; } - - platform_set_drvdata(pdev, info); + dev_info(dev, "probed %s\n", dev_name(dev)); return 0; } diff --git a/drivers/pinctrl/pinctrl-rockchip.h b/drivers/pinctrl/pinctrl-rockchip.h index b085aa290fcf..cd1662db5c97 100644 --- a/drivers/pinctrl/pinctrl-rockchip.h +++ b/drivers/pinctrl/pinctrl-rockchip.h @@ -87,6 +87,12 @@ enum rockchip_pin_route_type { ROUTE_TYPE_INVALID = -1, }; +enum rockchip_mux_route_location { + ROCKCHIP_ROUTE_SAME = 0, + ROCKCHIP_ROUTE_PMU, + ROCKCHIP_ROUTE_GRF, +}; + /** * @drv_type: drive strength variant using rockchip_perpin_drv_type * @offset: if initialized to -1 it will be autocalculated, by specifying @@ -173,7 +179,7 @@ struct rockchip_mux_recalced_data { * @bank_num: bank number. * @pin: index at register or used to calc index. * @func: the min pin. - * @route_type: the register type. + * @route_location: the mux route location (same, pmu, grf). * @route_offset: the max pin. * @route_val: the register offset. */ @@ -181,7 +187,7 @@ struct rockchip_mux_route_data { u8 bank_num; u8 pin; u8 func; - enum rockchip_pin_route_type route_type : 8; + enum rockchip_mux_route_location route_location; u32 route_offset; u32 route_val; };