brintos

brintos / linux-shallow public Read only

0
0
Text · 23.4 KiB · 3aee683 Raw
960 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2015, Sony Mobile Communications AB.4 * Copyright (c) 2013, The Linux Foundation. All rights reserved.5 */6 7#include <linux/gpio/driver.h>8#include <linux/interrupt.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/of_irq.h>12#include <linux/platform_device.h>13#include <linux/regmap.h>14#include <linux/seq_file.h>15#include <linux/slab.h>16 17#include <linux/pinctrl/pinconf-generic.h>18#include <linux/pinctrl/pinconf.h>19#include <linux/pinctrl/pinctrl.h>20#include <linux/pinctrl/pinmux.h>21 22#include <dt-bindings/pinctrl/qcom,pmic-mpp.h>23 24#include "../core.h"25#include "../pinctrl-utils.h"26 27/* MPP registers */28#define SSBI_REG_ADDR_MPP_BASE		0x5029#define SSBI_REG_ADDR_MPP(n)		(SSBI_REG_ADDR_MPP_BASE + n)30 31/* MPP Type: type */32#define PM8XXX_MPP_TYPE_D_INPUT         033#define PM8XXX_MPP_TYPE_D_OUTPUT        134#define PM8XXX_MPP_TYPE_D_BI_DIR        235#define PM8XXX_MPP_TYPE_A_INPUT         336#define PM8XXX_MPP_TYPE_A_OUTPUT        437#define PM8XXX_MPP_TYPE_SINK            538#define PM8XXX_MPP_TYPE_DTEST_SINK      639#define PM8XXX_MPP_TYPE_DTEST_OUTPUT    740 41/* Digital Input: control */42#define PM8XXX_MPP_DIN_TO_INT           043#define PM8XXX_MPP_DIN_TO_DBUS1         144#define PM8XXX_MPP_DIN_TO_DBUS2         245#define PM8XXX_MPP_DIN_TO_DBUS3         346 47/* Digital Output: control */48#define PM8XXX_MPP_DOUT_CTRL_LOW        049#define PM8XXX_MPP_DOUT_CTRL_HIGH       150#define PM8XXX_MPP_DOUT_CTRL_MPP        251#define PM8XXX_MPP_DOUT_CTRL_INV_MPP    352 53/* Bidirectional: control */54#define PM8XXX_MPP_BI_PULLUP_1KOHM      055#define PM8XXX_MPP_BI_PULLUP_OPEN       156#define PM8XXX_MPP_BI_PULLUP_10KOHM     257#define PM8XXX_MPP_BI_PULLUP_30KOHM     358 59/* Analog Output: control */60#define PM8XXX_MPP_AOUT_CTRL_DISABLE            061#define PM8XXX_MPP_AOUT_CTRL_ENABLE             162#define PM8XXX_MPP_AOUT_CTRL_MPP_HIGH_EN        263#define PM8XXX_MPP_AOUT_CTRL_MPP_LOW_EN         364 65/* Current Sink: control */66#define PM8XXX_MPP_CS_CTRL_DISABLE      067#define PM8XXX_MPP_CS_CTRL_ENABLE       168#define PM8XXX_MPP_CS_CTRL_MPP_HIGH_EN  269#define PM8XXX_MPP_CS_CTRL_MPP_LOW_EN   370 71/* DTEST Current Sink: control */72#define PM8XXX_MPP_DTEST_CS_CTRL_EN1    073#define PM8XXX_MPP_DTEST_CS_CTRL_EN2    174#define PM8XXX_MPP_DTEST_CS_CTRL_EN3    275#define PM8XXX_MPP_DTEST_CS_CTRL_EN4    376 77/* DTEST Digital Output: control */78#define PM8XXX_MPP_DTEST_DBUS1          079#define PM8XXX_MPP_DTEST_DBUS2          180#define PM8XXX_MPP_DTEST_DBUS3          281#define PM8XXX_MPP_DTEST_DBUS4          382 83/* custom pinconf parameters */84#define PM8XXX_CONFIG_AMUX		(PIN_CONFIG_END + 1)85#define PM8XXX_CONFIG_DTEST_SELECTOR	(PIN_CONFIG_END + 2)86#define PM8XXX_CONFIG_ALEVEL		(PIN_CONFIG_END + 3)87#define PM8XXX_CONFIG_PAIRED		(PIN_CONFIG_END + 4)88 89/**90 * struct pm8xxx_pin_data - dynamic configuration for a pin91 * @reg:		address of the control register92 * @mode:		operating mode for the pin (digital, analog or current sink)93 * @input:		pin is input94 * @output:		pin is output95 * @high_z:		pin is floating96 * @paired:		mpp operates in paired mode97 * @output_value:	logical output value of the mpp98 * @power_source:	selected power source99 * @dtest:		DTEST route selector100 * @amux:		input muxing in analog mode101 * @aout_level:		selector of the output in analog mode102 * @drive_strength:	drive strength of the current sink103 * @pullup:		pull up value, when in digital bidirectional mode104 */105struct pm8xxx_pin_data {106	unsigned reg;107 108	u8 mode;109 110	bool input;111	bool output;112	bool high_z;113	bool paired;114	bool output_value;115 116	u8 power_source;117	u8 dtest;118	u8 amux;119	u8 aout_level;120	u8 drive_strength;121	unsigned pullup;122};123 124struct pm8xxx_mpp {125	struct device *dev;126	struct regmap *regmap;127	struct pinctrl_dev *pctrl;128	struct gpio_chip chip;129 130	struct pinctrl_desc desc;131	unsigned npins;132};133 134static const struct pinconf_generic_params pm8xxx_mpp_bindings[] = {135	{"qcom,amux-route",	PM8XXX_CONFIG_AMUX,		0},136	{"qcom,analog-level",	PM8XXX_CONFIG_ALEVEL,		0},137	{"qcom,dtest",		PM8XXX_CONFIG_DTEST_SELECTOR,	0},138	{"qcom,paired",		PM8XXX_CONFIG_PAIRED,		0},139};140 141#ifdef CONFIG_DEBUG_FS142static const struct pin_config_item pm8xxx_conf_items[] = {143	PCONFDUMP(PM8XXX_CONFIG_AMUX, "analog mux", NULL, true),144	PCONFDUMP(PM8XXX_CONFIG_ALEVEL, "analog level", NULL, true),145	PCONFDUMP(PM8XXX_CONFIG_DTEST_SELECTOR, "dtest", NULL, true),146	PCONFDUMP(PM8XXX_CONFIG_PAIRED, "paired", NULL, false),147};148#endif149 150#define PM8XXX_MAX_MPPS	12151#define PM8XXX_MPP_PHYSICAL_OFFSET    1152 153static const char * const pm8xxx_groups[PM8XXX_MAX_MPPS] = {154	"mpp1", "mpp2", "mpp3", "mpp4", "mpp5", "mpp6", "mpp7", "mpp8",155	"mpp9", "mpp10", "mpp11", "mpp12",156};157 158#define PM8XXX_MPP_DIGITAL	0159#define PM8XXX_MPP_ANALOG	1160#define PM8XXX_MPP_SINK		2161 162static const char * const pm8xxx_mpp_functions[] = {163	"digital", "analog", "sink",164};165 166static int pm8xxx_mpp_update(struct pm8xxx_mpp *pctrl,167			     struct pm8xxx_pin_data *pin)168{169	unsigned level;170	unsigned ctrl;171	unsigned type;172	int ret;173	u8 val;174 175	switch (pin->mode) {176	case PM8XXX_MPP_DIGITAL:177		if (pin->dtest) {178			type = PM8XXX_MPP_TYPE_DTEST_OUTPUT;179			ctrl = pin->dtest - 1;180		} else if (pin->input && pin->output) {181			type = PM8XXX_MPP_TYPE_D_BI_DIR;182			if (pin->high_z)183				ctrl = PM8XXX_MPP_BI_PULLUP_OPEN;184			else if (pin->pullup == 600)185				ctrl = PM8XXX_MPP_BI_PULLUP_1KOHM;186			else if (pin->pullup == 10000)187				ctrl = PM8XXX_MPP_BI_PULLUP_10KOHM;188			else189				ctrl = PM8XXX_MPP_BI_PULLUP_30KOHM;190		} else if (pin->input) {191			type = PM8XXX_MPP_TYPE_D_INPUT;192			if (pin->dtest)193				ctrl = pin->dtest;194			else195				ctrl = PM8XXX_MPP_DIN_TO_INT;196		} else {197			type = PM8XXX_MPP_TYPE_D_OUTPUT;198			ctrl = !!pin->output_value;199			if (pin->paired)200				ctrl |= BIT(1);201		}202 203		level = pin->power_source;204		break;205	case PM8XXX_MPP_ANALOG:206		if (pin->output) {207			type = PM8XXX_MPP_TYPE_A_OUTPUT;208			level = pin->aout_level;209			ctrl = pin->output_value;210			if (pin->paired)211				ctrl |= BIT(1);212		} else {213			type = PM8XXX_MPP_TYPE_A_INPUT;214			level = pin->amux;215			ctrl = 0;216		}217		break;218	case PM8XXX_MPP_SINK:219		level = (pin->drive_strength / 5) - 1;220		if (pin->dtest) {221			type = PM8XXX_MPP_TYPE_DTEST_SINK;222			ctrl = pin->dtest - 1;223		} else {224			type = PM8XXX_MPP_TYPE_SINK;225			ctrl = pin->output_value;226			if (pin->paired)227				ctrl |= BIT(1);228		}229		break;230	default:231		return -EINVAL;232	}233 234	val = type << 5 | level << 2 | ctrl;235	ret = regmap_write(pctrl->regmap, pin->reg, val);236	if (ret)237		dev_err(pctrl->dev, "failed to write register\n");238 239	return ret;240}241 242static int pm8xxx_get_groups_count(struct pinctrl_dev *pctldev)243{244	struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev);245 246	return pctrl->npins;247}248 249static const char *pm8xxx_get_group_name(struct pinctrl_dev *pctldev,250					 unsigned group)251{252	return pm8xxx_groups[group];253}254 255 256static int pm8xxx_get_group_pins(struct pinctrl_dev *pctldev,257				 unsigned group,258				 const unsigned **pins,259				 unsigned *num_pins)260{261	struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev);262 263	*pins = &pctrl->desc.pins[group].number;264	*num_pins = 1;265 266	return 0;267}268 269static const struct pinctrl_ops pm8xxx_pinctrl_ops = {270	.get_groups_count	= pm8xxx_get_groups_count,271	.get_group_name		= pm8xxx_get_group_name,272	.get_group_pins         = pm8xxx_get_group_pins,273	.dt_node_to_map		= pinconf_generic_dt_node_to_map_group,274	.dt_free_map		= pinctrl_utils_free_map,275};276 277static int pm8xxx_get_functions_count(struct pinctrl_dev *pctldev)278{279	return ARRAY_SIZE(pm8xxx_mpp_functions);280}281 282static const char *pm8xxx_get_function_name(struct pinctrl_dev *pctldev,283					    unsigned function)284{285	return pm8xxx_mpp_functions[function];286}287 288static int pm8xxx_get_function_groups(struct pinctrl_dev *pctldev,289				      unsigned function,290				      const char * const **groups,291				      unsigned * const num_groups)292{293	struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev);294 295	*groups = pm8xxx_groups;296	*num_groups = pctrl->npins;297	return 0;298}299 300static int pm8xxx_pinmux_set_mux(struct pinctrl_dev *pctldev,301				 unsigned function,302				 unsigned group)303{304	struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev);305	struct pm8xxx_pin_data *pin = pctrl->desc.pins[group].drv_data;306 307	pin->mode = function;308	pm8xxx_mpp_update(pctrl, pin);309 310	return 0;311}312 313static const struct pinmux_ops pm8xxx_pinmux_ops = {314	.get_functions_count	= pm8xxx_get_functions_count,315	.get_function_name	= pm8xxx_get_function_name,316	.get_function_groups	= pm8xxx_get_function_groups,317	.set_mux		= pm8xxx_pinmux_set_mux,318};319 320static int pm8xxx_pin_config_get(struct pinctrl_dev *pctldev,321				 unsigned int offset,322				 unsigned long *config)323{324	struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev);325	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;326	unsigned param = pinconf_to_config_param(*config);327	unsigned arg;328 329	switch (param) {330	case PIN_CONFIG_BIAS_PULL_UP:331		arg = pin->pullup;332		break;333	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:334		arg = pin->high_z;335		break;336	case PIN_CONFIG_INPUT_ENABLE:337		arg = pin->input;338		break;339	case PIN_CONFIG_OUTPUT:340		arg = pin->output_value;341		break;342	case PIN_CONFIG_POWER_SOURCE:343		arg = pin->power_source;344		break;345	case PIN_CONFIG_DRIVE_STRENGTH:346		arg = pin->drive_strength;347		break;348	case PM8XXX_CONFIG_DTEST_SELECTOR:349		arg = pin->dtest;350		break;351	case PM8XXX_CONFIG_AMUX:352		arg = pin->amux;353		break;354	case PM8XXX_CONFIG_ALEVEL:355		arg = pin->aout_level;356		break;357	case PM8XXX_CONFIG_PAIRED:358		arg = pin->paired;359		break;360	default:361		return -EINVAL;362	}363 364	*config = pinconf_to_config_packed(param, arg);365 366	return 0;367}368 369static int pm8xxx_pin_config_set(struct pinctrl_dev *pctldev,370				 unsigned int offset,371				 unsigned long *configs,372				 unsigned num_configs)373{374	struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev);375	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;376	unsigned param;377	unsigned arg;378	unsigned i;379 380	for (i = 0; i < num_configs; i++) {381		param = pinconf_to_config_param(configs[i]);382		arg = pinconf_to_config_argument(configs[i]);383 384		switch (param) {385		case PIN_CONFIG_BIAS_PULL_UP:386			pin->pullup = arg;387			break;388		case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:389			pin->high_z = true;390			break;391		case PIN_CONFIG_INPUT_ENABLE:392			pin->input = true;393			break;394		case PIN_CONFIG_OUTPUT:395			pin->output = true;396			pin->output_value = !!arg;397			break;398		case PIN_CONFIG_POWER_SOURCE:399			pin->power_source = arg;400			break;401		case PIN_CONFIG_DRIVE_STRENGTH:402			pin->drive_strength = arg;403			break;404		case PM8XXX_CONFIG_DTEST_SELECTOR:405			pin->dtest = arg;406			break;407		case PM8XXX_CONFIG_AMUX:408			pin->amux = arg;409			break;410		case PM8XXX_CONFIG_ALEVEL:411			pin->aout_level = arg;412			break;413		case PM8XXX_CONFIG_PAIRED:414			pin->paired = !!arg;415			break;416		default:417			dev_err(pctrl->dev,418				"unsupported config parameter: %x\n",419				param);420			return -EINVAL;421		}422	}423 424	pm8xxx_mpp_update(pctrl, pin);425 426	return 0;427}428 429static const struct pinconf_ops pm8xxx_pinconf_ops = {430	.is_generic = true,431	.pin_config_group_get = pm8xxx_pin_config_get,432	.pin_config_group_set = pm8xxx_pin_config_set,433};434 435static const struct pinctrl_desc pm8xxx_pinctrl_desc = {436	.name = "pm8xxx_mpp",437	.pctlops = &pm8xxx_pinctrl_ops,438	.pmxops = &pm8xxx_pinmux_ops,439	.confops = &pm8xxx_pinconf_ops,440	.owner = THIS_MODULE,441};442 443static int pm8xxx_mpp_direction_input(struct gpio_chip *chip,444				       unsigned offset)445{446	struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);447	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;448 449	switch (pin->mode) {450	case PM8XXX_MPP_DIGITAL:451		pin->input = true;452		break;453	case PM8XXX_MPP_ANALOG:454		pin->input = true;455		pin->output = true;456		break;457	case PM8XXX_MPP_SINK:458		return -EINVAL;459	}460 461	pm8xxx_mpp_update(pctrl, pin);462 463	return 0;464}465 466static int pm8xxx_mpp_direction_output(struct gpio_chip *chip,467					unsigned offset,468					int value)469{470	struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);471	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;472 473	switch (pin->mode) {474	case PM8XXX_MPP_DIGITAL:475		pin->output = true;476		break;477	case PM8XXX_MPP_ANALOG:478		pin->input = false;479		pin->output = true;480		break;481	case PM8XXX_MPP_SINK:482		pin->input = false;483		pin->output = true;484		break;485	}486 487	pm8xxx_mpp_update(pctrl, pin);488 489	return 0;490}491 492static int pm8xxx_mpp_get(struct gpio_chip *chip, unsigned offset)493{494	struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);495	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;496	bool state;497	int ret, irq;498 499	if (!pin->input)500		return !!pin->output_value;501 502	irq = chip->to_irq(chip, offset);503	if (irq < 0)504		return irq;505 506	ret = irq_get_irqchip_state(irq, IRQCHIP_STATE_LINE_LEVEL, &state);507	if (!ret)508		ret = !!state;509 510	return ret;511}512 513static void pm8xxx_mpp_set(struct gpio_chip *chip, unsigned offset, int value)514{515	struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);516	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;517 518	pin->output_value = !!value;519 520	pm8xxx_mpp_update(pctrl, pin);521}522 523static int pm8xxx_mpp_of_xlate(struct gpio_chip *chip,524				const struct of_phandle_args *gpio_desc,525				u32 *flags)526{527	if (chip->of_gpio_n_cells < 2)528		return -EINVAL;529 530	if (flags)531		*flags = gpio_desc->args[1];532 533	return gpio_desc->args[0] - PM8XXX_MPP_PHYSICAL_OFFSET;534}535 536 537#ifdef CONFIG_DEBUG_FS538 539static void pm8xxx_mpp_dbg_show_one(struct seq_file *s,540				  struct pinctrl_dev *pctldev,541				  struct gpio_chip *chip,542				  unsigned offset,543				  unsigned gpio)544{545	struct pm8xxx_mpp *pctrl = gpiochip_get_data(chip);546	struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data;547 548	static const char * const aout_lvls[] = {549		"1v25", "1v25_2", "0v625", "0v3125", "mpp", "abus1", "abus2",550		"abus3"551	};552 553	static const char * const amuxs[] = {554		"amux5", "amux6", "amux7", "amux8", "amux9", "abus1", "abus2",555		"abus3",556	};557 558	seq_printf(s, " mpp%-2d:", offset + PM8XXX_MPP_PHYSICAL_OFFSET);559 560	switch (pin->mode) {561	case PM8XXX_MPP_DIGITAL:562		seq_puts(s, " digital ");563		if (pin->dtest) {564			seq_printf(s, "dtest%d\n", pin->dtest);565		} else if (pin->input && pin->output) {566			if (pin->high_z)567				seq_puts(s, "bi-dir high-z");568			else569				seq_printf(s, "bi-dir %dOhm", pin->pullup);570		} else if (pin->input) {571			if (pin->dtest)572				seq_printf(s, "in dtest%d", pin->dtest);573			else574				seq_puts(s, "in gpio");575		} else if (pin->output) {576			seq_puts(s, "out ");577 578			if (!pin->paired) {579				seq_puts(s, pin->output_value ?580					 "high" : "low");581			} else {582				seq_puts(s, pin->output_value ?583					 "inverted" : "follow");584			}585		}586		break;587	case PM8XXX_MPP_ANALOG:588		seq_puts(s, " analog ");589		if (pin->output) {590			seq_printf(s, "out %s ", aout_lvls[pin->aout_level]);591			if (!pin->paired) {592				seq_puts(s, pin->output_value ?593					 "high" : "low");594			} else {595				seq_puts(s, pin->output_value ?596					 "inverted" : "follow");597			}598		} else {599			seq_printf(s, "input mux %s", amuxs[pin->amux]);600		}601		break;602	case PM8XXX_MPP_SINK:603		seq_printf(s, " sink %dmA ", pin->drive_strength);604		if (pin->dtest) {605			seq_printf(s, "dtest%d", pin->dtest);606		} else {607			if (!pin->paired) {608				seq_puts(s, pin->output_value ?609					 "high" : "low");610			} else {611				seq_puts(s, pin->output_value ?612					 "inverted" : "follow");613			}614		}615		break;616	}617}618 619static void pm8xxx_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip)620{621	unsigned gpio = chip->base;622	unsigned i;623 624	for (i = 0; i < chip->ngpio; i++, gpio++) {625		pm8xxx_mpp_dbg_show_one(s, NULL, chip, i, gpio);626		seq_puts(s, "\n");627	}628}629 630#else631#define pm8xxx_mpp_dbg_show NULL632#endif633 634static const struct gpio_chip pm8xxx_mpp_template = {635	.direction_input = pm8xxx_mpp_direction_input,636	.direction_output = pm8xxx_mpp_direction_output,637	.get = pm8xxx_mpp_get,638	.set = pm8xxx_mpp_set,639	.of_xlate = pm8xxx_mpp_of_xlate,640	.dbg_show = pm8xxx_mpp_dbg_show,641	.owner = THIS_MODULE,642};643 644static int pm8xxx_pin_populate(struct pm8xxx_mpp *pctrl,645			       struct pm8xxx_pin_data *pin)646{647	unsigned int val;648	unsigned level;649	unsigned ctrl;650	unsigned type;651	int ret;652 653	ret = regmap_read(pctrl->regmap, pin->reg, &val);654	if (ret) {655		dev_err(pctrl->dev, "failed to read register\n");656		return ret;657	}658 659	type = (val >> 5) & 7;660	level = (val >> 2) & 7;661	ctrl = (val) & 3;662 663	switch (type) {664	case PM8XXX_MPP_TYPE_D_INPUT:665		pin->mode = PM8XXX_MPP_DIGITAL;666		pin->input = true;667		pin->power_source = level;668		pin->dtest = ctrl;669		break;670	case PM8XXX_MPP_TYPE_D_OUTPUT:671		pin->mode = PM8XXX_MPP_DIGITAL;672		pin->output = true;673		pin->power_source = level;674		pin->output_value = !!(ctrl & BIT(0));675		pin->paired = !!(ctrl & BIT(1));676		break;677	case PM8XXX_MPP_TYPE_D_BI_DIR:678		pin->mode = PM8XXX_MPP_DIGITAL;679		pin->input = true;680		pin->output = true;681		pin->power_source = level;682		switch (ctrl) {683		case PM8XXX_MPP_BI_PULLUP_1KOHM:684			pin->pullup = 600;685			break;686		case PM8XXX_MPP_BI_PULLUP_OPEN:687			pin->high_z = true;688			break;689		case PM8XXX_MPP_BI_PULLUP_10KOHM:690			pin->pullup = 10000;691			break;692		case PM8XXX_MPP_BI_PULLUP_30KOHM:693			pin->pullup = 30000;694			break;695		}696		break;697	case PM8XXX_MPP_TYPE_A_INPUT:698		pin->mode = PM8XXX_MPP_ANALOG;699		pin->input = true;700		pin->amux = level;701		break;702	case PM8XXX_MPP_TYPE_A_OUTPUT:703		pin->mode = PM8XXX_MPP_ANALOG;704		pin->output = true;705		pin->aout_level = level;706		pin->output_value = !!(ctrl & BIT(0));707		pin->paired = !!(ctrl & BIT(1));708		break;709	case PM8XXX_MPP_TYPE_SINK:710		pin->mode = PM8XXX_MPP_SINK;711		pin->drive_strength = 5 * (level + 1);712		pin->output_value = !!(ctrl & BIT(0));713		pin->paired = !!(ctrl & BIT(1));714		break;715	case PM8XXX_MPP_TYPE_DTEST_SINK:716		pin->mode = PM8XXX_MPP_SINK;717		pin->dtest = ctrl + 1;718		pin->drive_strength = 5 * (level + 1);719		break;720	case PM8XXX_MPP_TYPE_DTEST_OUTPUT:721		pin->mode = PM8XXX_MPP_DIGITAL;722		pin->power_source = level;723		if (ctrl >= 1)724			pin->dtest = ctrl;725		break;726	}727 728	return 0;729}730 731static int pm8xxx_mpp_domain_translate(struct irq_domain *domain,732				   struct irq_fwspec *fwspec,733				   unsigned long *hwirq,734				   unsigned int *type)735{736	struct pm8xxx_mpp *pctrl = container_of(domain->host_data,737						 struct pm8xxx_mpp, chip);738 739	if (fwspec->param_count != 2 ||740	    fwspec->param[0] < PM8XXX_MPP_PHYSICAL_OFFSET ||741	    fwspec->param[0] > pctrl->chip.ngpio)742		return -EINVAL;743 744	*hwirq = fwspec->param[0] - PM8XXX_MPP_PHYSICAL_OFFSET;745	*type = fwspec->param[1];746 747	return 0;748}749 750static unsigned int pm8xxx_mpp_child_offset_to_irq(struct gpio_chip *chip,751						   unsigned int offset)752{753	return offset + PM8XXX_MPP_PHYSICAL_OFFSET;754}755 756static int pm8821_mpp_child_to_parent_hwirq(struct gpio_chip *chip,757					    unsigned int child_hwirq,758					    unsigned int child_type,759					    unsigned int *parent_hwirq,760					    unsigned int *parent_type)761{762	*parent_hwirq = child_hwirq + 24;763	*parent_type = child_type;764 765	return 0;766}767 768static int pm8xxx_mpp_child_to_parent_hwirq(struct gpio_chip *chip,769					    unsigned int child_hwirq,770					    unsigned int child_type,771					    unsigned int *parent_hwirq,772					    unsigned int *parent_type)773{774	*parent_hwirq = child_hwirq + 0x80;775	*parent_type = child_type;776 777	return 0;778}779 780static void pm8xxx_mpp_irq_disable(struct irq_data *d)781{782	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);783 784	gpiochip_disable_irq(gc, irqd_to_hwirq(d));785}786 787static void pm8xxx_mpp_irq_enable(struct irq_data *d)788{789	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);790 791	gpiochip_enable_irq(gc, irqd_to_hwirq(d));792}793 794static const struct irq_chip pm8xxx_mpp_irq_chip = {795	.name = "ssbi-mpp",796	.irq_mask_ack = irq_chip_mask_ack_parent,797	.irq_unmask = irq_chip_unmask_parent,798	.irq_disable = pm8xxx_mpp_irq_disable,799	.irq_enable = pm8xxx_mpp_irq_enable,800	.irq_set_type = irq_chip_set_type_parent,801	.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE |802		IRQCHIP_IMMUTABLE,803	GPIOCHIP_IRQ_RESOURCE_HELPERS,804};805 806static const struct of_device_id pm8xxx_mpp_of_match[] = {807	{ .compatible = "qcom,pm8018-mpp", .data = (void *) 6 },808	{ .compatible = "qcom,pm8038-mpp", .data = (void *) 6 },809	{ .compatible = "qcom,pm8058-mpp", .data = (void *) 12 },810	{ .compatible = "qcom,pm8821-mpp", .data = (void *) 4 },811	{ .compatible = "qcom,pm8917-mpp", .data = (void *) 10 },812	{ .compatible = "qcom,pm8921-mpp", .data = (void *) 12 },813	{ },814};815MODULE_DEVICE_TABLE(of, pm8xxx_mpp_of_match);816 817static int pm8xxx_mpp_probe(struct platform_device *pdev)818{819	struct pm8xxx_pin_data *pin_data;820	struct irq_domain *parent_domain;821	struct device_node *parent_node;822	struct pinctrl_pin_desc *pins;823	struct gpio_irq_chip *girq;824	struct pm8xxx_mpp *pctrl;825	int ret;826	int i;827 828	pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);829	if (!pctrl)830		return -ENOMEM;831 832	pctrl->dev = &pdev->dev;833	pctrl->npins = (uintptr_t) device_get_match_data(&pdev->dev);834 835	pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL);836	if (!pctrl->regmap) {837		dev_err(&pdev->dev, "parent regmap unavailable\n");838		return -ENXIO;839	}840 841	pctrl->desc = pm8xxx_pinctrl_desc;842	pctrl->desc.npins = pctrl->npins;843 844	pins = devm_kcalloc(&pdev->dev,845			    pctrl->desc.npins,846			    sizeof(struct pinctrl_pin_desc),847			    GFP_KERNEL);848	if (!pins)849		return -ENOMEM;850 851	pin_data = devm_kcalloc(&pdev->dev,852				pctrl->desc.npins,853				sizeof(struct pm8xxx_pin_data),854				GFP_KERNEL);855	if (!pin_data)856		return -ENOMEM;857 858	for (i = 0; i < pctrl->desc.npins; i++) {859		pin_data[i].reg = SSBI_REG_ADDR_MPP(i);860 861		ret = pm8xxx_pin_populate(pctrl, &pin_data[i]);862		if (ret)863			return ret;864 865		pins[i].number = i;866		pins[i].name = pm8xxx_groups[i];867		pins[i].drv_data = &pin_data[i];868	}869	pctrl->desc.pins = pins;870 871	pctrl->desc.num_custom_params = ARRAY_SIZE(pm8xxx_mpp_bindings);872	pctrl->desc.custom_params = pm8xxx_mpp_bindings;873#ifdef CONFIG_DEBUG_FS874	pctrl->desc.custom_conf_items = pm8xxx_conf_items;875#endif876 877	pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &pctrl->desc, pctrl);878	if (IS_ERR(pctrl->pctrl)) {879		dev_err(&pdev->dev, "couldn't register pm8xxx mpp driver\n");880		return PTR_ERR(pctrl->pctrl);881	}882 883	pctrl->chip = pm8xxx_mpp_template;884	pctrl->chip.base = -1;885	pctrl->chip.parent = &pdev->dev;886	pctrl->chip.of_gpio_n_cells = 2;887	pctrl->chip.label = dev_name(pctrl->dev);888	pctrl->chip.ngpio = pctrl->npins;889 890	parent_node = of_irq_find_parent(pctrl->dev->of_node);891	if (!parent_node)892		return -ENXIO;893 894	parent_domain = irq_find_host(parent_node);895	of_node_put(parent_node);896	if (!parent_domain)897		return -ENXIO;898 899	girq = &pctrl->chip.irq;900	gpio_irq_chip_set_chip(girq, &pm8xxx_mpp_irq_chip);901	girq->default_type = IRQ_TYPE_NONE;902	girq->handler = handle_level_irq;903	girq->fwnode = dev_fwnode(pctrl->dev);904	girq->parent_domain = parent_domain;905	if (of_device_is_compatible(pdev->dev.of_node, "qcom,pm8821-mpp"))906		girq->child_to_parent_hwirq = pm8821_mpp_child_to_parent_hwirq;907	else908		girq->child_to_parent_hwirq = pm8xxx_mpp_child_to_parent_hwirq;909	girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_twocell;910	girq->child_offset_to_irq = pm8xxx_mpp_child_offset_to_irq;911	girq->child_irq_domain_ops.translate = pm8xxx_mpp_domain_translate;912 913	ret = gpiochip_add_data(&pctrl->chip, pctrl);914	if (ret) {915		dev_err(&pdev->dev, "failed register gpiochip\n");916		return ret;917	}918 919	ret = gpiochip_add_pin_range(&pctrl->chip,920				     dev_name(pctrl->dev),921				     0, 0, pctrl->chip.ngpio);922	if (ret) {923		dev_err(pctrl->dev, "failed to add pin range\n");924		goto unregister_gpiochip;925	}926 927	platform_set_drvdata(pdev, pctrl);928 929	dev_dbg(&pdev->dev, "Qualcomm pm8xxx mpp driver probed\n");930 931	return 0;932 933unregister_gpiochip:934	gpiochip_remove(&pctrl->chip);935 936	return ret;937}938 939static void pm8xxx_mpp_remove(struct platform_device *pdev)940{941	struct pm8xxx_mpp *pctrl = platform_get_drvdata(pdev);942 943	gpiochip_remove(&pctrl->chip);944}945 946static struct platform_driver pm8xxx_mpp_driver = {947	.driver = {948		.name = "qcom-ssbi-mpp",949		.of_match_table = pm8xxx_mpp_of_match,950	},951	.probe = pm8xxx_mpp_probe,952	.remove_new = pm8xxx_mpp_remove,953};954 955module_platform_driver(pm8xxx_mpp_driver);956 957MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");958MODULE_DESCRIPTION("Qualcomm PM8xxx MPP driver");959MODULE_LICENSE("GPL v2");960