diff options
Diffstat (limited to 'drivers/pinctrl/qcom/pinctrl-lpass-lpi.c')
| -rw-r--r-- | drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 119 |
1 files changed, 78 insertions, 41 deletions
diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c index e5a418026ba3..1c97ec44aa5f 100644 --- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c @@ -20,7 +20,7 @@ #include "pinctrl-lpass-lpi.h" -#define MAX_NR_GPIO 23 +#define MAX_NR_GPIO 32 #define GPIO_FUNC 0 #define MAX_LPI_NUM_CLKS 2 @@ -32,7 +32,8 @@ struct lpi_pinctrl { char __iomem *tlmm_base; char __iomem *slew_base; struct clk_bulk_data clks[MAX_LPI_NUM_CLKS]; - struct mutex slew_access_lock; + /* Protects from concurrent register updates */ + struct mutex lock; DECLARE_BITMAP(ever_gpio, MAX_NR_GPIO); const struct lpi_pinctrl_variant_data *data; }; @@ -40,13 +41,27 @@ struct lpi_pinctrl { static int lpi_gpio_read(struct lpi_pinctrl *state, unsigned int pin, unsigned int addr) { - return ioread32(state->tlmm_base + LPI_TLMM_REG_OFFSET * pin + addr); + u32 pin_offset; + + if (state->data->flags & LPI_FLAG_USE_PREDEFINED_PIN_OFFSET) + pin_offset = state->data->groups[pin].pin_offset; + else + pin_offset = LPI_TLMM_REG_OFFSET * pin; + + return ioread32(state->tlmm_base + pin_offset + addr); } static int lpi_gpio_write(struct lpi_pinctrl *state, unsigned int pin, unsigned int addr, unsigned int val) { - iowrite32(val, state->tlmm_base + LPI_TLMM_REG_OFFSET * pin + addr); + u32 pin_offset; + + if (state->data->flags & LPI_FLAG_USE_PREDEFINED_PIN_OFFSET) + pin_offset = state->data->groups[pin].pin_offset; + else + pin_offset = LPI_TLMM_REG_OFFSET * pin; + + iowrite32(val, state->tlmm_base + pin_offset + addr); return 0; } @@ -103,6 +118,7 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function, if (WARN_ON(i == g->nfuncs)) return -EINVAL; + mutex_lock(&pctrl->lock); val = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG); /* @@ -128,6 +144,7 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function, u32p_replace_bits(&val, i, LPI_GPIO_FUNCTION_MASK); lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val); + mutex_unlock(&pctrl->lock); return 0; } @@ -171,7 +188,7 @@ static int lpi_config_get(struct pinctrl_dev *pctldev, arg = 1; break; case PIN_CONFIG_INPUT_ENABLE: - case PIN_CONFIG_OUTPUT: + case PIN_CONFIG_LEVEL: if (is_out) arg = 1; break; @@ -183,6 +200,41 @@ static int lpi_config_get(struct pinctrl_dev *pctldev, return 0; } +static int lpi_config_set_slew_rate(struct lpi_pinctrl *pctrl, + const struct lpi_pingroup *g, + unsigned int group, unsigned int slew) +{ + unsigned long sval; + void __iomem *reg; + int slew_offset; + + if (slew > LPI_SLEW_RATE_MAX) { + dev_err(pctrl->dev, "invalid slew rate %u for pin: %d\n", + slew, group); + return -EINVAL; + } + + slew_offset = g->slew_offset; + if (slew_offset == LPI_NO_SLEW) + return 0; + + if (pctrl->data->flags & LPI_FLAG_SLEW_RATE_SAME_REG) + reg = pctrl->tlmm_base + LPI_TLMM_REG_OFFSET * group + LPI_GPIO_CFG_REG; + else + reg = pctrl->slew_base + LPI_SLEW_RATE_CTL_REG; + + mutex_lock(&pctrl->lock); + + sval = ioread32(reg); + sval &= ~(LPI_SLEW_RATE_MASK << slew_offset); + sval |= slew << slew_offset; + iowrite32(sval, reg); + + mutex_unlock(&pctrl->lock); + + return 0; +} + static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, unsigned long *configs, unsigned int nconfs) { @@ -190,8 +242,7 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, unsigned int param, arg, pullup = LPI_GPIO_BIAS_DISABLE, strength = 2; bool value, output_enabled = false; const struct lpi_pingroup *g; - unsigned long sval; - int i, slew_offset; + int i, ret; u32 val; g = &pctrl->data->groups[group]; @@ -215,7 +266,7 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, case PIN_CONFIG_INPUT_ENABLE: output_enabled = false; break; - case PIN_CONFIG_OUTPUT: + case PIN_CONFIG_LEVEL: output_enabled = true; value = arg; break; @@ -223,24 +274,9 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, strength = arg; break; case PIN_CONFIG_SLEW_RATE: - if (arg > LPI_SLEW_RATE_MAX) { - dev_err(pctldev->dev, "invalid slew rate %u for pin: %d\n", - arg, group); - return -EINVAL; - } - - slew_offset = g->slew_offset; - if (slew_offset == LPI_NO_SLEW) - break; - - mutex_lock(&pctrl->slew_access_lock); - - sval = ioread32(pctrl->slew_base + LPI_SLEW_RATE_CTL_REG); - sval &= ~(LPI_SLEW_RATE_MASK << slew_offset); - sval |= arg << slew_offset; - iowrite32(sval, pctrl->slew_base + LPI_SLEW_RATE_CTL_REG); - - mutex_unlock(&pctrl->slew_access_lock); + ret = lpi_config_set_slew_rate(pctrl, g, group, arg); + if (ret) + return ret; break; default: return -EINVAL; @@ -256,6 +292,7 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val); } + mutex_lock(&pctrl->lock); val = lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG); u32p_replace_bits(&val, pullup, LPI_GPIO_PULL_MASK); @@ -264,6 +301,7 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, u32p_replace_bits(&val, output_enabled, LPI_GPIO_OE_MASK); lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val); + mutex_unlock(&pctrl->lock); return 0; } @@ -290,7 +328,7 @@ static int lpi_gpio_direction_output(struct gpio_chip *chip, struct lpi_pinctrl *state = gpiochip_get_data(chip); unsigned long config; - config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val); + config = pinconf_to_config_packed(PIN_CONFIG_LEVEL, val); return lpi_config_set(state->ctrl, pin, &config, 1); } @@ -303,18 +341,17 @@ static int lpi_gpio_get(struct gpio_chip *chip, unsigned int pin) LPI_GPIO_VALUE_IN_MASK; } -static void lpi_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) +static int lpi_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) { struct lpi_pinctrl *state = gpiochip_get_data(chip); unsigned long config; - config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value); + config = pinconf_to_config_packed(PIN_CONFIG_LEVEL, value); - lpi_config_set(state->ctrl, pin, &config, 1); + return lpi_config_set(state->ctrl, pin, &config, 1); } #ifdef CONFIG_DEBUG_FS -#include <linux/seq_file.h> static unsigned int lpi_regval_to_drive(u32 val) { @@ -434,10 +471,12 @@ int lpi_pinctrl_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(pctrl->tlmm_base), "TLMM resource not provided\n"); - pctrl->slew_base = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(pctrl->slew_base)) - return dev_err_probe(dev, PTR_ERR(pctrl->slew_base), - "Slew resource not provided\n"); + if (!(data->flags & LPI_FLAG_SLEW_RATE_SAME_REG)) { + pctrl->slew_base = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(pctrl->slew_base)) + return dev_err_probe(dev, PTR_ERR(pctrl->slew_base), + "Slew resource not provided\n"); + } ret = devm_clk_bulk_get_optional(dev, MAX_LPI_NUM_CLKS, pctrl->clks); if (ret) @@ -461,7 +500,7 @@ int lpi_pinctrl_probe(struct platform_device *pdev) pctrl->chip.label = dev_name(dev); pctrl->chip.can_sleep = false; - mutex_init(&pctrl->slew_access_lock); + mutex_init(&pctrl->lock); pctrl->ctrl = devm_pinctrl_register(dev, &pctrl->desc, pctrl); if (IS_ERR(pctrl->ctrl)) { @@ -483,25 +522,23 @@ int lpi_pinctrl_probe(struct platform_device *pdev) return 0; err_pinctrl: - mutex_destroy(&pctrl->slew_access_lock); + mutex_destroy(&pctrl->lock); clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks); return ret; } EXPORT_SYMBOL_GPL(lpi_pinctrl_probe); -int lpi_pinctrl_remove(struct platform_device *pdev) +void lpi_pinctrl_remove(struct platform_device *pdev) { struct lpi_pinctrl *pctrl = platform_get_drvdata(pdev); int i; - mutex_destroy(&pctrl->slew_access_lock); + mutex_destroy(&pctrl->lock); clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks); for (i = 0; i < pctrl->data->npins; i++) pinctrl_generic_remove_group(pctrl->ctrl, i); - - return 0; } EXPORT_SYMBOL_GPL(lpi_pinctrl_remove); |
