Loading arch/arm64/configs/vendor/gen3auto_GKI.config +3 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,9 @@ CONFIG_UNUSED_KSYMS_WHITELIST="android/abi_gki_aarch64_qcom android/abi_gki_aarc CONFIG_UNUSED_KSYMS_WHITELIST_ONLY=y CONFIG_PINCTRL_SM8150=m CONFIG_PINCTRL_SDMSHRIKE=m CONFIG_PINCTRL_SLPI=m CONFIG_ION_MSM_HEAPS=m CONFIG_QCOM_SECURE_BUFFER=m CONFIG_HEADER_TEST=y CONFIG_HEADERS_INSTALL=y CONFIG_KERNEL_HEADER_TEST=y Loading arch/arm64/configs/vendor/gen3auto_QGKI.config +1 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ CONFIG_LOCALVERSION="-qgki" CONFIG_DEBUG_FS=y # CONFIG_TRIM_UNUSED_KSYMS is not set CONFIG_REGULATOR_QTI_DEBUG=y CONFIG_ION_POOL_AUTO_REFILL=y # CONFIG_DETECT_HUNG_TASK is not set # CONFIG_ZONE_DMA32 is not set # CONFIG_SOFTLOCKUP_DETECTOR is not set Loading drivers/pinctrl/qcom/Kconfig +10 −0 Original line number Diff line number Diff line Loading @@ -300,4 +300,14 @@ config PINCTRL_MONACO Say Y here to compile statically, or M here to compile it as a module. If unsure, say N. config PINCTRL_SLPI tristate "Qualcomm Technologies, Inc SLPI pin controller driver" depends on GPIOLIB && OF help Sensor Low Power Island(SLPI) has a Pin controller which can support 14 pin configurations. This is the pinctrl, pinmux and pinconf driver for the SLPI pin controller block. Say Y here to compile statically, or M here to compile it as a module. If unsure, say N. endif drivers/pinctrl/qcom/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -33,3 +33,4 @@ obj-$(CONFIG_PINCTRL_SCUBA) += pinctrl-scuba.o obj-$(CONFIG_PINCTRL_SDXLEMUR) += pinctrl-sdxlemur.o obj-$(CONFIG_PINCTRL_SDXNIGHTJAR) += pinctrl-sdxnightjar.o obj-$(CONFIG_PINCTRL_MONACO) += pinctrl-monaco.o obj-$(CONFIG_PINCTRL_SLPI) += pinctrl-slpi.o drivers/pinctrl/qcom/pinctrl-slpi.c 0 → 100644 +457 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include <linux/gpio.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinmux.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/types.h> #include "../core.h" #include "../pinctrl-utils.h" /** * struct slpi_pin - SLPI pin definition * @name: Name of the pin. * @ctl_reg: Offset of the register holding control bits for this group. * @io_reg: Offset of the register holding input/output bits for this group. * @pull_bit: Offset in @ctl_reg for the bias configuration. * @mux_bit: Offset in @ctl_reg for the pinmux function selection. * @drv_bit: Offset in @ctl_reg for the drive strength configuration. * @oe_bit: Offset in @ctl_reg for controlling output enable. * @in_bit: Offset in @io_reg for the input bit value. * @out_bit: Offset in @io_reg for the output bit value. */ struct slpi_pin { void __iomem *base; unsigned int offset; unsigned int ctl_reg; unsigned int io_reg; unsigned int pull_bit:5; unsigned int mux_bit:5; unsigned int drv_bit:5; unsigned int oe_bit:5; unsigned int in_bit:5; unsigned int out_bit:5; }; /* The index of each function in slpi_pin_functions[] array */ enum slpi_pin_func_index { SLPI_PIN_FUNC_INDEX_GPIO = 0x00, SLPI_PIN_FUNC_INDEX_FUNC1 = 0x01, SLPI_PIN_FUNC_INDEX_FUNC2 = 0x02, SLPI_PIN_FUNC_INDEX_FUNC3 = 0x03, SLPI_PIN_FUNC_INDEX_FUNC4 = 0x04, SLPI_PIN_FUNC_INDEX_FUNC5 = 0x05, }; #define SLPI_PIN_FUNC_GPIO "gpio" #define SLPI_PIN_FUNC_FUNC1 "func1" #define SLPI_PIN_FUNC_FUNC2 "func2" #define SLPI_PIN_FUNC_FUNC3 "func3" #define SLPI_PIN_FUNC_FUNC4 "func4" #define SLPI_PIN_FUNC_FUNC5 "func5" static const char *const slpi_gpio_groups[] = { "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", }; static const char *const slpi_pin_functions[] = { [SLPI_PIN_FUNC_INDEX_GPIO] = SLPI_PIN_FUNC_GPIO, [SLPI_PIN_FUNC_INDEX_FUNC1] = SLPI_PIN_FUNC_FUNC1, [SLPI_PIN_FUNC_INDEX_FUNC2] = SLPI_PIN_FUNC_FUNC2, [SLPI_PIN_FUNC_INDEX_FUNC3] = SLPI_PIN_FUNC_FUNC3, [SLPI_PIN_FUNC_INDEX_FUNC4] = SLPI_PIN_FUNC_FUNC4, [SLPI_PIN_FUNC_INDEX_FUNC5] = SLPI_PIN_FUNC_FUNC5, }; static unsigned int slpi_read(struct slpi_pin *pin, u32 reg) { return readl_relaxed(pin->base + pin->offset + reg); } static void slpi_write(u32 val, struct slpi_pin *pin, u32 reg) { return writel_relaxed(val, pin->base + pin->offset + reg); } static int slpi_get_groups_count(struct pinctrl_dev *pctldev) { /* Every PIN is a group */ return pctldev->desc->npins; } static const char *slpi_get_group_name(struct pinctrl_dev *pctldev, unsigned int pin) { return pctldev->desc->pins[pin].name; } static int slpi_get_group_pins(struct pinctrl_dev *pctldev, unsigned int pin, const unsigned int **pins, unsigned int *num_pins) { *pins = &pctldev->desc->pins[pin].number; *num_pins = 1; return 0; } static const struct pinctrl_ops slpi_pinctrl_ops = { .get_groups_count = slpi_get_groups_count, .get_group_name = slpi_get_group_name, .get_group_pins = slpi_get_group_pins, .dt_node_to_map = pinconf_generic_dt_node_to_map_group, .dt_free_map = pinctrl_utils_free_map, }; static int slpi_get_functions_count(struct pinctrl_dev *pctldev) { return ARRAY_SIZE(slpi_pin_functions); } static const char *slpi_get_function_name(struct pinctrl_dev *pctldev, unsigned int function) { return slpi_pin_functions[function]; } static int slpi_get_function_groups(struct pinctrl_dev *pctldev, unsigned int function, const char * const **groups, unsigned int * const num_groups) { *groups = slpi_gpio_groups; *num_groups = pctldev->desc->npins; return 0; } static int slpi_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, unsigned int pin_index) { struct slpi_pin *pin; u32 val; pin = pctldev->desc->pins[pin_index].drv_data; if (WARN_ON(function >= ARRAY_SIZE(slpi_pin_functions))) return -EINVAL; val = slpi_read(pin, pin->ctl_reg); val &= ~(0x7 << pin->mux_bit); val |= function << pin->mux_bit; slpi_write(val, pin, pin->ctl_reg); return 0; } static const struct pinmux_ops slpi_pinmux_ops = { .get_functions_count = slpi_get_functions_count, .get_function_name = slpi_get_function_name, .get_function_groups = slpi_get_function_groups, .set_mux = slpi_pinmux_set_mux, }; static int slpi_config_reg(const struct slpi_pin *pin, unsigned int param, unsigned int *mask, unsigned int *bit) { switch (param) { case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_BUS_HOLD: case PIN_CONFIG_BIAS_PULL_UP: *bit = pin->pull_bit; *mask = 3; break; case PIN_CONFIG_DRIVE_STRENGTH: *bit = pin->drv_bit; *mask = 7; break; case PIN_CONFIG_OUTPUT: case PIN_CONFIG_INPUT_ENABLE: *bit = pin->oe_bit; *mask = 1; break; default: return -EOPNOTSUPP; } return 0; } #define MSM_NO_PULL 0 #define MSM_PULL_DOWN 1 #define MSM_KEEPER 2 #define MSM_PULL_UP 3 static unsigned int slpi_regval_to_drive(u32 val) { return (val + 1) * 2; } static int slpi_config_group_get(struct pinctrl_dev *pctldev, unsigned int pin_index, unsigned long *config) { unsigned int param = pinconf_to_config_param(*config); struct slpi_pin *pin; unsigned int mask; unsigned int arg; unsigned int bit; int ret; u32 val; pin = pctldev->desc->pins[pin_index].drv_data; ret = slpi_config_reg(pin, param, &mask, &bit); if (ret < 0) return ret; val = slpi_read(pin, pin->ctl_reg); arg = (val >> bit) & mask; /* Convert register value to pinconf value */ switch (param) { case PIN_CONFIG_BIAS_DISABLE: arg = arg == MSM_NO_PULL; break; case PIN_CONFIG_BIAS_PULL_DOWN: arg = arg == MSM_PULL_DOWN; break; case PIN_CONFIG_BIAS_BUS_HOLD: arg = arg == MSM_KEEPER; break; case PIN_CONFIG_BIAS_PULL_UP: arg = arg == MSM_PULL_UP; break; case PIN_CONFIG_DRIVE_STRENGTH: arg = slpi_regval_to_drive(arg); break; case PIN_CONFIG_OUTPUT: /* Pin is not output */ if (!arg) return -EINVAL; val = slpi_read(pin, pin->io_reg); arg = !!(val & BIT(pin->in_bit)); break; case PIN_CONFIG_INPUT_ENABLE: /* Pin is output */ if (arg) return -EINVAL; arg = 1; break; default: return -EOPNOTSUPP; } *config = pinconf_to_config_packed(param, arg); return 0; } static int slpi_config_group_set(struct pinctrl_dev *pctldev, unsigned int pin_index, unsigned long *configs, unsigned int num_configs) { struct slpi_pin *pin; unsigned int param; unsigned int mask; unsigned int arg; unsigned int bit; int ret; u32 val; int i; pin = pctldev->desc->pins[pin_index].drv_data; for (i = 0; i < num_configs; i++) { param = pinconf_to_config_param(configs[i]); arg = pinconf_to_config_argument(configs[i]); ret = slpi_config_reg(pin, param, &mask, &bit); if (ret < 0) return ret; /* Convert pinconf values to register values */ switch (param) { case PIN_CONFIG_BIAS_DISABLE: arg = MSM_NO_PULL; break; case PIN_CONFIG_BIAS_PULL_DOWN: arg = MSM_PULL_DOWN; break; case PIN_CONFIG_BIAS_BUS_HOLD: arg = MSM_KEEPER; break; case PIN_CONFIG_BIAS_PULL_UP: arg = MSM_PULL_UP; break; case PIN_CONFIG_DRIVE_STRENGTH: /* Check for invalid values */ if (arg > 16 || arg < 2 || (arg % 2) != 0) arg = -1; else arg = (arg / 2) - 1; break; case PIN_CONFIG_OUTPUT: /* set output value */ val = slpi_read(pin, pin->io_reg); if (arg) val |= BIT(pin->out_bit); else val &= ~BIT(pin->out_bit); slpi_write(val, pin, pin->io_reg); /* enable output */ arg = 1; break; case PIN_CONFIG_INPUT_ENABLE: /* disable output */ arg = 0; break; default: dev_err(pctldev->dev, "Unsupported config parameter: %x\n", param); return -EINVAL; } /* Range-check user-supplied value */ if (arg & ~mask) { dev_err(pctldev->dev, "config %x: %x is invalid\n", param, arg); return -EINVAL; } val = slpi_read(pin, pin->ctl_reg); val &= ~(mask << bit); val |= arg << bit; slpi_write(val, pin, pin->ctl_reg); } return 0; } static const struct pinconf_ops slpi_pinconf_ops = { .is_generic = true, .pin_config_group_get = slpi_config_group_get, .pin_config_group_set = slpi_config_group_set, }; static int slpi_pinctrl_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct pinctrl_dev *pctldev; struct pinctrl_pin_desc *pindesc; struct pinctrl_desc *pctrldesc; struct slpi_pin *pin, *pins; struct resource *res; int ret, npins, i; void __iomem *base; dev_err(dev, "SLPI probe called !!!!!!\n"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) return PTR_ERR(base); ret = of_property_read_u32(dev->of_node, "qcom,num-pins", &npins); if (ret < 0) return ret; pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL); if (!pindesc) return -ENOMEM; WARN_ON(npins > ARRAY_SIZE(slpi_gpio_groups)); pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); if (!pins) return -ENOMEM; pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL); if (!pctrldesc) return -ENOMEM; pctrldesc->pctlops = &slpi_pinctrl_ops; pctrldesc->pmxops = &slpi_pinmux_ops; pctrldesc->confops = &slpi_pinconf_ops; pctrldesc->owner = THIS_MODULE; pctrldesc->name = dev_name(&pdev->dev); pctrldesc->pins = pindesc; pctrldesc->npins = npins; for (i = 0; i < npins; i++, pindesc++) { pin = &pins[i]; pindesc->drv_data = pin; pindesc->number = i; pindesc->name = slpi_gpio_groups[i]; pin->base = base; pin->offset = i * 0x1000; pin->ctl_reg = 0x0; pin->io_reg = 0x4; pin->pull_bit = 0; pin->out_bit = 1; pin->mux_bit = 2; pin->oe_bit = 9; pin->drv_bit = 6; pin->in_bit = 0; } pctldev = devm_pinctrl_register(&pdev->dev, pctrldesc, NULL); if (IS_ERR(pctldev)) { dev_err(dev, "Failed to register pinctrl device\n"); return PTR_ERR(pctldev); } dev_err(dev, "Registered pinctrl SLPI !!!!!!\n"); return 0; } static const struct of_device_id slpi_pinctrl_of_match[] = { { .compatible = "qcom,slpi-pinctrl" }, /* Generic */ { }, }; MODULE_DEVICE_TABLE(of, slpi_pinctrl_of_match); static struct platform_driver slpi_pinctrl_driver = { .driver = { .name = "qcom-slpi-pinctrl", .of_match_table = slpi_pinctrl_of_match, }, .probe = slpi_pinctrl_probe, }; static int __init slpi_pinctrl_init(void) { return platform_driver_register(&slpi_pinctrl_driver); } arch_initcall(slpi_pinctrl_init); static void __exit slpi_pinctrl_exit(void) { platform_driver_unregister(&slpi_pinctrl_driver); } module_exit(slpi_pinctrl_exit); MODULE_DESCRIPTION("QTI SLPI GPIO pin control driver"); MODULE_LICENSE("GPL v2"); Loading
arch/arm64/configs/vendor/gen3auto_GKI.config +3 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,9 @@ CONFIG_UNUSED_KSYMS_WHITELIST="android/abi_gki_aarch64_qcom android/abi_gki_aarc CONFIG_UNUSED_KSYMS_WHITELIST_ONLY=y CONFIG_PINCTRL_SM8150=m CONFIG_PINCTRL_SDMSHRIKE=m CONFIG_PINCTRL_SLPI=m CONFIG_ION_MSM_HEAPS=m CONFIG_QCOM_SECURE_BUFFER=m CONFIG_HEADER_TEST=y CONFIG_HEADERS_INSTALL=y CONFIG_KERNEL_HEADER_TEST=y Loading
arch/arm64/configs/vendor/gen3auto_QGKI.config +1 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ CONFIG_LOCALVERSION="-qgki" CONFIG_DEBUG_FS=y # CONFIG_TRIM_UNUSED_KSYMS is not set CONFIG_REGULATOR_QTI_DEBUG=y CONFIG_ION_POOL_AUTO_REFILL=y # CONFIG_DETECT_HUNG_TASK is not set # CONFIG_ZONE_DMA32 is not set # CONFIG_SOFTLOCKUP_DETECTOR is not set Loading
drivers/pinctrl/qcom/Kconfig +10 −0 Original line number Diff line number Diff line Loading @@ -300,4 +300,14 @@ config PINCTRL_MONACO Say Y here to compile statically, or M here to compile it as a module. If unsure, say N. config PINCTRL_SLPI tristate "Qualcomm Technologies, Inc SLPI pin controller driver" depends on GPIOLIB && OF help Sensor Low Power Island(SLPI) has a Pin controller which can support 14 pin configurations. This is the pinctrl, pinmux and pinconf driver for the SLPI pin controller block. Say Y here to compile statically, or M here to compile it as a module. If unsure, say N. endif
drivers/pinctrl/qcom/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -33,3 +33,4 @@ obj-$(CONFIG_PINCTRL_SCUBA) += pinctrl-scuba.o obj-$(CONFIG_PINCTRL_SDXLEMUR) += pinctrl-sdxlemur.o obj-$(CONFIG_PINCTRL_SDXNIGHTJAR) += pinctrl-sdxnightjar.o obj-$(CONFIG_PINCTRL_MONACO) += pinctrl-monaco.o obj-$(CONFIG_PINCTRL_SLPI) += pinctrl-slpi.o
drivers/pinctrl/qcom/pinctrl-slpi.c 0 → 100644 +457 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include <linux/gpio.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinmux.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/types.h> #include "../core.h" #include "../pinctrl-utils.h" /** * struct slpi_pin - SLPI pin definition * @name: Name of the pin. * @ctl_reg: Offset of the register holding control bits for this group. * @io_reg: Offset of the register holding input/output bits for this group. * @pull_bit: Offset in @ctl_reg for the bias configuration. * @mux_bit: Offset in @ctl_reg for the pinmux function selection. * @drv_bit: Offset in @ctl_reg for the drive strength configuration. * @oe_bit: Offset in @ctl_reg for controlling output enable. * @in_bit: Offset in @io_reg for the input bit value. * @out_bit: Offset in @io_reg for the output bit value. */ struct slpi_pin { void __iomem *base; unsigned int offset; unsigned int ctl_reg; unsigned int io_reg; unsigned int pull_bit:5; unsigned int mux_bit:5; unsigned int drv_bit:5; unsigned int oe_bit:5; unsigned int in_bit:5; unsigned int out_bit:5; }; /* The index of each function in slpi_pin_functions[] array */ enum slpi_pin_func_index { SLPI_PIN_FUNC_INDEX_GPIO = 0x00, SLPI_PIN_FUNC_INDEX_FUNC1 = 0x01, SLPI_PIN_FUNC_INDEX_FUNC2 = 0x02, SLPI_PIN_FUNC_INDEX_FUNC3 = 0x03, SLPI_PIN_FUNC_INDEX_FUNC4 = 0x04, SLPI_PIN_FUNC_INDEX_FUNC5 = 0x05, }; #define SLPI_PIN_FUNC_GPIO "gpio" #define SLPI_PIN_FUNC_FUNC1 "func1" #define SLPI_PIN_FUNC_FUNC2 "func2" #define SLPI_PIN_FUNC_FUNC3 "func3" #define SLPI_PIN_FUNC_FUNC4 "func4" #define SLPI_PIN_FUNC_FUNC5 "func5" static const char *const slpi_gpio_groups[] = { "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", }; static const char *const slpi_pin_functions[] = { [SLPI_PIN_FUNC_INDEX_GPIO] = SLPI_PIN_FUNC_GPIO, [SLPI_PIN_FUNC_INDEX_FUNC1] = SLPI_PIN_FUNC_FUNC1, [SLPI_PIN_FUNC_INDEX_FUNC2] = SLPI_PIN_FUNC_FUNC2, [SLPI_PIN_FUNC_INDEX_FUNC3] = SLPI_PIN_FUNC_FUNC3, [SLPI_PIN_FUNC_INDEX_FUNC4] = SLPI_PIN_FUNC_FUNC4, [SLPI_PIN_FUNC_INDEX_FUNC5] = SLPI_PIN_FUNC_FUNC5, }; static unsigned int slpi_read(struct slpi_pin *pin, u32 reg) { return readl_relaxed(pin->base + pin->offset + reg); } static void slpi_write(u32 val, struct slpi_pin *pin, u32 reg) { return writel_relaxed(val, pin->base + pin->offset + reg); } static int slpi_get_groups_count(struct pinctrl_dev *pctldev) { /* Every PIN is a group */ return pctldev->desc->npins; } static const char *slpi_get_group_name(struct pinctrl_dev *pctldev, unsigned int pin) { return pctldev->desc->pins[pin].name; } static int slpi_get_group_pins(struct pinctrl_dev *pctldev, unsigned int pin, const unsigned int **pins, unsigned int *num_pins) { *pins = &pctldev->desc->pins[pin].number; *num_pins = 1; return 0; } static const struct pinctrl_ops slpi_pinctrl_ops = { .get_groups_count = slpi_get_groups_count, .get_group_name = slpi_get_group_name, .get_group_pins = slpi_get_group_pins, .dt_node_to_map = pinconf_generic_dt_node_to_map_group, .dt_free_map = pinctrl_utils_free_map, }; static int slpi_get_functions_count(struct pinctrl_dev *pctldev) { return ARRAY_SIZE(slpi_pin_functions); } static const char *slpi_get_function_name(struct pinctrl_dev *pctldev, unsigned int function) { return slpi_pin_functions[function]; } static int slpi_get_function_groups(struct pinctrl_dev *pctldev, unsigned int function, const char * const **groups, unsigned int * const num_groups) { *groups = slpi_gpio_groups; *num_groups = pctldev->desc->npins; return 0; } static int slpi_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function, unsigned int pin_index) { struct slpi_pin *pin; u32 val; pin = pctldev->desc->pins[pin_index].drv_data; if (WARN_ON(function >= ARRAY_SIZE(slpi_pin_functions))) return -EINVAL; val = slpi_read(pin, pin->ctl_reg); val &= ~(0x7 << pin->mux_bit); val |= function << pin->mux_bit; slpi_write(val, pin, pin->ctl_reg); return 0; } static const struct pinmux_ops slpi_pinmux_ops = { .get_functions_count = slpi_get_functions_count, .get_function_name = slpi_get_function_name, .get_function_groups = slpi_get_function_groups, .set_mux = slpi_pinmux_set_mux, }; static int slpi_config_reg(const struct slpi_pin *pin, unsigned int param, unsigned int *mask, unsigned int *bit) { switch (param) { case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_BUS_HOLD: case PIN_CONFIG_BIAS_PULL_UP: *bit = pin->pull_bit; *mask = 3; break; case PIN_CONFIG_DRIVE_STRENGTH: *bit = pin->drv_bit; *mask = 7; break; case PIN_CONFIG_OUTPUT: case PIN_CONFIG_INPUT_ENABLE: *bit = pin->oe_bit; *mask = 1; break; default: return -EOPNOTSUPP; } return 0; } #define MSM_NO_PULL 0 #define MSM_PULL_DOWN 1 #define MSM_KEEPER 2 #define MSM_PULL_UP 3 static unsigned int slpi_regval_to_drive(u32 val) { return (val + 1) * 2; } static int slpi_config_group_get(struct pinctrl_dev *pctldev, unsigned int pin_index, unsigned long *config) { unsigned int param = pinconf_to_config_param(*config); struct slpi_pin *pin; unsigned int mask; unsigned int arg; unsigned int bit; int ret; u32 val; pin = pctldev->desc->pins[pin_index].drv_data; ret = slpi_config_reg(pin, param, &mask, &bit); if (ret < 0) return ret; val = slpi_read(pin, pin->ctl_reg); arg = (val >> bit) & mask; /* Convert register value to pinconf value */ switch (param) { case PIN_CONFIG_BIAS_DISABLE: arg = arg == MSM_NO_PULL; break; case PIN_CONFIG_BIAS_PULL_DOWN: arg = arg == MSM_PULL_DOWN; break; case PIN_CONFIG_BIAS_BUS_HOLD: arg = arg == MSM_KEEPER; break; case PIN_CONFIG_BIAS_PULL_UP: arg = arg == MSM_PULL_UP; break; case PIN_CONFIG_DRIVE_STRENGTH: arg = slpi_regval_to_drive(arg); break; case PIN_CONFIG_OUTPUT: /* Pin is not output */ if (!arg) return -EINVAL; val = slpi_read(pin, pin->io_reg); arg = !!(val & BIT(pin->in_bit)); break; case PIN_CONFIG_INPUT_ENABLE: /* Pin is output */ if (arg) return -EINVAL; arg = 1; break; default: return -EOPNOTSUPP; } *config = pinconf_to_config_packed(param, arg); return 0; } static int slpi_config_group_set(struct pinctrl_dev *pctldev, unsigned int pin_index, unsigned long *configs, unsigned int num_configs) { struct slpi_pin *pin; unsigned int param; unsigned int mask; unsigned int arg; unsigned int bit; int ret; u32 val; int i; pin = pctldev->desc->pins[pin_index].drv_data; for (i = 0; i < num_configs; i++) { param = pinconf_to_config_param(configs[i]); arg = pinconf_to_config_argument(configs[i]); ret = slpi_config_reg(pin, param, &mask, &bit); if (ret < 0) return ret; /* Convert pinconf values to register values */ switch (param) { case PIN_CONFIG_BIAS_DISABLE: arg = MSM_NO_PULL; break; case PIN_CONFIG_BIAS_PULL_DOWN: arg = MSM_PULL_DOWN; break; case PIN_CONFIG_BIAS_BUS_HOLD: arg = MSM_KEEPER; break; case PIN_CONFIG_BIAS_PULL_UP: arg = MSM_PULL_UP; break; case PIN_CONFIG_DRIVE_STRENGTH: /* Check for invalid values */ if (arg > 16 || arg < 2 || (arg % 2) != 0) arg = -1; else arg = (arg / 2) - 1; break; case PIN_CONFIG_OUTPUT: /* set output value */ val = slpi_read(pin, pin->io_reg); if (arg) val |= BIT(pin->out_bit); else val &= ~BIT(pin->out_bit); slpi_write(val, pin, pin->io_reg); /* enable output */ arg = 1; break; case PIN_CONFIG_INPUT_ENABLE: /* disable output */ arg = 0; break; default: dev_err(pctldev->dev, "Unsupported config parameter: %x\n", param); return -EINVAL; } /* Range-check user-supplied value */ if (arg & ~mask) { dev_err(pctldev->dev, "config %x: %x is invalid\n", param, arg); return -EINVAL; } val = slpi_read(pin, pin->ctl_reg); val &= ~(mask << bit); val |= arg << bit; slpi_write(val, pin, pin->ctl_reg); } return 0; } static const struct pinconf_ops slpi_pinconf_ops = { .is_generic = true, .pin_config_group_get = slpi_config_group_get, .pin_config_group_set = slpi_config_group_set, }; static int slpi_pinctrl_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct pinctrl_dev *pctldev; struct pinctrl_pin_desc *pindesc; struct pinctrl_desc *pctrldesc; struct slpi_pin *pin, *pins; struct resource *res; int ret, npins, i; void __iomem *base; dev_err(dev, "SLPI probe called !!!!!!\n"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) return PTR_ERR(base); ret = of_property_read_u32(dev->of_node, "qcom,num-pins", &npins); if (ret < 0) return ret; pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL); if (!pindesc) return -ENOMEM; WARN_ON(npins > ARRAY_SIZE(slpi_gpio_groups)); pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL); if (!pins) return -ENOMEM; pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL); if (!pctrldesc) return -ENOMEM; pctrldesc->pctlops = &slpi_pinctrl_ops; pctrldesc->pmxops = &slpi_pinmux_ops; pctrldesc->confops = &slpi_pinconf_ops; pctrldesc->owner = THIS_MODULE; pctrldesc->name = dev_name(&pdev->dev); pctrldesc->pins = pindesc; pctrldesc->npins = npins; for (i = 0; i < npins; i++, pindesc++) { pin = &pins[i]; pindesc->drv_data = pin; pindesc->number = i; pindesc->name = slpi_gpio_groups[i]; pin->base = base; pin->offset = i * 0x1000; pin->ctl_reg = 0x0; pin->io_reg = 0x4; pin->pull_bit = 0; pin->out_bit = 1; pin->mux_bit = 2; pin->oe_bit = 9; pin->drv_bit = 6; pin->in_bit = 0; } pctldev = devm_pinctrl_register(&pdev->dev, pctrldesc, NULL); if (IS_ERR(pctldev)) { dev_err(dev, "Failed to register pinctrl device\n"); return PTR_ERR(pctldev); } dev_err(dev, "Registered pinctrl SLPI !!!!!!\n"); return 0; } static const struct of_device_id slpi_pinctrl_of_match[] = { { .compatible = "qcom,slpi-pinctrl" }, /* Generic */ { }, }; MODULE_DEVICE_TABLE(of, slpi_pinctrl_of_match); static struct platform_driver slpi_pinctrl_driver = { .driver = { .name = "qcom-slpi-pinctrl", .of_match_table = slpi_pinctrl_of_match, }, .probe = slpi_pinctrl_probe, }; static int __init slpi_pinctrl_init(void) { return platform_driver_register(&slpi_pinctrl_driver); } arch_initcall(slpi_pinctrl_init); static void __exit slpi_pinctrl_exit(void) { platform_driver_unregister(&slpi_pinctrl_driver); } module_exit(slpi_pinctrl_exit); MODULE_DESCRIPTION("QTI SLPI GPIO pin control driver"); MODULE_LICENSE("GPL v2");