Hi David, Am Montag, 1. Februar 2016, 10:58:21 schrieb David Wu: > The pinctrl of rk3399 is much different from other's, > especially the 3bits of drive strength. > > Signed-off-by: David Wu <david.wu@xxxxxxxxxxxxxx> > Reviewed-by: Heiko Stuebner <heiko@xxxxxxxxx> looks nice now :-) Thanks Heiko > --- > Changes in v5: > - merge the binding-doc-addition in one patch (Linus Heiko) > - fix the comment of bit15 drive setting (Heiko) > > Change in v4: None > > Change in v3: > - use switch-case to distinguish special 3bits width per pin (Heiko) > > Change in v2: > - need spin_unlock_irqrestore for set drive default case > > .../bindings/pinctrl/rockchip,pinctrl.txt | 1 + > drivers/pinctrl/pinctrl-rockchip.c | 369 > ++++++++++++++++++++- 2 files changed, 356 insertions(+), 14 deletions(-) > > diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt > b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt index > 391ef4b..3bb9456 100644 > --- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt > +++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt > @@ -22,6 +22,7 @@ Required properties for iomux controller: > - compatible: one of "rockchip,rk2928-pinctrl", > "rockchip,rk3066a-pinctrl" "rockchip,rk3066b-pinctrl", > "rockchip,rk3188-pinctrl" > "rockchip,rk3288-pinctrl", "rockchip,rk3368-pinctrl" > + "rockchip,rk3399-pinctrl" > - rockchip,grf: phandle referencing a syscon providing the > "general register files" > > diff --git a/drivers/pinctrl/pinctrl-rockchip.c > b/drivers/pinctrl/pinctrl-rockchip.c index a065112..d485f22 100644 > --- a/drivers/pinctrl/pinctrl-rockchip.c > +++ b/drivers/pinctrl/pinctrl-rockchip.c > @@ -64,6 +64,7 @@ enum rockchip_pinctrl_type { > RK3188, > RK3288, > RK3368, > + RK3399, > }; > > /** > @@ -86,6 +87,31 @@ struct rockchip_iomux { > }; > > /** > + * 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 > +}; > + > +/** > + * @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; > +}; > + > +/** > * @reg_base: register base of the gpio bank > * @reg_pull: optional separate register for additional pull settings > * @clk: clock of the gpio bank > @@ -96,6 +122,7 @@ struct rockchip_iomux { > * @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 > * @valid: are all necessary informations present > * @of_node: dt node of this bank > * @drvdata: common pinctrl basedata > @@ -115,6 +142,7 @@ struct rockchip_pin_bank { > char *name; > u8 bank_num; > struct rockchip_iomux iomux[4]; > + struct rockchip_drv drv[4]; > bool valid; > struct device_node *of_node; > struct rockchip_pinctrl *drvdata; > @@ -151,6 +179,47 @@ struct rockchip_pin_bank { > }, \ > } > > +#define PIN_BANK_DRV_FLAGS(id, pins, label, type0, type1, type2, type3) \ > + { \ > + .bank_num = id, \ > + .nr_pins = pins, \ > + .name = label, \ > + .iomux = { \ > + { .offset = -1 }, \ > + { .offset = -1 }, \ > + { .offset = -1 }, \ > + { .offset = -1 }, \ > + }, \ > + .drv = { \ > + { .drv_type = type0, .offset = -1 }, \ > + { .drv_type = type1, .offset = -1 }, \ > + { .drv_type = type2, .offset = -1 }, \ > + { .drv_type = type3, .offset = -1 }, \ > + }, \ > + } > + > +#define PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(id, pins, label, iom0, iom1, \ > + iom2, iom3, drv0, drv1, drv2, \ > + drv3, offset0, offset1, \ > + offset2, offset3) \ > + { \ > + .bank_num = id, \ > + .nr_pins = pins, \ > + .name = label, \ > + .iomux = { \ > + { .type = iom0, .offset = -1 }, \ > + { .type = iom1, .offset = -1 }, \ > + { .type = iom2, .offset = -1 }, \ > + { .type = iom3, .offset = -1 }, \ > + }, \ > + .drv = { \ > + { .drv_type = drv0, .offset = offset0 }, \ > + { .drv_type = drv1, .offset = offset1 }, \ > + { .drv_type = drv2, .offset = offset2 }, \ > + { .drv_type = drv3, .offset = offset3 }, \ > + }, \ > + } > + > /** > */ > struct rockchip_pin_ctrl { > @@ -161,6 +230,9 @@ struct rockchip_pin_ctrl { > enum rockchip_pinctrl_type type; > int grf_mux_offset; > int pmu_mux_offset; > + int grf_drv_offset; > + int pmu_drv_offset; > + > void (*pull_calc_reg)(struct rockchip_pin_bank *bank, > int pin_num, struct regmap **regmap, > int *reg, u8 *bit); > @@ -676,7 +748,68 @@ static void rk3368_calc_drv_reg_and_bit(struct > rockchip_pin_bank *bank, } > } > > -static int rockchip_perpin_drv_list[] = { 2, 4, 8, 12 }; > +#define RK3399_PULL_GRF_OFFSET 0xe040 > +#define RK3399_PULL_PMU_OFFSET 0x40 > +#define RK3399_DRV_3BITS_PER_PIN 3 > + > +static void rk3399_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank, > + int pin_num, struct regmap **regmap, > + int *reg, u8 *bit) > +{ > + struct rockchip_pinctrl *info = bank->drvdata; > + > + /* The bank0:16 and bank1:32 pins are located in PMU */ > + if ((bank->bank_num == 0) || (bank->bank_num == 1)) { > + *regmap = info->regmap_pmu; > + *reg = RK3399_PULL_PMU_OFFSET; > + > + *reg += bank->bank_num * RK3188_PULL_BANK_STRIDE; > + > + *reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4); > + *bit = pin_num % RK3188_PULL_PINS_PER_REG; > + *bit *= RK3188_PULL_BITS_PER_PIN; > + } else { > + *regmap = info->regmap_base; > + *reg = RK3399_PULL_GRF_OFFSET; > + > + /* correct the offset, as we're starting with the 3rd bank */ > + *reg -= 0x20; > + *reg += bank->bank_num * RK3188_PULL_BANK_STRIDE; > + *reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4); > + > + *bit = (pin_num % RK3188_PULL_PINS_PER_REG); > + *bit *= RK3188_PULL_BITS_PER_PIN; > + } > +} > + > +static void rk3399_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank, > + int pin_num, struct regmap **regmap, > + int *reg, u8 *bit) > +{ > + struct rockchip_pinctrl *info = bank->drvdata; > + int drv_num = (pin_num / 8); > + > + /* The bank0:16 and bank1:32 pins are located in PMU */ > + if ((bank->bank_num == 0) || (bank->bank_num == 1)) > + *regmap = info->regmap_pmu; > + else > + *regmap = info->regmap_base; > + > + *reg = bank->drv[drv_num].offset; > + if ((bank->drv[drv_num].drv_type == DRV_TYPE_IO_1V8_3V0_AUTO) || > + (bank->drv[drv_num].drv_type == DRV_TYPE_IO_3V3_ONLY)) > + *bit = (pin_num % 8) * 3; > + else > + *bit = (pin_num % 8) * 2; > +} > + > +static int rockchip_perpin_drv_list[DRV_TYPE_MAX][8] = { > + { 2, 4, 8, 12, -1, -1, -1, -1 }, > + { 3, 6, 9, 12, -1, -1, -1, -1 }, > + { 5, 10, 15, 20, -1, -1, -1, -1 }, > + { 4, 6, 8, 10, 12, 14, 16, 18 }, > + { 4, 7, 10, 13, 16, 19, 22, 26 } > +}; > > static int rockchip_get_drive_perpin(struct rockchip_pin_bank *bank, > int pin_num) > @@ -685,19 +818,74 @@ static int rockchip_get_drive_perpin(struct > rockchip_pin_bank *bank, struct rockchip_pin_ctrl *ctrl = info->ctrl; > struct regmap *regmap; > int reg, ret; > - u32 data; > + u32 data, temp, rmask_bits; > u8 bit; > + int drv_type = bank->drv[pin_num / 8].drv_type; > > ctrl->drv_calc_reg(bank, pin_num, ®map, ®, &bit); > > + switch (drv_type) { > + case DRV_TYPE_IO_1V8_3V0_AUTO: > + case DRV_TYPE_IO_3V3_ONLY: > + rmask_bits = RK3399_DRV_3BITS_PER_PIN; > + switch (bit) { > + case 0 ... 12: > + /* regular case, nothing to do */ > + break; > + case 15: > + /* > + * drive-strength offset is special, as it is > + * spread over 2 registers > + */ > + ret = regmap_read(regmap, reg, &data); > + if (ret) > + return ret; > + > + ret = regmap_read(regmap, reg + 0x4, &temp); > + if (ret) > + return ret; > + > + /* > + * the bit data[15] contains bit 0 of the value > + * while temp[1:0] contains bits 2 and 1 > + */ > + data >>= 15; > + temp &= 0x3; > + temp <<= 1; > + data |= temp; > + > + return rockchip_perpin_drv_list[drv_type][data]; > + case 18 ... 21: > + /* setting fully enclosed in the second register */ > + reg += 4; > + bit -= 16; > + break; > + default: > + dev_err(info->dev, "unsupported bit: %d for pinctrl drive type: %d\n", > + bit, drv_type); > + return -EINVAL; > + } > + > + break; > + case DRV_TYPE_IO_DEFAULT: > + case DRV_TYPE_IO_1V8_OR_3V0: > + case DRV_TYPE_IO_1V8_ONLY: > + rmask_bits = RK3288_DRV_BITS_PER_PIN; > + break; > + default: > + dev_err(info->dev, "unsupported pinctrl drive type: %d\n", > + drv_type); > + return -EINVAL; > + } > + > ret = regmap_read(regmap, reg, &data); > if (ret) > return ret; > > data >>= bit; > - data &= (1 << RK3288_DRV_BITS_PER_PIN) - 1; > + data &= (1 << rmask_bits) - 1; > > - return rockchip_perpin_drv_list[data]; > + return rockchip_perpin_drv_list[drv_type][data]; > } > > static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank, > @@ -708,16 +896,23 @@ static int rockchip_set_drive_perpin(struct > rockchip_pin_bank *bank, struct regmap *regmap; > unsigned long flags; > int reg, ret, i; > - u32 data, rmask; > + u32 data, rmask, rmask_bits, temp; > u8 bit; > + int drv_type = bank->drv[pin_num / 8].drv_type; > + > + dev_dbg(info->dev, "setting drive of GPIO%d-%d to %d\n", > + bank->bank_num, pin_num, strength); > > ctrl->drv_calc_reg(bank, pin_num, ®map, ®, &bit); > > ret = -EINVAL; > - for (i = 0; i < ARRAY_SIZE(rockchip_perpin_drv_list); i++) { > - if (rockchip_perpin_drv_list[i] == strength) { > + for (i = 0; i < ARRAY_SIZE(rockchip_perpin_drv_list[drv_type]); i++) { > + if (rockchip_perpin_drv_list[drv_type][i] == strength) { > ret = i; > break; > + } else if (rockchip_perpin_drv_list[drv_type][i] < 0) { > + ret = rockchip_perpin_drv_list[drv_type][i]; > + break; > } > } > > @@ -729,8 +924,64 @@ static int rockchip_set_drive_perpin(struct > rockchip_pin_bank *bank, > > spin_lock_irqsave(&bank->slock, flags); > > + switch (drv_type) { > + case DRV_TYPE_IO_1V8_3V0_AUTO: > + case DRV_TYPE_IO_3V3_ONLY: > + rmask_bits = RK3399_DRV_3BITS_PER_PIN; > + switch (bit) { > + case 0 ... 12: > + /* regular case, nothing to do */ > + break; > + case 15: > + /* > + * drive-strength offset is special, as it is spread > + * over 2 registers, the bit data[15] contains bit 0 > + * of the value while temp[1:0] contains bits 2 and 1 > + */ > + data = (ret & 0x1) << 15; > + temp = (ret >> 0x1) & 0x3; > + > + rmask = BIT(15) | BIT(31); > + data |= BIT(31); > + ret = regmap_update_bits(regmap, reg, rmask, data); > + if (ret) { > + spin_unlock_irqrestore(&bank->slock, flags); > + return ret; > + } > + > + rmask = 0x3 | (0x3 << 16); > + temp |= (0x3 << 16); > + reg += 0x4; > + ret = regmap_update_bits(regmap, reg, rmask, temp); > + > + spin_unlock_irqrestore(&bank->slock, flags); > + return ret; > + case 18 ... 21: > + /* setting fully enclosed in the second register */ > + reg += 4; > + bit -= 16; > + break; > + default: > + spin_unlock_irqrestore(&bank->slock, flags); > + dev_err(info->dev, "unsupported bit: %d for pinctrl drive type: %d\n", > + bit, drv_type); > + return -EINVAL; > + } > + break; > + case DRV_TYPE_IO_DEFAULT: > + case DRV_TYPE_IO_1V8_OR_3V0: > + case DRV_TYPE_IO_1V8_ONLY: > + rmask_bits = RK3288_DRV_BITS_PER_PIN; > + break; > + default: > + spin_unlock_irqrestore(&bank->slock, flags); > + dev_err(info->dev, "unsupported pinctrl drive type: %d\n", > + drv_type); > + return -EINVAL; > + } > + > /* enable the write to the equivalent lower bits */ > - data = ((1 << RK3288_DRV_BITS_PER_PIN) - 1) << (bit + 16); > + data = ((1 << rmask_bits) - 1) << (bit + 16); > rmask = data | (data >> 16); > data |= (ret << bit); > > @@ -767,6 +1018,7 @@ static int rockchip_get_pull(struct rockchip_pin_bank > *bank, int pin_num) case RK3188: > case RK3288: > case RK3368: > + case RK3399: > data >>= bit; > data &= (1 << RK3188_PULL_BITS_PER_PIN) - 1; > > @@ -823,6 +1075,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank > *bank, case RK3188: > case RK3288: > case RK3368: > + case RK3399: > spin_lock_irqsave(&bank->slock, flags); > > /* enable the write to the equivalent lower bits */ > @@ -1003,6 +1256,7 @@ static bool rockchip_pinconf_pull_valid(struct > rockchip_pin_ctrl *ctrl, case RK3188: > case RK3288: > case RK3368: > + case RK3399: > return (pull != PIN_CONFIG_BIAS_PULL_PIN_DEFAULT); > } > > @@ -1860,7 +2114,7 @@ static struct rockchip_pin_ctrl > *rockchip_pinctrl_get_soc_data( struct device_node *np; > struct rockchip_pin_ctrl *ctrl; > struct rockchip_pin_bank *bank; > - int grf_offs, pmu_offs, i, j; > + int grf_offs, pmu_offs, drv_grf_offs, drv_pmu_offs, i, j; > > match = of_match_node(rockchip_pinctrl_dt_match, node); > ctrl = (struct rockchip_pin_ctrl *)match->data; > @@ -1884,6 +2138,8 @@ static struct rockchip_pin_ctrl > *rockchip_pinctrl_get_soc_data( > > grf_offs = ctrl->grf_mux_offset; > pmu_offs = ctrl->pmu_mux_offset; > + drv_pmu_offs = ctrl->pmu_drv_offset; > + drv_grf_offs = ctrl->grf_drv_offset; > bank = ctrl->pin_banks; > for (i = 0; i < ctrl->nr_banks; ++i, ++bank) { > int bank_pins = 0; > @@ -1893,27 +2149,39 @@ static struct rockchip_pin_ctrl > *rockchip_pinctrl_get_soc_data( bank->pin_base = ctrl->nr_pins; > ctrl->nr_pins += bank->nr_pins; > > - /* calculate iomux offsets */ > + /* calculate iomux and drv offsets */ > for (j = 0; j < 4; j++) { > struct rockchip_iomux *iom = &bank->iomux[j]; > + struct rockchip_drv *drv = &bank->drv[j]; > int inc; > > if (bank_pins >= bank->nr_pins) > break; > > - /* preset offset value, set new start value */ > + /* preset iomux offset value, set new start value */ > if (iom->offset >= 0) { > if (iom->type & IOMUX_SOURCE_PMU) > pmu_offs = iom->offset; > else > grf_offs = iom->offset; > - } else { /* set current offset */ > + } else { /* set current iomux offset */ > iom->offset = (iom->type & IOMUX_SOURCE_PMU) ? > pmu_offs : grf_offs; > } > > - dev_dbg(d->dev, "bank %d, iomux %d has offset 0x%x\n", > - i, j, iom->offset); > + /* preset drv offset value, set new start value */ > + if (drv->offset >= 0) { > + if (iom->type & IOMUX_SOURCE_PMU) > + drv_pmu_offs = drv->offset; > + else > + drv_grf_offs = drv->offset; > + } else { /* set current drv offset */ > + drv->offset = (iom->type & IOMUX_SOURCE_PMU) ? > + drv_pmu_offs : drv_grf_offs; > + } > + > + dev_dbg(d->dev, "bank %d, iomux %d has iom_offset 0x%x drv_offset > 0x%x\n", + i, j, iom->offset, drv->offset); > > /* > * Increase offset according to iomux width. > @@ -1925,6 +2193,21 @@ static struct rockchip_pin_ctrl > *rockchip_pinctrl_get_soc_data( else > grf_offs += inc; > > + /* > + * Increase offset according to drv width. > + * 3bit drive-strenth'es are spread over two registers. > + */ > + if ((drv->drv_type == DRV_TYPE_IO_1V8_3V0_AUTO) || > + (drv->drv_type == DRV_TYPE_IO_3V3_ONLY)) > + inc = 8; > + else > + inc = 4; > + > + if (iom->type & IOMUX_SOURCE_PMU) > + drv_pmu_offs += inc; > + else > + drv_grf_offs += inc; > + > bank_pins += 8; > } > } > @@ -2208,6 +2491,62 @@ static struct rockchip_pin_ctrl rk3368_pin_ctrl = { > .drv_calc_reg = rk3368_calc_drv_reg_and_bit, > }; > > +static struct rockchip_pin_bank rk3399_pin_banks[] = { > + PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(0, 32, "gpio0", IOMUX_SOURCE_PMU, > + IOMUX_SOURCE_PMU, > + IOMUX_SOURCE_PMU, > + IOMUX_SOURCE_PMU, > + DRV_TYPE_IO_1V8_ONLY, > + DRV_TYPE_IO_1V8_ONLY, > + DRV_TYPE_IO_DEFAULT, > + DRV_TYPE_IO_DEFAULT, > + 0x0, > + 0x8, > + -1, > + -1 > + ), > + PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(1, 32, "gpio1", IOMUX_SOURCE_PMU, > + IOMUX_SOURCE_PMU, > + IOMUX_SOURCE_PMU, > + IOMUX_SOURCE_PMU, > + DRV_TYPE_IO_1V8_OR_3V0, > + DRV_TYPE_IO_1V8_OR_3V0, > + DRV_TYPE_IO_1V8_OR_3V0, > + DRV_TYPE_IO_1V8_OR_3V0, > + 0x20, > + 0x28, > + 0x30, > + 0x38 > + ), > + PIN_BANK_DRV_FLAGS(2, 32, "gpio2", DRV_TYPE_IO_1V8_OR_3V0, > + DRV_TYPE_IO_1V8_OR_3V0, > + DRV_TYPE_IO_1V8_ONLY, > + DRV_TYPE_IO_1V8_ONLY > + ), > + PIN_BANK_DRV_FLAGS(3, 32, "gpio3", DRV_TYPE_IO_3V3_ONLY, > + DRV_TYPE_IO_3V3_ONLY, > + DRV_TYPE_IO_3V3_ONLY, > + DRV_TYPE_IO_1V8_OR_3V0 > + ), > + PIN_BANK_DRV_FLAGS(4, 32, "gpio4", DRV_TYPE_IO_1V8_OR_3V0, > + DRV_TYPE_IO_1V8_3V0_AUTO, > + DRV_TYPE_IO_1V8_OR_3V0, > + DRV_TYPE_IO_1V8_OR_3V0 > + ), > +}; > + > +static struct rockchip_pin_ctrl rk3399_pin_ctrl = { > + .pin_banks = rk3399_pin_banks, > + .nr_banks = ARRAY_SIZE(rk3399_pin_banks), > + .label = "RK3399-GPIO", > + .type = RK3399, > + .grf_mux_offset = 0xe000, > + .pmu_mux_offset = 0x0, > + .grf_drv_offset = 0xe100, > + .pmu_drv_offset = 0x80, > + .pull_calc_reg = rk3399_calc_pull_reg_and_bit, > + .drv_calc_reg = rk3399_calc_drv_reg_and_bit, > +}; > > static const struct of_device_id rockchip_pinctrl_dt_match[] = { > { .compatible = "rockchip,rk2928-pinctrl", > @@ -2224,6 +2563,8 @@ static const struct of_device_id > rockchip_pinctrl_dt_match[] = { .data = (void *)&rk3288_pin_ctrl }, > { .compatible = "rockchip,rk3368-pinctrl", > .data = (void *)&rk3368_pin_ctrl }, > + { .compatible = "rockchip,rk3399-pinctrl", > + .data = (void *)&rk3399_pin_ctrl }, > {}, > }; > MODULE_DEVICE_TABLE(of, rockchip_pinctrl_dt_match); -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html