mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-10 06:09:23 -04:00
pinctrl: qcom: add pinctrl driver for SLPI
Sensor Low Power Island (SLPI) has a Pin controller which can support 14 pin configurations, add pinctrl driver to handle pins of SLPI from APPS. The snapshot of this driver is taken from msm-4.14 commit "e4483b491ed60". Change-Id: Id44ccb34f23a285edf0eaccb501ba4d2296a7b87 Signed-off-by: Vivek Kumar <vivekuma@codeaurora.org>
This commit is contained in:
parent
aa860b5b17
commit
1f46e62d77
3 changed files with 468 additions and 0 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
457
drivers/pinctrl/qcom/pinctrl-slpi.c
Normal file
457
drivers/pinctrl/qcom/pinctrl-slpi.c
Normal file
|
|
@ -0,0 +1,457 @@
|
|||
// 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…
Reference in a new issue