diff options
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/Kconfig | 3 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpio/mcp230xx_gpio.c | 144 | ||||
-rw-r--r-- | drivers/gpio/msm_gpio.c | 20 | ||||
-rw-r--r-- | drivers/gpio/qcom_pmic_gpio.c | 273 | ||||
-rw-r--r-- | drivers/gpio/rk_gpio.c | 8 |
6 files changed, 372 insertions, 78 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2df3dc42d0f..a7fb1eb3f4c 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -256,6 +256,9 @@ config MCP230XX_GPIO - MCP23008 - MCP23017 - MCP23018 + - MCP23S08 + - MCP23S17 + - MCP23S18 config MSCC_SGPIO bool "Microsemi Serial GPIO driver" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index da3da5da2b3..90711702a69 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -23,7 +23,7 @@ obj-$(CONFIG_INTEL_ICH6_GPIO) += intel_ich6_gpio.o obj-$(CONFIG_INTEL_BROADWELL_GPIO) += intel_broadwell_gpio.o obj-$(CONFIG_IPROC_GPIO) += iproc_gpio.o obj-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o -obj-$(CONFIG_MCP230XX_GPIO) += mcp230xx_gpio.o +obj-$(CONFIG_$(SPL_TPL_)MCP230XX_GPIO) += mcp230xx_gpio.o obj-$(CONFIG_MXC_GPIO) += mxc_gpio.o obj-$(CONFIG_MXS_GPIO) += mxs_gpio.o obj-$(CONFIG_NPCM_GPIO) += npcm_gpio.o diff --git a/drivers/gpio/mcp230xx_gpio.c b/drivers/gpio/mcp230xx_gpio.c index 9f02fd42b35..df99fde5660 100644 --- a/drivers/gpio/mcp230xx_gpio.c +++ b/drivers/gpio/mcp230xx_gpio.c @@ -11,6 +11,7 @@ #include <errno.h> #include <dm.h> #include <i2c.h> +#include <spi.h> #include <asm/gpio.h> #include <dm/device_compat.h> #include <dt-bindings/gpio/gpio.h> @@ -20,6 +21,13 @@ enum mcp230xx_type { MCP23008, MCP23017, MCP23018, + MCP23S08, + MCP23S17, + MCP23S18, +}; + +struct mcp230xx_info { + uint dev_addr; }; #define MCP230XX_IODIR 0x00 @@ -29,29 +37,136 @@ enum mcp230xx_type { #define BANKSIZE 8 +#define MCP230XX_ADDR 0x20 + +static int mcp230xx_read_spi(struct udevice *dev, uint reg_addr) +{ + struct mcp230xx_info *info = dev_get_plat(dev); + uint dev_addr, value = 0; + int ret; + + /* set R/W bit for reading */ + dev_addr = (info->dev_addr << 1) | 1; + + ret = dm_spi_claim_bus(dev); + if (ret) + return ret; + + ret = dm_spi_xfer(dev, 0, NULL, NULL, SPI_XFER_BEGIN); + if (ret < 0) + goto fail; + udelay(1); + + ret = dm_spi_xfer(dev, 8, &dev_addr, NULL, 0); + if (ret < 0) + goto fail; + + ret = dm_spi_xfer(dev, 8, ®_addr, NULL, 0); + if (ret < 0) + goto fail; + + ret = dm_spi_xfer(dev, 8, NULL, &value, 0); + +fail: + dm_spi_xfer(dev, 0, NULL, NULL, SPI_XFER_END); + dm_spi_release_bus(dev); + if (ret < 0) + return ret; + return value; +} + static int mcp230xx_read(struct udevice *dev, uint reg, uint offset) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); int bank = offset / BANKSIZE; int mask = 1 << (offset % BANKSIZE); int shift = (uc_priv->gpio_count / BANKSIZE) - 1; - int ret; + int reg_addr = (reg << shift) | bank; + int ret = 0; + + switch (dev_get_driver_data(dev)) { + case MCP23008: + case MCP23017: + case MCP23018: + ret = dm_i2c_reg_read(dev, reg_addr); + break; + case MCP23S08: + case MCP23S17: + case MCP23S18: + ret = mcp230xx_read_spi(dev, reg_addr); + break; + default: + return -ENODEV; + } - ret = dm_i2c_reg_read(dev, (reg << shift) | bank); if (ret < 0) return ret; return !!(ret & mask); } +static int mcp230xx_clrset_spi(struct udevice *dev, uint reg_addr, uint clr, uint set) +{ + struct mcp230xx_info *info = dev_get_plat(dev); + int dev_addr, value; + int ret; + + /* R/W bit = 0 for writing */ + dev_addr = (info->dev_addr << 1); + + ret = mcp230xx_read_spi(dev, reg_addr); + if (ret < 0) + return ret; + + value = ret; + value &= ~clr; + value |= set; + + ret = dm_spi_claim_bus(dev); + if (ret) + return ret; + + ret = dm_spi_xfer(dev, 0, NULL, NULL, SPI_XFER_BEGIN); + if (ret < 0) + goto fail; + udelay(1); + + ret = dm_spi_xfer(dev, 8, &dev_addr, NULL, 0); + if (ret < 0) + goto fail; + + ret = dm_spi_xfer(dev, 8, ®_addr, NULL, 0); + if (ret < 0) + goto fail; + + ret = dm_spi_xfer(dev, 8, &value, NULL, 0); + +fail: + dm_spi_xfer(dev, 0, NULL, NULL, SPI_XFER_END); + dm_spi_release_bus(dev); + return ret; +} + static int mcp230xx_write(struct udevice *dev, uint reg, uint offset, bool val) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); int bank = offset / BANKSIZE; int mask = 1 << (offset % BANKSIZE); int shift = (uc_priv->gpio_count / BANKSIZE) - 1; + int reg_addr = (reg << shift) | bank; - return dm_i2c_reg_clrset(dev, (reg << shift) | bank, mask, val ? mask : 0); + switch (dev_get_driver_data(dev)) { + case MCP23008: + case MCP23017: + case MCP23018: + return dm_i2c_reg_clrset(dev, reg_addr, mask, val ? mask : 0); + case MCP23S08: + case MCP23S17: + case MCP23S18: + return mcp230xx_clrset_spi(dev, reg_addr, mask, val ? mask : 0); + default: + return -ENODEV; + } } static int mcp230xx_get_value(struct udevice *dev, uint offset) @@ -181,22 +296,37 @@ static const struct dm_gpio_ops mcp230xx_ops = { static int mcp230xx_probe(struct udevice *dev) { struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); - char name[32], label[8], *str; + struct mcp230xx_info *info = dev_get_plat(dev); + char name[32], label[32], *str; int addr, gpio_count, size; const u8 *tmp; switch (dev_get_driver_data(dev)) { case MCP23008: + case MCP23S08: gpio_count = 8; break; case MCP23017: case MCP23018: + case MCP23S17: + case MCP23S18: gpio_count = 16; break; default: return -ENODEV; } + switch (dev_get_driver_data(dev)) { + case MCP23S08: + case MCP23S17: + case MCP23S18: + info->dev_addr = dev_read_u32_default(dev, "addr", MCP230XX_ADDR); + break; + default: + info->dev_addr = 0; + break; + } + addr = dev_read_addr(dev); tmp = dev_read_prop(dev, "label", &size); if (tmp) { @@ -220,9 +350,14 @@ static int mcp230xx_probe(struct udevice *dev) } static const struct udevice_id mcp230xx_ids[] = { + /* i2c interface */ { .compatible = "microchip,mcp23008", .data = MCP23008, }, { .compatible = "microchip,mcp23017", .data = MCP23017, }, { .compatible = "microchip,mcp23018", .data = MCP23018, }, + /* spi interface */ + { .compatible = "microchip,mcp23s08", .data = MCP23S08, }, + { .compatible = "microchip,mcp23s17", .data = MCP23S17, }, + { .compatible = "microchip,mcp23s18", .data = MCP23S18, }, { } }; @@ -231,5 +366,6 @@ U_BOOT_DRIVER(mcp230xx) = { .id = UCLASS_GPIO, .ops = &mcp230xx_ops, .probe = mcp230xx_probe, + .plat_auto = sizeof(struct mcp230xx_info), .of_match = mcp230xx_ids, }; diff --git a/drivers/gpio/msm_gpio.c b/drivers/gpio/msm_gpio.c index 80cd28bb231..5e57b0cbde7 100644 --- a/drivers/gpio/msm_gpio.c +++ b/drivers/gpio/msm_gpio.c @@ -39,6 +39,10 @@ static int msm_gpio_direction_input(struct udevice *dev, unsigned int gpio) { struct msm_gpio_bank *priv = dev_get_priv(dev); + /* Always NOP for special pins, assume they're in the correct state */ + if (qcom_is_special_pin(priv->pin_data, gpio)) + return 0; + /* Disable OE bit */ clrsetbits_le32(priv->base + GPIO_CONFIG_REG(dev, gpio), GPIO_OE_MASK, GPIO_OE_DISABLE); @@ -50,6 +54,10 @@ static int msm_gpio_set_value(struct udevice *dev, unsigned int gpio, int value) { struct msm_gpio_bank *priv = dev_get_priv(dev); + /* Always NOP for special pins, assume they're in the correct state */ + if (qcom_is_special_pin(priv->pin_data, gpio)) + return 0; + value = !!value; /* set value */ writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio)); @@ -62,6 +70,10 @@ static int msm_gpio_direction_output(struct udevice *dev, unsigned int gpio, { struct msm_gpio_bank *priv = dev_get_priv(dev); + /* Always NOP for special pins, assume they're in the correct state */ + if (qcom_is_special_pin(priv->pin_data, gpio)) + return 0; + value = !!value; /* set value */ writel(value << GPIO_OUT, priv->base + GPIO_IN_OUT_REG(dev, gpio)); @@ -76,6 +88,10 @@ static int msm_gpio_get_value(struct udevice *dev, unsigned int gpio) { struct msm_gpio_bank *priv = dev_get_priv(dev); + /* Always NOP for special pins, assume they're in the correct state */ + if (qcom_is_special_pin(priv->pin_data, gpio)) + return 0; + return !!(readl(priv->base + GPIO_IN_OUT_REG(dev, gpio)) >> GPIO_IN); } @@ -83,6 +99,10 @@ static int msm_gpio_get_function(struct udevice *dev, unsigned int gpio) { struct msm_gpio_bank *priv = dev_get_priv(dev); + /* Always NOP for special pins, assume they're in the correct state */ + if (qcom_is_special_pin(priv->pin_data, gpio)) + return 0; + if (readl(priv->base + GPIO_CONFIG_REG(dev, gpio)) & GPIO_OE_ENABLE) return GPIOF_OUTPUT; diff --git a/drivers/gpio/qcom_pmic_gpio.c b/drivers/gpio/qcom_pmic_gpio.c index 6167c841167..14a8210522b 100644 --- a/drivers/gpio/qcom_pmic_gpio.c +++ b/drivers/gpio/qcom_pmic_gpio.c @@ -7,10 +7,14 @@ #include <common.h> #include <dm.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <dm/pinctrl.h> #include <log.h> #include <power/pmic.h> #include <spmi/spmi.h> #include <asm/io.h> +#include <stdlib.h> #include <asm/gpio.h> #include <linux/bitops.h> @@ -64,27 +68,34 @@ #define REG_EN_CTL 0x46 #define REG_EN_CTL_ENABLE (1 << 7) -struct qcom_gpio_bank { +/** + * pmic_gpio_match_data - platform specific configuration + * + * @PMIC_MATCH_READONLY: treat all GPIOs as readonly, don't attempt to configure them. + * This is a workaround for an unknown bug on some platforms where trying to write the + * GPIO configuration registers causes the board to hang. + */ +enum pmic_gpio_quirks { + QCOM_PMIC_QUIRK_READONLY = (1 << 0), +}; + +struct qcom_pmic_gpio_data { uint32_t pid; /* Peripheral ID on SPMI bus */ bool lv_mv_type; /* If subtype is GPIO_LV(0x10) or GPIO_MV(0x11) */ + u32 pin_count; + struct udevice *pmic; /* Reference to pmic device for read/write */ }; -static int qcom_gpio_set_direction(struct udevice *dev, unsigned offset, - bool input, int value) +/* dev can be the GPIO or pinctrl device */ +static int _qcom_gpio_set_direction(struct udevice *dev, u32 offset, bool input, int value) { - struct qcom_gpio_bank *priv = dev_get_priv(dev); - uint32_t gpio_base = priv->pid + REG_OFFSET(offset); - uint32_t reg_ctl_val; - int ret; - - /* Disable the GPIO */ - ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, - REG_EN_CTL_ENABLE, 0); - if (ret < 0) - return ret; + struct qcom_pmic_gpio_data *plat = dev_get_plat(dev); + u32 gpio_base = plat->pid + REG_OFFSET(offset); + u32 reg_ctl_val; + int ret = 0; /* Select the mode and output */ - if (priv->lv_mv_type) { + if (plat->lv_mv_type) { if (input) reg_ctl_val = REG_CTL_LV_MV_MODE_INPUT; else @@ -96,20 +107,43 @@ static int qcom_gpio_set_direction(struct udevice *dev, unsigned offset, reg_ctl_val = REG_CTL_MODE_INOUT | !!value; } - ret = pmic_reg_write(dev->parent, gpio_base + REG_CTL, reg_ctl_val); + ret = pmic_reg_write(plat->pmic, gpio_base + REG_CTL, reg_ctl_val); if (ret < 0) return ret; - if (priv->lv_mv_type && !input) { - ret = pmic_reg_write(dev->parent, + if (plat->lv_mv_type && !input) { + ret = pmic_reg_write(plat->pmic, gpio_base + REG_LV_MV_OUTPUT_CTL, !!value << REG_LV_MV_OUTPUT_CTL_SHIFT); if (ret < 0) return ret; } + return 0; +} + +static int qcom_gpio_set_direction(struct udevice *dev, unsigned int offset, + bool input, int value) +{ + struct qcom_pmic_gpio_data *plat = dev_get_plat(dev); + uint32_t gpio_base = plat->pid + REG_OFFSET(offset); + ulong quirks = dev_get_driver_data(dev); + int ret = 0; + + /* Some PMICs don't like their GPIOs being configured */ + if (quirks & QCOM_PMIC_QUIRK_READONLY) + return 0; + + /* Disable the GPIO */ + ret = pmic_clrsetbits(dev->parent, gpio_base + REG_EN_CTL, + REG_EN_CTL_ENABLE, 0); + if (ret < 0) + return ret; + + _qcom_gpio_set_direction(dev, offset, input, value); + /* Set the right pull (no pull) */ - ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_PULL_CTL, + ret = pmic_reg_write(plat->pmic, gpio_base + REG_DIG_PULL_CTL, REG_DIG_PULL_NO_PU); if (ret < 0) return ret; @@ -117,13 +151,13 @@ static int qcom_gpio_set_direction(struct udevice *dev, unsigned offset, /* Configure output pin drivers if needed */ if (!input) { /* Select the VIN - VIN0, pin is input so it doesn't matter */ - ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_VIN_CTL, + ret = pmic_reg_write(plat->pmic, gpio_base + REG_DIG_VIN_CTL, REG_DIG_VIN_VIN0); if (ret < 0) return ret; /* Set the right dig out control */ - ret = pmic_reg_write(dev->parent, gpio_base + REG_DIG_OUT_CTL, + ret = pmic_reg_write(plat->pmic, gpio_base + REG_DIG_OUT_CTL, REG_DIG_OUT_CTL_CMOS | REG_DIG_OUT_CTL_DRIVE_L); if (ret < 0) @@ -148,15 +182,15 @@ static int qcom_gpio_direction_output(struct udevice *dev, unsigned offset, static int qcom_gpio_get_function(struct udevice *dev, unsigned offset) { - struct qcom_gpio_bank *priv = dev_get_priv(dev); - uint32_t gpio_base = priv->pid + REG_OFFSET(offset); + struct qcom_pmic_gpio_data *plat = dev_get_plat(dev); + uint32_t gpio_base = plat->pid + REG_OFFSET(offset); int reg; - reg = pmic_reg_read(dev->parent, gpio_base + REG_CTL); + reg = pmic_reg_read(plat->pmic, gpio_base + REG_CTL); if (reg < 0) return reg; - if (priv->lv_mv_type) { + if (plat->lv_mv_type) { switch (reg & REG_CTL_LV_MV_MODE_MASK) { case REG_CTL_LV_MV_MODE_INPUT: return GPIOF_INPUT; @@ -181,11 +215,11 @@ static int qcom_gpio_get_function(struct udevice *dev, unsigned offset) static int qcom_gpio_get_value(struct udevice *dev, unsigned offset) { - struct qcom_gpio_bank *priv = dev_get_priv(dev); - uint32_t gpio_base = priv->pid + REG_OFFSET(offset); + struct qcom_pmic_gpio_data *plat = dev_get_plat(dev); + uint32_t gpio_base = plat->pid + REG_OFFSET(offset); int reg; - reg = pmic_reg_read(dev->parent, gpio_base + REG_STATUS); + reg = pmic_reg_read(plat->pmic, gpio_base + REG_STATUS); if (reg < 0) return reg; @@ -195,11 +229,11 @@ static int qcom_gpio_get_value(struct udevice *dev, unsigned offset) static int qcom_gpio_set_value(struct udevice *dev, unsigned offset, int value) { - struct qcom_gpio_bank *priv = dev_get_priv(dev); - uint32_t gpio_base = priv->pid + REG_OFFSET(offset); + struct qcom_pmic_gpio_data *plat = dev_get_plat(dev); + uint32_t gpio_base = plat->pid + REG_OFFSET(offset); /* Set the output value of the gpio */ - if (priv->lv_mv_type) + if (plat->lv_mv_type) return pmic_clrsetbits(dev->parent, gpio_base + REG_LV_MV_OUTPUT_CTL, REG_LV_MV_OUTPUT_CTL_MASK, @@ -209,71 +243,104 @@ static int qcom_gpio_set_value(struct udevice *dev, unsigned offset, REG_CTL_OUTPUT_MASK, !!value); } +static int qcom_gpio_xlate(struct udevice *dev, struct gpio_desc *desc, + struct ofnode_phandle_args *args) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + if (args->args_count < 1) + return -EINVAL; + + /* GPIOs in DT are 1-based */ + desc->offset = args->args[0] - 1; + if (desc->offset >= uc_priv->gpio_count) + return -EINVAL; + + if (args->args_count < 2) + return 0; + + desc->flags = gpio_flags_xlate(args->args[1]); + + return 0; +} + static const struct dm_gpio_ops qcom_gpio_ops = { .direction_input = qcom_gpio_direction_input, .direction_output = qcom_gpio_direction_output, .get_value = qcom_gpio_get_value, .set_value = qcom_gpio_set_value, .get_function = qcom_gpio_get_function, + .xlate = qcom_gpio_xlate, }; +static int qcom_gpio_bind(struct udevice *dev) +{ + + struct qcom_pmic_gpio_data *plat = dev_get_plat(dev); + ulong quirks = dev_get_driver_data(dev); + struct udevice *child; + struct driver *drv; + int ret; + + drv = lists_driver_lookup_name("qcom_pmic_pinctrl"); + if (!drv) { + log_warning("Cannot find driver '%s'\n", "qcom_pmic_pinctrl"); + return -ENOENT; + } + + /* Bind the GPIO driver as a child of the PMIC. */ + ret = device_bind_with_driver_data(dev, drv, + dev->name, + quirks, dev_ofnode(dev), &child); + if (ret) + return log_msg_ret("bind", ret); + + dev_set_plat(child, plat); + + return 0; +} + static int qcom_gpio_probe(struct udevice *dev) { - struct qcom_gpio_bank *priv = dev_get_priv(dev); - int reg; + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct qcom_pmic_gpio_data *plat = dev_get_plat(dev); + struct ofnode_phandle_args args; + int val, ret; u64 pid; + plat->pmic = dev->parent; + pid = dev_read_addr(dev); if (pid == FDT_ADDR_T_NONE) return log_msg_ret("bad address", -EINVAL); - priv->pid = pid; + plat->pid = pid; /* Do a sanity check */ - reg = pmic_reg_read(dev->parent, priv->pid + REG_TYPE); - if (reg != REG_TYPE_VAL) + val = pmic_reg_read(plat->pmic, plat->pid + REG_TYPE); + if (val != REG_TYPE_VAL) return log_msg_ret("bad type", -ENXIO); - reg = pmic_reg_read(dev->parent, priv->pid + REG_SUBTYPE); - if (reg != REG_SUBTYPE_GPIO_4CH && reg != REG_SUBTYPE_GPIOC_4CH && - reg != REG_SUBTYPE_GPIO_LV && reg != REG_SUBTYPE_GPIO_MV) + val = pmic_reg_read(plat->pmic, plat->pid + REG_SUBTYPE); + if (val != REG_SUBTYPE_GPIO_4CH && val != REG_SUBTYPE_GPIOC_4CH && + val != REG_SUBTYPE_GPIO_LV && val != REG_SUBTYPE_GPIO_MV) return log_msg_ret("bad subtype", -ENXIO); - priv->lv_mv_type = reg == REG_SUBTYPE_GPIO_LV || - reg == REG_SUBTYPE_GPIO_MV; - - return 0; -} - -/* - * Parse basic GPIO count specified via the gpio-ranges property - * as specified in Linux devicetrees - * Returns < 0 on error, otherwise gpio count - */ -static int qcom_gpio_of_parse_ranges(struct udevice *dev) -{ - int ret; - struct ofnode_phandle_args args; + plat->lv_mv_type = val == REG_SUBTYPE_GPIO_LV || + val == REG_SUBTYPE_GPIO_MV; + /* + * Parse basic GPIO count specified via the gpio-ranges property + * as specified in upstream devicetrees + */ ret = ofnode_parse_phandle_with_args(dev_ofnode(dev), "gpio-ranges", NULL, 3, 0, &args); if (ret) return log_msg_ret("gpio-ranges", ret); - return args.args[2]; -} - -static int qcom_gpio_of_to_plat(struct udevice *dev) -{ - struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); - int ret; - - ret = qcom_gpio_of_parse_ranges(dev); - if (ret > 0) - uc_priv->gpio_count = ret; - else - return ret; + plat->pin_count = args.args[2]; + uc_priv->gpio_count = plat->pin_count; uc_priv->bank_name = "pmic"; return 0; @@ -282,7 +349,7 @@ static int qcom_gpio_of_to_plat(struct udevice *dev) static const struct udevice_id qcom_gpio_ids[] = { { .compatible = "qcom,pm8916-gpio" }, { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */ - { .compatible = "qcom,pm8998-gpio" }, + { .compatible = "qcom,pm8998-gpio", .data = QCOM_PMIC_QUIRK_READONLY }, { .compatible = "qcom,pms405-gpio" }, { } }; @@ -291,9 +358,75 @@ U_BOOT_DRIVER(qcom_pmic_gpio) = { .name = "qcom_pmic_gpio", .id = UCLASS_GPIO, .of_match = qcom_gpio_ids, - .of_to_plat = qcom_gpio_of_to_plat, - .probe = qcom_gpio_probe, + .bind = qcom_gpio_bind, + .probe = qcom_gpio_probe, .ops = &qcom_gpio_ops, - .priv_auto = sizeof(struct qcom_gpio_bank), + .plat_auto = sizeof(struct qcom_pmic_gpio_data), + .flags = DM_FLAG_ALLOC_PDATA, +}; + +static const struct pinconf_param qcom_pmic_pinctrl_conf_params[] = { + { "output-high", PIN_CONFIG_OUTPUT_ENABLE, 1 }, + { "output-low", PIN_CONFIG_OUTPUT, 0 }, +}; + +static int qcom_pmic_pinctrl_get_pins_count(struct udevice *dev) +{ + struct qcom_pmic_gpio_data *plat = dev_get_plat(dev); + + return plat->pin_count; +} + +static const char *qcom_pmic_pinctrl_get_pin_name(struct udevice *dev, unsigned int selector) +{ + static char name[8]; + + /* DT indexes from 1 */ + snprintf(name, sizeof(name), "gpio%u", selector + 1); + + return name; +} + +static int qcom_pmic_pinctrl_pinconf_set(struct udevice *dev, unsigned int selector, + unsigned int param, unsigned int arg) +{ + /* We only support configuring the pin as an output, either low or high */ + return _qcom_gpio_set_direction(dev, selector, false, + param == PIN_CONFIG_OUTPUT_ENABLE); +} + +static const char *qcom_pmic_pinctrl_get_function_name(struct udevice *dev, unsigned int selector) +{ + if (!selector) + return "normal"; + return NULL; +} + +static int qcom_pmic_pinctrl_generic_get_functions_count(struct udevice *dev) +{ + return 1; +} + +static int qcom_pmic_pinctrl_generic_pinmux_set_mux(struct udevice *dev, unsigned int selector, + unsigned int func_selector) +{ + return 0; +} + +struct pinctrl_ops qcom_pmic_pinctrl_ops = { + .get_pins_count = qcom_pmic_pinctrl_get_pins_count, + .get_pin_name = qcom_pmic_pinctrl_get_pin_name, + .set_state = pinctrl_generic_set_state, + .pinconf_num_params = ARRAY_SIZE(qcom_pmic_pinctrl_conf_params), + .pinconf_params = qcom_pmic_pinctrl_conf_params, + .pinconf_set = qcom_pmic_pinctrl_pinconf_set, + .get_function_name = qcom_pmic_pinctrl_get_function_name, + .get_functions_count = qcom_pmic_pinctrl_generic_get_functions_count, + .pinmux_set = qcom_pmic_pinctrl_generic_pinmux_set_mux, }; +U_BOOT_DRIVER(qcom_pmic_pinctrl) = { + .name = "qcom_pmic_pinctrl", + .id = UCLASS_PINCTRL, + .ops = &qcom_pmic_pinctrl_ops, +}; diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c index 4a6ae554bf7..2e901ac5c73 100644 --- a/drivers/gpio/rk_gpio.c +++ b/drivers/gpio/rk_gpio.c @@ -11,7 +11,6 @@ #include <syscon.h> #include <linux/errno.h> #include <asm/gpio.h> -#include <asm/io.h> #include <asm/arch-rockchip/clock.h> #include <asm/arch-rockchip/hardware.h> #include <asm/arch-rockchip/gpio.h> @@ -201,8 +200,11 @@ static int rockchip_gpio_probe(struct udevice *dev) priv->bank = args.args[1] / ROCKCHIP_GPIOS_PER_BANK; } else { uc_priv->gpio_count = ROCKCHIP_GPIOS_PER_BANK; - end = strrchr(dev->name, '@'); - priv->bank = trailing_strtoln(dev->name, end); + ret = dev_read_alias_seq(dev, &priv->bank); + if (ret) { + end = strrchr(dev->name, '@'); + priv->bank = trailing_strtoln(dev->name, end); + } } priv->name[0] = 'A' + priv->bank; |