brintos

brintos / linux-shallow public Read only

0
0
Text · 5.8 KiB · 8f38303 Raw
214 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * GPIO support for Cirrus Logic Madera codecs4 *5 * Copyright (C) 2015-2018 Cirrus Logic6 */7 8#include <linux/gpio/driver.h>9#include <linux/kernel.h>10#include <linux/module.h>11#include <linux/platform_device.h>12 13#include <linux/mfd/madera/core.h>14#include <linux/mfd/madera/pdata.h>15#include <linux/mfd/madera/registers.h>16 17struct madera_gpio {18	struct madera *madera;19	/* storage space for the gpio_chip we're using */20	struct gpio_chip gpio_chip;21};22 23static int madera_gpio_get_direction(struct gpio_chip *chip,24				     unsigned int offset)25{26	struct madera_gpio *madera_gpio = gpiochip_get_data(chip);27	struct madera *madera = madera_gpio->madera;28	unsigned int reg_offset = 2 * offset;29	unsigned int val;30	int ret;31 32	ret = regmap_read(madera->regmap, MADERA_GPIO1_CTRL_2 + reg_offset,33			  &val);34	if (ret < 0)35		return ret;36 37	if (val & MADERA_GP1_DIR_MASK)38		return GPIO_LINE_DIRECTION_IN;39 40	return GPIO_LINE_DIRECTION_OUT;41}42 43static int madera_gpio_direction_in(struct gpio_chip *chip, unsigned int offset)44{45	struct madera_gpio *madera_gpio = gpiochip_get_data(chip);46	struct madera *madera = madera_gpio->madera;47	unsigned int reg_offset = 2 * offset;48 49	return regmap_update_bits(madera->regmap,50				  MADERA_GPIO1_CTRL_2 + reg_offset,51				  MADERA_GP1_DIR_MASK, MADERA_GP1_DIR);52}53 54static int madera_gpio_get(struct gpio_chip *chip, unsigned int offset)55{56	struct madera_gpio *madera_gpio = gpiochip_get_data(chip);57	struct madera *madera = madera_gpio->madera;58	unsigned int reg_offset = 2 * offset;59	unsigned int val;60	int ret;61 62	ret = regmap_read(madera->regmap, MADERA_GPIO1_CTRL_1 + reg_offset,63			  &val);64	if (ret < 0)65		return ret;66 67	return !!(val & MADERA_GP1_LVL_MASK);68}69 70static int madera_gpio_direction_out(struct gpio_chip *chip,71				     unsigned int offset, int value)72{73	struct madera_gpio *madera_gpio = gpiochip_get_data(chip);74	struct madera *madera = madera_gpio->madera;75	unsigned int reg_offset = 2 * offset;76	unsigned int reg_val = value ? MADERA_GP1_LVL : 0;77	int ret;78 79	ret = regmap_update_bits(madera->regmap,80				 MADERA_GPIO1_CTRL_2 + reg_offset,81				 MADERA_GP1_DIR_MASK, 0);82	if (ret < 0)83		return ret;84 85	return regmap_update_bits(madera->regmap,86				  MADERA_GPIO1_CTRL_1 + reg_offset,87				  MADERA_GP1_LVL_MASK, reg_val);88}89 90static void madera_gpio_set(struct gpio_chip *chip, unsigned int offset,91			    int value)92{93	struct madera_gpio *madera_gpio = gpiochip_get_data(chip);94	struct madera *madera = madera_gpio->madera;95	unsigned int reg_offset = 2 * offset;96	unsigned int reg_val = value ? MADERA_GP1_LVL : 0;97	int ret;98 99	ret = regmap_update_bits(madera->regmap,100				 MADERA_GPIO1_CTRL_1 + reg_offset,101				 MADERA_GP1_LVL_MASK, reg_val);102 103	/* set() doesn't return an error so log a warning */104	if (ret)105		dev_warn(madera->dev, "Failed to write to 0x%x (%d)\n",106			 MADERA_GPIO1_CTRL_1 + reg_offset, ret);107}108 109static const struct gpio_chip madera_gpio_chip = {110	.label			= "madera",111	.owner			= THIS_MODULE,112	.request		= gpiochip_generic_request,113	.free			= gpiochip_generic_free,114	.get_direction		= madera_gpio_get_direction,115	.direction_input	= madera_gpio_direction_in,116	.get			= madera_gpio_get,117	.direction_output	= madera_gpio_direction_out,118	.set			= madera_gpio_set,119	.set_config		= gpiochip_generic_config,120	.can_sleep		= true,121};122 123static int madera_gpio_probe(struct platform_device *pdev)124{125	struct madera *madera = dev_get_drvdata(pdev->dev.parent);126	struct madera_pdata *pdata = &madera->pdata;127	struct madera_gpio *madera_gpio;128	int ret;129 130	madera_gpio = devm_kzalloc(&pdev->dev, sizeof(*madera_gpio),131				   GFP_KERNEL);132	if (!madera_gpio)133		return -ENOMEM;134 135	madera_gpio->madera = madera;136 137	/* Construct suitable gpio_chip from the template in madera_gpio_chip */138	madera_gpio->gpio_chip = madera_gpio_chip;139	madera_gpio->gpio_chip.parent = pdev->dev.parent;140 141	switch (madera->type) {142	case CS47L15:143		madera_gpio->gpio_chip.ngpio = CS47L15_NUM_GPIOS;144		break;145	case CS47L35:146		madera_gpio->gpio_chip.ngpio = CS47L35_NUM_GPIOS;147		break;148	case CS47L85:149	case WM1840:150		madera_gpio->gpio_chip.ngpio = CS47L85_NUM_GPIOS;151		break;152	case CS47L90:153	case CS47L91:154		madera_gpio->gpio_chip.ngpio = CS47L90_NUM_GPIOS;155		break;156	case CS42L92:157	case CS47L92:158	case CS47L93:159		madera_gpio->gpio_chip.ngpio = CS47L92_NUM_GPIOS;160		break;161	default:162		dev_err(&pdev->dev, "Unknown chip variant %d\n", madera->type);163		return -EINVAL;164	}165 166	/* We want to be usable on systems that don't use devicetree or acpi */167	if (pdata->gpio_base)168		madera_gpio->gpio_chip.base = pdata->gpio_base;169	else170		madera_gpio->gpio_chip.base = -1;171 172	ret = devm_gpiochip_add_data(&pdev->dev,173				     &madera_gpio->gpio_chip,174				     madera_gpio);175	if (ret < 0) {176		dev_dbg(&pdev->dev, "Could not register gpiochip, %d\n", ret);177		return ret;178	}179 180	/*181	 * This is part of a composite MFD device which can only be used with182	 * the corresponding pinctrl driver. On all supported silicon the GPIO183	 * to pinctrl mapping is fixed in the silicon, so we register it184	 * explicitly instead of requiring a redundant gpio-ranges in the185	 * devicetree.186	 * In any case we also want to work on systems that don't use devicetree187	 * or acpi.188	 */189	ret = gpiochip_add_pin_range(&madera_gpio->gpio_chip, "madera-pinctrl",190				     0, 0, madera_gpio->gpio_chip.ngpio);191	if (ret) {192		dev_dbg(&pdev->dev, "Failed to add pin range (%d)\n", ret);193		return ret;194	}195 196	return 0;197}198 199static struct platform_driver madera_gpio_driver = {200	.driver = {201		.name	= "madera-gpio",202	},203	.probe		= madera_gpio_probe,204};205 206module_platform_driver(madera_gpio_driver);207 208MODULE_SOFTDEP("pre: pinctrl-madera");209MODULE_DESCRIPTION("GPIO interface for Madera codecs");210MODULE_AUTHOR("Nariman Poushin <nariman@opensource.cirrus.com>");211MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");212MODULE_LICENSE("GPL v2");213MODULE_ALIAS("platform:madera-gpio");214