diff options
Diffstat (limited to 'drivers/pinctrl/qcom/pinctrl-lpass-lpi.c')
-rw-r--r-- | drivers/pinctrl/qcom/pinctrl-lpass-lpi.c | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c index 87920257bb73..fdb6585a9234 100644 --- a/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c +++ b/drivers/pinctrl/qcom/pinctrl-lpass-lpi.c @@ -19,6 +19,8 @@ #include "pinctrl-lpass-lpi.h" +#define MAX_NR_GPIO 23 +#define GPIO_FUNC 0 #define MAX_LPI_NUM_CLKS 2 struct lpi_pinctrl { @@ -30,6 +32,7 @@ struct lpi_pinctrl { char __iomem *slew_base; struct clk_bulk_data clks[MAX_LPI_NUM_CLKS]; struct mutex slew_access_lock; + DECLARE_BITMAP(ever_gpio, MAX_NR_GPIO); const struct lpi_pinctrl_variant_data *data; }; @@ -84,10 +87,10 @@ static int lpi_gpio_get_function_groups(struct pinctrl_dev *pctldev, } static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function, - unsigned int group_num) + unsigned int group) { struct lpi_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - const struct lpi_pingroup *g = &pctrl->data->groups[group_num]; + const struct lpi_pingroup *g = &pctrl->data->groups[group]; u32 val; int i, pin = g->pin; @@ -100,6 +103,28 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function, return -EINVAL; val = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG); + + /* + * If this is the first time muxing to GPIO and the direction is + * output, make sure that we're not going to be glitching the pin + * by reading the current state of the pin and setting it as the + * output. + */ + if (i == GPIO_FUNC && (val & LPI_GPIO_OE_MASK) && + !test_and_set_bit(group, pctrl->ever_gpio)) { + u32 io_val = lpi_gpio_read(pctrl, group, LPI_GPIO_VALUE_REG); + + if (io_val & LPI_GPIO_VALUE_IN_MASK) { + if (!(io_val & LPI_GPIO_VALUE_OUT_MASK)) + lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, + io_val | LPI_GPIO_VALUE_OUT_MASK); + } else { + if (io_val & LPI_GPIO_VALUE_OUT_MASK) + lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, + io_val & ~LPI_GPIO_VALUE_OUT_MASK); + } + } + u32p_replace_bits(&val, i, LPI_GPIO_FUNCTION_MASK); lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val); @@ -221,6 +246,15 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, } } + /* + * As per Hardware Programming Guide, when configuring pin as output, + * set the pin value before setting output-enable (OE). + */ + if (output_enabled) { + val = u32_encode_bits(value ? 1 : 0, LPI_GPIO_VALUE_OUT_MASK); + lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val); + } + val = lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG); u32p_replace_bits(&val, pullup, LPI_GPIO_PULL_MASK); @@ -230,11 +264,6 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group, lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val); - if (output_enabled) { - val = u32_encode_bits(value ? 1 : 0, LPI_GPIO_VALUE_OUT_MASK); - lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val); - } - return 0; } @@ -390,6 +419,9 @@ int lpi_pinctrl_probe(struct platform_device *pdev) if (!data) return -EINVAL; + if (WARN_ON(data->npins > MAX_NR_GPIO)) + return -EINVAL; + pctrl->data = data; pctrl->dev = &pdev->dev; |