Loading soc/pinctrl-lpi.c +134 −43 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #include <linux/gpio.h> Loading @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/clk.h> #include <linux/bitops.h> #include <soc/snd_event.h> #include <linux/pm_runtime.h> #include <dsp/audio_notifier.h> Loading @@ -24,10 +25,16 @@ #define LPI_AUTO_SUSPEND_DELAY 100 /* delay in msec */ #define LPI_ADDRESS_SIZE 0x20000 #define LPI_SLEW_ADDRESS_SIZE 0x1000 #define LPI_GPIO_REG_VAL_CTL 0x00 #define LPI_GPIO_REG_DIR_CTL 0x04 #define LPI_SLEW_REG_VAL_CTL 0x00 #define LPI_SLEW_RATE_MAX 0x03 #define LPI_SLEW_BITS_SIZE 0x02 #define LPI_SLEW_OFFSET_INVALID 0xFFFFFFFF #define LPI_GPIO_REG_PULL_SHIFT 0x0 #define LPI_GPIO_REG_PULL_MASK 0x3 Loading Loading @@ -70,19 +77,27 @@ enum lpi_gpio_func_index { /** * struct lpi_gpio_pad - keep current GPIO settings * @offset: Nth GPIO in supported GPIOs. * @offset: stores one of gpio_offset or slew_offset at a given time. * @gpio_offset: Nth GPIO in supported GPIOs. * @slew_offset: Nth GPIO's position in slew register in supported GPIOs. * @output_enabled: Set to true if GPIO output logic is enabled. * @value: value of a pin * @base: Address base of LPI GPIO PAD. * @base: stores one of gpio_base or slew_base at a given time. * @gpio_base: Address base of LPI GPIO PAD. * @slew_base: Address base of LPI SLEW PAD. * @pullup: Constant current which flow through GPIO output buffer. * @strength: No, Low, Medium, High * @function: See lpi_gpio_functions[] */ struct lpi_gpio_pad { u32 offset; u32 gpio_offset; u32 slew_offset; bool output_enabled; bool value; char __iomem *base; char __iomem *gpio_base; char __iomem *slew_base; unsigned int pullup; unsigned int strength; unsigned int function; Loading @@ -94,6 +109,7 @@ struct lpi_gpio_state { struct gpio_chip chip; char __iomem *base; struct clk *lpass_npa_rsc_island; struct mutex slew_access_lock; }; static const char *const lpi_gpio_groups[] = { Loading @@ -106,6 +122,7 @@ static const char *const lpi_gpio_groups[] = { #define LPI_TLMM_MAX_PINS 100 static u32 lpi_offset[LPI_TLMM_MAX_PINS]; static u32 lpi_slew_offset[LPI_TLMM_MAX_PINS]; static const char *const lpi_gpio_functions[] = { [LPI_GPIO_FUNC_INDEX_GPIO] = LPI_GPIO_FUNC_GPIO, Loading Loading @@ -272,7 +289,9 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int pin, { struct lpi_gpio_pad *pad; unsigned int param, arg; int i, ret = 0, val; int i, ret = 0; volatile unsigned long val; struct lpi_gpio_state *state = dev_get_drvdata(pctldev->dev); pad = pctldev->desc->pins[pin].drv_data; Loading Loading @@ -306,12 +325,44 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int pin, case PIN_CONFIG_DRIVE_STRENGTH: pad->strength = arg; break; case PIN_CONFIG_SLEW_RATE: if (pad->slew_base == NULL || pad->slew_offset == LPI_SLEW_OFFSET_INVALID) { dev_dbg(pctldev->dev, "%s: invalid slew settings for pin: %d\n", __func__, pin); goto set_gpio; } if (arg > LPI_SLEW_RATE_MAX) { dev_err(pctldev->dev, "%s: invalid slew rate %u for pin: %d\n", __func__, arg, pin); goto set_gpio; } pad->base = pad->slew_base; pad->offset = 0; mutex_lock(&state->slew_access_lock); val = lpi_gpio_read(pad, LPI_SLEW_REG_VAL_CTL); pad->offset = pad->slew_offset; for (i = 0; i < LPI_SLEW_BITS_SIZE; i++) { if (arg & 0x01) set_bit(pad->offset, &val); else clear_bit(pad->offset, &val); pad->offset++; arg = arg >> 1; } pad->offset = 0; lpi_gpio_write(pad, LPI_SLEW_REG_VAL_CTL, val); mutex_unlock(&state->slew_access_lock); break; default: ret = -EINVAL; goto done; } } set_gpio: pad->base = pad->gpio_base; pad->offset = pad->gpio_offset; val = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL); val &= ~(LPI_GPIO_REG_PULL_MASK | LPI_GPIO_REG_OUT_STRENGTH_MASK | LPI_GPIO_REG_OE_MASK); Loading Loading @@ -502,7 +553,8 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) struct lpi_gpio_state *state; int ret, npins, i; char __iomem *lpi_base; u32 reg; char __iomem *slew_base; u32 reg, slew_reg; struct clk *lpass_npa_rsc_island = NULL; ret = of_property_read_u32(dev->of_node, "reg", ®); Loading @@ -524,6 +576,16 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) return ret; } ret = of_property_read_u32_array(dev->of_node, "qcom,lpi-slew-offset-tbl", lpi_slew_offset, npins); if (ret < 0) { for (i = 0; i < npins; i++) lpi_slew_offset[i] = LPI_SLEW_OFFSET_INVALID; dev_dbg(dev, "%s: error in reading lpi slew offset table: %d\n", __func__, ret); } state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; Loading @@ -532,6 +594,23 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) state->dev = &pdev->dev; slew_reg = 0; ret = of_property_read_u32(dev->of_node, "qcom,slew-reg", &slew_reg); if (!ret) { slew_base = devm_ioremap(dev, slew_reg, LPI_SLEW_ADDRESS_SIZE); if (slew_base == NULL) { dev_err(dev, "%s devm_ioremap failed for slew rate reg\n", __func__); ret = -ENOMEM; goto err_io; } } else { slew_base = NULL; dev_dbg(dev, "error in reading lpi slew register: %d\n", __func__, ret); } pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL); if (!pindesc) return -ENOMEM; Loading Loading @@ -566,8 +645,13 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) pindesc->number = i; pindesc->name = lpi_gpio_groups[i]; pad->base = lpi_base; pad->offset = lpi_offset[i]; pad->gpio_base = lpi_base; pad->slew_base = slew_base; pad->base = pad->gpio_base; pad->gpio_offset = lpi_offset[i]; pad->slew_offset = lpi_slew_offset[i]; pad->offset = pad->gpio_offset; } state->chip = lpi_gpio_template; Loading @@ -578,6 +662,8 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) state->chip.of_gpio_n_cells = 2; state->chip.can_sleep = false; mutex_init(&state->slew_access_lock); state->ctrl = devm_pinctrl_register(dev, pctrldesc, state); if (IS_ERR(state->ctrl)) return PTR_ERR(state->ctrl); Loading Loading @@ -636,18 +722,23 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) err_range: gpiochip_remove(&state->chip); err_chip: mutex_destroy(&state->slew_access_lock); err_io: return ret; } static int lpi_pinctrl_remove(struct platform_device *pdev) { struct lpi_gpio_state *state = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); snd_event_client_deregister(&pdev->dev); audio_notifier_deregister("lpi_tlmm"); gpiochip_remove(&state->chip); mutex_destroy(&state->slew_access_lock); return 0; } Loading Loading
soc/pinctrl-lpi.c +134 −43 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #include <linux/gpio.h> Loading @@ -14,6 +14,7 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/clk.h> #include <linux/bitops.h> #include <soc/snd_event.h> #include <linux/pm_runtime.h> #include <dsp/audio_notifier.h> Loading @@ -24,10 +25,16 @@ #define LPI_AUTO_SUSPEND_DELAY 100 /* delay in msec */ #define LPI_ADDRESS_SIZE 0x20000 #define LPI_SLEW_ADDRESS_SIZE 0x1000 #define LPI_GPIO_REG_VAL_CTL 0x00 #define LPI_GPIO_REG_DIR_CTL 0x04 #define LPI_SLEW_REG_VAL_CTL 0x00 #define LPI_SLEW_RATE_MAX 0x03 #define LPI_SLEW_BITS_SIZE 0x02 #define LPI_SLEW_OFFSET_INVALID 0xFFFFFFFF #define LPI_GPIO_REG_PULL_SHIFT 0x0 #define LPI_GPIO_REG_PULL_MASK 0x3 Loading Loading @@ -70,19 +77,27 @@ enum lpi_gpio_func_index { /** * struct lpi_gpio_pad - keep current GPIO settings * @offset: Nth GPIO in supported GPIOs. * @offset: stores one of gpio_offset or slew_offset at a given time. * @gpio_offset: Nth GPIO in supported GPIOs. * @slew_offset: Nth GPIO's position in slew register in supported GPIOs. * @output_enabled: Set to true if GPIO output logic is enabled. * @value: value of a pin * @base: Address base of LPI GPIO PAD. * @base: stores one of gpio_base or slew_base at a given time. * @gpio_base: Address base of LPI GPIO PAD. * @slew_base: Address base of LPI SLEW PAD. * @pullup: Constant current which flow through GPIO output buffer. * @strength: No, Low, Medium, High * @function: See lpi_gpio_functions[] */ struct lpi_gpio_pad { u32 offset; u32 gpio_offset; u32 slew_offset; bool output_enabled; bool value; char __iomem *base; char __iomem *gpio_base; char __iomem *slew_base; unsigned int pullup; unsigned int strength; unsigned int function; Loading @@ -94,6 +109,7 @@ struct lpi_gpio_state { struct gpio_chip chip; char __iomem *base; struct clk *lpass_npa_rsc_island; struct mutex slew_access_lock; }; static const char *const lpi_gpio_groups[] = { Loading @@ -106,6 +122,7 @@ static const char *const lpi_gpio_groups[] = { #define LPI_TLMM_MAX_PINS 100 static u32 lpi_offset[LPI_TLMM_MAX_PINS]; static u32 lpi_slew_offset[LPI_TLMM_MAX_PINS]; static const char *const lpi_gpio_functions[] = { [LPI_GPIO_FUNC_INDEX_GPIO] = LPI_GPIO_FUNC_GPIO, Loading Loading @@ -272,7 +289,9 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int pin, { struct lpi_gpio_pad *pad; unsigned int param, arg; int i, ret = 0, val; int i, ret = 0; volatile unsigned long val; struct lpi_gpio_state *state = dev_get_drvdata(pctldev->dev); pad = pctldev->desc->pins[pin].drv_data; Loading Loading @@ -306,12 +325,44 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int pin, case PIN_CONFIG_DRIVE_STRENGTH: pad->strength = arg; break; case PIN_CONFIG_SLEW_RATE: if (pad->slew_base == NULL || pad->slew_offset == LPI_SLEW_OFFSET_INVALID) { dev_dbg(pctldev->dev, "%s: invalid slew settings for pin: %d\n", __func__, pin); goto set_gpio; } if (arg > LPI_SLEW_RATE_MAX) { dev_err(pctldev->dev, "%s: invalid slew rate %u for pin: %d\n", __func__, arg, pin); goto set_gpio; } pad->base = pad->slew_base; pad->offset = 0; mutex_lock(&state->slew_access_lock); val = lpi_gpio_read(pad, LPI_SLEW_REG_VAL_CTL); pad->offset = pad->slew_offset; for (i = 0; i < LPI_SLEW_BITS_SIZE; i++) { if (arg & 0x01) set_bit(pad->offset, &val); else clear_bit(pad->offset, &val); pad->offset++; arg = arg >> 1; } pad->offset = 0; lpi_gpio_write(pad, LPI_SLEW_REG_VAL_CTL, val); mutex_unlock(&state->slew_access_lock); break; default: ret = -EINVAL; goto done; } } set_gpio: pad->base = pad->gpio_base; pad->offset = pad->gpio_offset; val = lpi_gpio_read(pad, LPI_GPIO_REG_VAL_CTL); val &= ~(LPI_GPIO_REG_PULL_MASK | LPI_GPIO_REG_OUT_STRENGTH_MASK | LPI_GPIO_REG_OE_MASK); Loading Loading @@ -502,7 +553,8 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) struct lpi_gpio_state *state; int ret, npins, i; char __iomem *lpi_base; u32 reg; char __iomem *slew_base; u32 reg, slew_reg; struct clk *lpass_npa_rsc_island = NULL; ret = of_property_read_u32(dev->of_node, "reg", ®); Loading @@ -524,6 +576,16 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) return ret; } ret = of_property_read_u32_array(dev->of_node, "qcom,lpi-slew-offset-tbl", lpi_slew_offset, npins); if (ret < 0) { for (i = 0; i < npins; i++) lpi_slew_offset[i] = LPI_SLEW_OFFSET_INVALID; dev_dbg(dev, "%s: error in reading lpi slew offset table: %d\n", __func__, ret); } state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; Loading @@ -532,6 +594,23 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) state->dev = &pdev->dev; slew_reg = 0; ret = of_property_read_u32(dev->of_node, "qcom,slew-reg", &slew_reg); if (!ret) { slew_base = devm_ioremap(dev, slew_reg, LPI_SLEW_ADDRESS_SIZE); if (slew_base == NULL) { dev_err(dev, "%s devm_ioremap failed for slew rate reg\n", __func__); ret = -ENOMEM; goto err_io; } } else { slew_base = NULL; dev_dbg(dev, "error in reading lpi slew register: %d\n", __func__, ret); } pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL); if (!pindesc) return -ENOMEM; Loading Loading @@ -566,8 +645,13 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) pindesc->number = i; pindesc->name = lpi_gpio_groups[i]; pad->base = lpi_base; pad->offset = lpi_offset[i]; pad->gpio_base = lpi_base; pad->slew_base = slew_base; pad->base = pad->gpio_base; pad->gpio_offset = lpi_offset[i]; pad->slew_offset = lpi_slew_offset[i]; pad->offset = pad->gpio_offset; } state->chip = lpi_gpio_template; Loading @@ -578,6 +662,8 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) state->chip.of_gpio_n_cells = 2; state->chip.can_sleep = false; mutex_init(&state->slew_access_lock); state->ctrl = devm_pinctrl_register(dev, pctrldesc, state); if (IS_ERR(state->ctrl)) return PTR_ERR(state->ctrl); Loading Loading @@ -636,18 +722,23 @@ static int lpi_pinctrl_probe(struct platform_device *pdev) err_range: gpiochip_remove(&state->chip); err_chip: mutex_destroy(&state->slew_access_lock); err_io: return ret; } static int lpi_pinctrl_remove(struct platform_device *pdev) { struct lpi_gpio_state *state = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); snd_event_client_deregister(&pdev->dev); audio_notifier_deregister("lpi_tlmm"); gpiochip_remove(&state->chip); mutex_destroy(&state->slew_access_lock); return 0; } Loading