brintos

brintos / linux-shallow public Read only

0
0
Text · 16.2 KiB · 0d8c75c Raw
599 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * ams AS3722 pin control and GPIO driver.4 *5 * Copyright (c) 2013, NVIDIA Corporation.6 *7 * Author: Laxman Dewangan <ldewangan@nvidia.com>8 */9 10#include <linux/delay.h>11#include <linux/gpio/driver.h>12#include <linux/kernel.h>13#include <linux/mod_devicetable.h>14#include <linux/module.h>15#include <linux/mfd/as3722.h>16#include <linux/platform_device.h>17#include <linux/pm.h>18#include <linux/property.h>19#include <linux/slab.h>20 21#include <linux/pinctrl/consumer.h>22#include <linux/pinctrl/machine.h>23#include <linux/pinctrl/pinctrl.h>24#include <linux/pinctrl/pinconf-generic.h>25#include <linux/pinctrl/pinconf.h>26#include <linux/pinctrl/pinmux.h>27 28#include "core.h"29#include "pinconf.h"30#include "pinctrl-utils.h"31 32#define AS3722_PIN_GPIO0		033#define AS3722_PIN_GPIO1		134#define AS3722_PIN_GPIO2		235#define AS3722_PIN_GPIO3		336#define AS3722_PIN_GPIO4		437#define AS3722_PIN_GPIO5		538#define AS3722_PIN_GPIO6		639#define AS3722_PIN_GPIO7		740#define AS3722_PIN_NUM			(AS3722_PIN_GPIO7 + 1)41 42#define AS3722_GPIO_MODE_PULL_UP           BIT(PIN_CONFIG_BIAS_PULL_UP)43#define AS3722_GPIO_MODE_PULL_DOWN         BIT(PIN_CONFIG_BIAS_PULL_DOWN)44#define AS3722_GPIO_MODE_HIGH_IMPED        BIT(PIN_CONFIG_BIAS_HIGH_IMPEDANCE)45#define AS3722_GPIO_MODE_OPEN_DRAIN        BIT(PIN_CONFIG_DRIVE_OPEN_DRAIN)46 47struct as3722_pin_function {48	const char *name;49	const char * const *groups;50	unsigned ngroups;51	int mux_option;52};53 54struct as3722_gpio_pin_control {55	unsigned mode_prop;56	int io_function;57};58 59struct as3722_pingroup {60	const char *name;61	const unsigned pins[1];62	unsigned npins;63};64 65struct as3722_pctrl_info {66	struct device *dev;67	struct pinctrl_dev *pctl;68	struct as3722 *as3722;69	struct gpio_chip gpio_chip;70	int pins_current_opt[AS3722_PIN_NUM];71	const struct as3722_pin_function *functions;72	unsigned num_functions;73	const struct as3722_pingroup *pin_groups;74	int num_pin_groups;75	const struct pinctrl_pin_desc *pins;76	unsigned num_pins;77	struct as3722_gpio_pin_control gpio_control[AS3722_PIN_NUM];78};79 80static const struct pinctrl_pin_desc as3722_pins_desc[] = {81	PINCTRL_PIN(AS3722_PIN_GPIO0, "gpio0"),82	PINCTRL_PIN(AS3722_PIN_GPIO1, "gpio1"),83	PINCTRL_PIN(AS3722_PIN_GPIO2, "gpio2"),84	PINCTRL_PIN(AS3722_PIN_GPIO3, "gpio3"),85	PINCTRL_PIN(AS3722_PIN_GPIO4, "gpio4"),86	PINCTRL_PIN(AS3722_PIN_GPIO5, "gpio5"),87	PINCTRL_PIN(AS3722_PIN_GPIO6, "gpio6"),88	PINCTRL_PIN(AS3722_PIN_GPIO7, "gpio7"),89};90 91static const char * const gpio_groups[] = {92	"gpio0",93	"gpio1",94	"gpio2",95	"gpio3",96	"gpio4",97	"gpio5",98	"gpio6",99	"gpio7",100};101 102enum as3722_pinmux_option {103	AS3722_PINMUX_GPIO			= 0,104	AS3722_PINMUX_INTERRUPT_OUT		= 1,105	AS3722_PINMUX_VSUB_VBAT_UNDEB_LOW_OUT	= 2,106	AS3722_PINMUX_GPIO_INTERRUPT		= 3,107	AS3722_PINMUX_PWM_INPUT			= 4,108	AS3722_PINMUX_VOLTAGE_IN_STBY		= 5,109	AS3722_PINMUX_OC_PG_SD0			= 6,110	AS3722_PINMUX_PG_OUT			= 7,111	AS3722_PINMUX_CLK32K_OUT		= 8,112	AS3722_PINMUX_WATCHDOG_INPUT		= 9,113	AS3722_PINMUX_SOFT_RESET_IN		= 11,114	AS3722_PINMUX_PWM_OUTPUT		= 12,115	AS3722_PINMUX_VSUB_VBAT_LOW_DEB_OUT	= 13,116	AS3722_PINMUX_OC_PG_SD6			= 14,117};118 119#define FUNCTION_GROUP(fname, mux)			\120	{						\121		.name = #fname,				\122		.groups = gpio_groups,			\123		.ngroups = ARRAY_SIZE(gpio_groups),	\124		.mux_option = AS3722_PINMUX_##mux,	\125	}126 127static const struct as3722_pin_function as3722_pin_function[] = {128	FUNCTION_GROUP(gpio, GPIO),129	FUNCTION_GROUP(interrupt-out, INTERRUPT_OUT),130	FUNCTION_GROUP(gpio-in-interrupt, GPIO_INTERRUPT),131	FUNCTION_GROUP(vsup-vbat-low-undebounce-out, VSUB_VBAT_UNDEB_LOW_OUT),132	FUNCTION_GROUP(vsup-vbat-low-debounce-out, VSUB_VBAT_LOW_DEB_OUT),133	FUNCTION_GROUP(voltage-in-standby, VOLTAGE_IN_STBY),134	FUNCTION_GROUP(oc-pg-sd0, OC_PG_SD0),135	FUNCTION_GROUP(oc-pg-sd6, OC_PG_SD6),136	FUNCTION_GROUP(powergood-out, PG_OUT),137	FUNCTION_GROUP(pwm-in, PWM_INPUT),138	FUNCTION_GROUP(pwm-out, PWM_OUTPUT),139	FUNCTION_GROUP(clk32k-out, CLK32K_OUT),140	FUNCTION_GROUP(watchdog-in, WATCHDOG_INPUT),141	FUNCTION_GROUP(soft-reset-in, SOFT_RESET_IN),142};143 144#define AS3722_PINGROUP(pg_name, pin_id) \145	{								\146		.name = #pg_name,					\147		.pins = {AS3722_PIN_##pin_id},				\148		.npins = 1,						\149	}150 151static const struct as3722_pingroup as3722_pingroups[] = {152	AS3722_PINGROUP(gpio0,	GPIO0),153	AS3722_PINGROUP(gpio1,	GPIO1),154	AS3722_PINGROUP(gpio2,	GPIO2),155	AS3722_PINGROUP(gpio3,	GPIO3),156	AS3722_PINGROUP(gpio4,	GPIO4),157	AS3722_PINGROUP(gpio5,	GPIO5),158	AS3722_PINGROUP(gpio6,	GPIO6),159	AS3722_PINGROUP(gpio7,	GPIO7),160};161 162static int as3722_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)163{164	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);165 166	return as_pci->num_pin_groups;167}168 169static const char *as3722_pinctrl_get_group_name(struct pinctrl_dev *pctldev,170		unsigned group)171{172	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);173 174	return as_pci->pin_groups[group].name;175}176 177static int as3722_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,178		unsigned group, const unsigned **pins, unsigned *num_pins)179{180	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);181 182	*pins = as_pci->pin_groups[group].pins;183	*num_pins = as_pci->pin_groups[group].npins;184	return 0;185}186 187static const struct pinctrl_ops as3722_pinctrl_ops = {188	.get_groups_count = as3722_pinctrl_get_groups_count,189	.get_group_name = as3722_pinctrl_get_group_name,190	.get_group_pins = as3722_pinctrl_get_group_pins,191	.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,192	.dt_free_map = pinctrl_utils_free_map,193};194 195static int as3722_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)196{197	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);198 199	return as_pci->num_functions;200}201 202static const char *as3722_pinctrl_get_func_name(struct pinctrl_dev *pctldev,203			unsigned function)204{205	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);206 207	return as_pci->functions[function].name;208}209 210static int as3722_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,211		unsigned function, const char * const **groups,212		unsigned * const num_groups)213{214	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);215 216	*groups = as_pci->functions[function].groups;217	*num_groups = as_pci->functions[function].ngroups;218	return 0;219}220 221static int as3722_pinctrl_set(struct pinctrl_dev *pctldev, unsigned function,222		unsigned group)223{224	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);225	int gpio_cntr_reg = AS3722_GPIOn_CONTROL_REG(group);226	u8 val = AS3722_GPIO_IOSF_VAL(as_pci->functions[function].mux_option);227	int ret;228 229	dev_dbg(as_pci->dev, "%s(): GPIO %u pin to function %u and val %u\n",230		__func__, group, function, val);231 232	ret = as3722_update_bits(as_pci->as3722, gpio_cntr_reg,233			AS3722_GPIO_IOSF_MASK, val);234	if (ret < 0) {235		dev_err(as_pci->dev, "GPIO%d_CTRL_REG update failed %d\n",236			group, ret);237		return ret;238	}239	as_pci->gpio_control[group].io_function = function;240 241	switch (val) {242	case AS3722_GPIO_IOSF_SD0_OUT:243	case AS3722_GPIO_IOSF_PWR_GOOD_OUT:244	case AS3722_GPIO_IOSF_Q32K_OUT:245	case AS3722_GPIO_IOSF_PWM_OUT:246	case AS3722_GPIO_IOSF_SD6_LOW_VOLT_LOW:247		ret = as3722_update_bits(as_pci->as3722, gpio_cntr_reg,248			AS3722_GPIO_MODE_MASK, AS3722_GPIO_MODE_OUTPUT_VDDH);249		if (ret < 0) {250			dev_err(as_pci->dev, "GPIO%d_CTRL update failed %d\n",251				group, ret);252			return ret;253		}254		as_pci->gpio_control[group].mode_prop =255				AS3722_GPIO_MODE_OUTPUT_VDDH;256		break;257	default:258		break;259	}260	return ret;261}262 263static int as3722_pinctrl_gpio_get_mode(unsigned gpio_mode_prop, bool input)264{265	if (gpio_mode_prop & AS3722_GPIO_MODE_HIGH_IMPED)266		return -EINVAL;267 268	if (gpio_mode_prop & AS3722_GPIO_MODE_OPEN_DRAIN) {269		if (gpio_mode_prop & AS3722_GPIO_MODE_PULL_UP)270			return AS3722_GPIO_MODE_IO_OPEN_DRAIN_PULL_UP;271		return AS3722_GPIO_MODE_IO_OPEN_DRAIN;272	}273	if (input) {274		if (gpio_mode_prop & AS3722_GPIO_MODE_PULL_UP)275			return AS3722_GPIO_MODE_INPUT_PULL_UP;276		else if (gpio_mode_prop & AS3722_GPIO_MODE_PULL_DOWN)277			return AS3722_GPIO_MODE_INPUT_PULL_DOWN;278		return AS3722_GPIO_MODE_INPUT;279	}280	if (gpio_mode_prop & AS3722_GPIO_MODE_PULL_DOWN)281		return AS3722_GPIO_MODE_OUTPUT_VDDL;282	return AS3722_GPIO_MODE_OUTPUT_VDDH;283}284 285static int as3722_pinctrl_gpio_request_enable(struct pinctrl_dev *pctldev,286		struct pinctrl_gpio_range *range, unsigned offset)287{288	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);289 290	if (as_pci->gpio_control[offset].io_function)291		return -EBUSY;292	return 0;293}294 295static int as3722_pinctrl_gpio_set_direction(struct pinctrl_dev *pctldev,296		struct pinctrl_gpio_range *range, unsigned offset, bool input)297{298	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);299	struct as3722 *as3722 = as_pci->as3722;300	int mode;301 302	mode = as3722_pinctrl_gpio_get_mode(303			as_pci->gpio_control[offset].mode_prop, input);304	if (mode < 0) {305		dev_err(as_pci->dev, "%s direction for GPIO %d not supported\n",306			(input) ? "Input" : "Output", offset);307		return mode;308	}309 310	return as3722_update_bits(as3722, AS3722_GPIOn_CONTROL_REG(offset),311				AS3722_GPIO_MODE_MASK, mode);312}313 314static const struct pinmux_ops as3722_pinmux_ops = {315	.get_functions_count	= as3722_pinctrl_get_funcs_count,316	.get_function_name	= as3722_pinctrl_get_func_name,317	.get_function_groups	= as3722_pinctrl_get_func_groups,318	.set_mux		= as3722_pinctrl_set,319	.gpio_request_enable	= as3722_pinctrl_gpio_request_enable,320	.gpio_set_direction	= as3722_pinctrl_gpio_set_direction,321};322 323static int as3722_pinconf_get(struct pinctrl_dev *pctldev,324			unsigned pin, unsigned long *config)325{326	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);327	enum pin_config_param param = pinconf_to_config_param(*config);328	int arg = 0;329	u16 prop;330 331	switch (param) {332	case PIN_CONFIG_BIAS_DISABLE:333		prop = AS3722_GPIO_MODE_PULL_UP |334				AS3722_GPIO_MODE_PULL_DOWN;335		if (!(as_pci->gpio_control[pin].mode_prop & prop))336			arg = 1;337		prop = 0;338		break;339 340	case PIN_CONFIG_BIAS_PULL_UP:341		prop = AS3722_GPIO_MODE_PULL_UP;342		break;343 344	case PIN_CONFIG_BIAS_PULL_DOWN:345		prop = AS3722_GPIO_MODE_PULL_DOWN;346		break;347 348	case PIN_CONFIG_DRIVE_OPEN_DRAIN:349		prop = AS3722_GPIO_MODE_OPEN_DRAIN;350		break;351 352	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:353		prop = AS3722_GPIO_MODE_HIGH_IMPED;354		break;355 356	default:357		dev_err(as_pci->dev, "Properties not supported\n");358		return -ENOTSUPP;359	}360 361	if (as_pci->gpio_control[pin].mode_prop & prop)362		arg = 1;363 364	*config = pinconf_to_config_packed(param, (u16)arg);365	return 0;366}367 368static int as3722_pinconf_set(struct pinctrl_dev *pctldev,369			unsigned pin, unsigned long *configs,370			unsigned num_configs)371{372	struct as3722_pctrl_info *as_pci = pinctrl_dev_get_drvdata(pctldev);373	enum pin_config_param param;374	int mode_prop;375	int i;376 377	for (i = 0; i < num_configs; i++) {378		param = pinconf_to_config_param(configs[i]);379		mode_prop = as_pci->gpio_control[pin].mode_prop;380 381		switch (param) {382		case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:383			break;384 385		case PIN_CONFIG_BIAS_DISABLE:386			mode_prop &= ~(AS3722_GPIO_MODE_PULL_UP |387					AS3722_GPIO_MODE_PULL_DOWN);388			break;389		case PIN_CONFIG_BIAS_PULL_UP:390			mode_prop |= AS3722_GPIO_MODE_PULL_UP;391			break;392 393		case PIN_CONFIG_BIAS_PULL_DOWN:394			mode_prop |= AS3722_GPIO_MODE_PULL_DOWN;395			break;396 397		case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:398			mode_prop |= AS3722_GPIO_MODE_HIGH_IMPED;399			break;400 401		case PIN_CONFIG_DRIVE_OPEN_DRAIN:402			mode_prop |= AS3722_GPIO_MODE_OPEN_DRAIN;403			break;404 405		default:406			dev_err(as_pci->dev, "Properties not supported\n");407			return -ENOTSUPP;408		}409 410		as_pci->gpio_control[pin].mode_prop = mode_prop;411	}412	return 0;413}414 415static const struct pinconf_ops as3722_pinconf_ops = {416	.pin_config_get = as3722_pinconf_get,417	.pin_config_set = as3722_pinconf_set,418};419 420static struct pinctrl_desc as3722_pinctrl_desc = {421	.pctlops = &as3722_pinctrl_ops,422	.pmxops = &as3722_pinmux_ops,423	.confops = &as3722_pinconf_ops,424	.owner = THIS_MODULE,425};426 427static int as3722_gpio_get(struct gpio_chip *chip, unsigned offset)428{429	struct as3722_pctrl_info *as_pci = gpiochip_get_data(chip);430	struct as3722 *as3722 = as_pci->as3722;431	int ret;432	u32 reg;433	u32 control;434	u32 val;435	int mode;436	int invert_enable;437 438	ret = as3722_read(as3722, AS3722_GPIOn_CONTROL_REG(offset), &control);439	if (ret < 0) {440		dev_err(as_pci->dev,441			"GPIO_CONTROL%d_REG read failed: %d\n", offset, ret);442		return ret;443	}444 445	invert_enable = !!(control & AS3722_GPIO_INV);446	mode = control & AS3722_GPIO_MODE_MASK;447	switch (mode) {448	case AS3722_GPIO_MODE_INPUT:449	case AS3722_GPIO_MODE_INPUT_PULL_UP:450	case AS3722_GPIO_MODE_INPUT_PULL_DOWN:451	case AS3722_GPIO_MODE_IO_OPEN_DRAIN:452	case AS3722_GPIO_MODE_IO_OPEN_DRAIN_PULL_UP:453		reg = AS3722_GPIO_SIGNAL_IN_REG;454		break;455	case AS3722_GPIO_MODE_OUTPUT_VDDH:456	case AS3722_GPIO_MODE_OUTPUT_VDDL:457		reg = AS3722_GPIO_SIGNAL_OUT_REG;458		break;459	default:460		return -EINVAL;461	}462 463	ret = as3722_read(as3722, reg, &val);464	if (ret < 0) {465		dev_err(as_pci->dev,466			"GPIO_SIGNAL_IN_REG read failed: %d\n", ret);467		return ret;468	}469 470	val = !!(val & AS3722_GPIOn_SIGNAL(offset));471	return (invert_enable) ? !val : val;472}473 474static void as3722_gpio_set(struct gpio_chip *chip, unsigned offset,475		int value)476{477	struct as3722_pctrl_info *as_pci = gpiochip_get_data(chip);478	struct as3722 *as3722 = as_pci->as3722;479	int en_invert;480	u32 val;481	int ret;482 483	ret = as3722_read(as3722, AS3722_GPIOn_CONTROL_REG(offset), &val);484	if (ret < 0) {485		dev_err(as_pci->dev,486			"GPIO_CONTROL%d_REG read failed: %d\n", offset, ret);487		return;488	}489	en_invert = !!(val & AS3722_GPIO_INV);490 491	if (value)492		val = (en_invert) ? 0 : AS3722_GPIOn_SIGNAL(offset);493	else494		val = (en_invert) ? AS3722_GPIOn_SIGNAL(offset) : 0;495 496	ret = as3722_update_bits(as3722, AS3722_GPIO_SIGNAL_OUT_REG,497			AS3722_GPIOn_SIGNAL(offset), val);498	if (ret < 0)499		dev_err(as_pci->dev,500			"GPIO_SIGNAL_OUT_REG update failed: %d\n", ret);501}502 503static int as3722_gpio_direction_output(struct gpio_chip *chip,504		unsigned offset, int value)505{506	as3722_gpio_set(chip, offset, value);507	return pinctrl_gpio_direction_output(chip, offset);508}509 510static int as3722_gpio_to_irq(struct gpio_chip *chip, unsigned offset)511{512	struct as3722_pctrl_info *as_pci = gpiochip_get_data(chip);513 514	return as3722_irq_get_virq(as_pci->as3722, offset);515}516 517static const struct gpio_chip as3722_gpio_chip = {518	.label			= "as3722-gpio",519	.owner			= THIS_MODULE,520	.request		= gpiochip_generic_request,521	.free			= gpiochip_generic_free,522	.get			= as3722_gpio_get,523	.set			= as3722_gpio_set,524	.direction_input	= pinctrl_gpio_direction_input,525	.direction_output	= as3722_gpio_direction_output,526	.to_irq			= as3722_gpio_to_irq,527	.can_sleep		= true,528	.ngpio			= AS3722_PIN_NUM,529	.base			= -1,530};531 532static int as3722_pinctrl_probe(struct platform_device *pdev)533{534	struct as3722_pctrl_info *as_pci;535	int ret;536 537	device_set_node(&pdev->dev, dev_fwnode(pdev->dev.parent));538 539	as_pci = devm_kzalloc(&pdev->dev, sizeof(*as_pci), GFP_KERNEL);540	if (!as_pci)541		return -ENOMEM;542 543	as_pci->dev = &pdev->dev;544	as_pci->as3722 = dev_get_drvdata(pdev->dev.parent);545 546	as_pci->pins = as3722_pins_desc;547	as_pci->num_pins = ARRAY_SIZE(as3722_pins_desc);548	as_pci->functions = as3722_pin_function;549	as_pci->num_functions = ARRAY_SIZE(as3722_pin_function);550	as_pci->pin_groups = as3722_pingroups;551	as_pci->num_pin_groups = ARRAY_SIZE(as3722_pingroups);552	as3722_pinctrl_desc.name = dev_name(&pdev->dev);553	as3722_pinctrl_desc.pins = as3722_pins_desc;554	as3722_pinctrl_desc.npins = ARRAY_SIZE(as3722_pins_desc);555	as_pci->pctl = devm_pinctrl_register(&pdev->dev, &as3722_pinctrl_desc,556					     as_pci);557	if (IS_ERR(as_pci->pctl)) {558		dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");559		return PTR_ERR(as_pci->pctl);560	}561 562	as_pci->gpio_chip = as3722_gpio_chip;563	as_pci->gpio_chip.parent = &pdev->dev;564	ret = devm_gpiochip_add_data(&pdev->dev, &as_pci->gpio_chip, as_pci);565	if (ret < 0) {566		dev_err(&pdev->dev, "Couldn't register gpiochip, %d\n", ret);567		return ret;568	}569 570	ret = gpiochip_add_pin_range(&as_pci->gpio_chip, dev_name(&pdev->dev),571				0, 0, AS3722_PIN_NUM);572	if (ret < 0) {573		dev_err(&pdev->dev, "Couldn't add pin range, %d\n", ret);574		return ret;575	}576 577	return 0;578}579 580static const struct of_device_id as3722_pinctrl_of_match[] = {581	{ .compatible = "ams,as3722-pinctrl", },582	{ },583};584MODULE_DEVICE_TABLE(of, as3722_pinctrl_of_match);585 586static struct platform_driver as3722_pinctrl_driver = {587	.driver = {588		.name = "as3722-pinctrl",589		.of_match_table = as3722_pinctrl_of_match,590	},591	.probe = as3722_pinctrl_probe,592};593module_platform_driver(as3722_pinctrl_driver);594 595MODULE_ALIAS("platform:as3722-pinctrl");596MODULE_DESCRIPTION("AS3722 pin control and GPIO driver");597MODULE_AUTHOR("Laxman Dewangan<ldewangan@nvidia.com>");598MODULE_LICENSE("GPL v2");599