Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * AXP20x GPIO driver
  3 *
  4 * Copyright (C) 2016 Maxime Ripard <maxime.ripard@free-electrons.com>
  5 *
  6 * This program is free software; you can redistribute it and/or modify it
  7 * under  the terms of the GNU General  Public License as published by the
  8 * Free Software Foundation;  either version 2 of the License, or (at your
  9 * option) any later version.
 10 */
 11
 12#include <linux/bitops.h>
 13#include <linux/device.h>
 14#include <linux/gpio/driver.h>
 15#include <linux/init.h>
 16#include <linux/interrupt.h>
 17#include <linux/kernel.h>
 18#include <linux/mfd/axp20x.h>
 19#include <linux/module.h>
 20#include <linux/of.h>
 21#include <linux/platform_device.h>
 22#include <linux/regmap.h>
 23#include <linux/slab.h>
 24
 25#define AXP20X_GPIO_FUNCTIONS		0x7
 26#define AXP20X_GPIO_FUNCTION_OUT_LOW	0
 27#define AXP20X_GPIO_FUNCTION_OUT_HIGH	1
 28#define AXP20X_GPIO_FUNCTION_INPUT	2
 29
 30struct axp20x_gpio {
 31	struct gpio_chip	chip;
 32	struct regmap		*regmap;
 33};
 34
 35static int axp20x_gpio_get_reg(unsigned offset)
 36{
 37	switch (offset) {
 38	case 0:
 39		return AXP20X_GPIO0_CTRL;
 40	case 1:
 41		return AXP20X_GPIO1_CTRL;
 42	case 2:
 43		return AXP20X_GPIO2_CTRL;
 44	}
 45
 46	return -EINVAL;
 47}
 48
 49static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset)
 50{
 51	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
 52	int reg;
 53
 54	reg = axp20x_gpio_get_reg(offset);
 55	if (reg < 0)
 56		return reg;
 57
 58	return regmap_update_bits(gpio->regmap, reg,
 59				  AXP20X_GPIO_FUNCTIONS,
 60				  AXP20X_GPIO_FUNCTION_INPUT);
 61}
 62
 63static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset)
 64{
 65	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
 66	unsigned int val;
 67	int ret;
 68
 69	ret = regmap_read(gpio->regmap, AXP20X_GPIO20_SS, &val);
 70	if (ret)
 71		return ret;
 72
 73	return !!(val & BIT(offset + 4));
 74}
 75
 76static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
 77{
 78	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
 79	unsigned int val;
 80	int reg, ret;
 81
 82	reg = axp20x_gpio_get_reg(offset);
 83	if (reg < 0)
 84		return reg;
 85
 86	ret = regmap_read(gpio->regmap, reg, &val);
 87	if (ret)
 88		return ret;
 89
 90	/*
 91	 * This shouldn't really happen if the pin is in use already,
 92	 * or if it's not in use yet, it doesn't matter since we're
 93	 * going to change the value soon anyway. Default to output.
 94	 */
 95	if ((val & AXP20X_GPIO_FUNCTIONS) > 2)
 96		return 0;
 97
 98	/*
 99	 * The GPIO directions are the three lowest values.
100	 * 2 is input, 0 and 1 are output
101	 */
102	return val & 2;
103}
104
105static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset,
106			      int value)
107{
108	struct axp20x_gpio *gpio = gpiochip_get_data(chip);
109	int reg;
110
111	reg = axp20x_gpio_get_reg(offset);
112	if (reg < 0)
113		return reg;
114
115	return regmap_update_bits(gpio->regmap, reg,
116				  AXP20X_GPIO_FUNCTIONS,
117				  value ? AXP20X_GPIO_FUNCTION_OUT_HIGH
118				  : AXP20X_GPIO_FUNCTION_OUT_LOW);
119}
120
121static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset,
122			    int value)
123{
124	axp20x_gpio_output(chip, offset, value);
125}
126
127static int axp20x_gpio_probe(struct platform_device *pdev)
128{
129	struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
130	struct axp20x_gpio *gpio;
131	int ret;
132
133	if (!of_device_is_available(pdev->dev.of_node))
134		return -ENODEV;
135
136	if (!axp20x) {
137		dev_err(&pdev->dev, "Parent drvdata not set\n");
138		return -EINVAL;
139	}
140
141	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
142	if (!gpio)
143		return -ENOMEM;
144
145	gpio->chip.base			= -1;
146	gpio->chip.can_sleep		= true;
147	gpio->chip.parent		= &pdev->dev;
148	gpio->chip.label		= dev_name(&pdev->dev);
149	gpio->chip.owner		= THIS_MODULE;
150	gpio->chip.get			= axp20x_gpio_get;
151	gpio->chip.get_direction	= axp20x_gpio_get_direction;
152	gpio->chip.set			= axp20x_gpio_set;
153	gpio->chip.direction_input	= axp20x_gpio_input;
154	gpio->chip.direction_output	= axp20x_gpio_output;
155	gpio->chip.ngpio		= 3;
156
157	gpio->regmap = axp20x->regmap;
158
159	ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
160	if (ret) {
161		dev_err(&pdev->dev, "Failed to register GPIO chip\n");
162		return ret;
163	}
164
165	dev_info(&pdev->dev, "AXP209 GPIO driver loaded\n");
166
167	return 0;
168}
169
170static const struct of_device_id axp20x_gpio_match[] = {
171	{ .compatible = "x-powers,axp209-gpio" },
172	{ }
173};
174MODULE_DEVICE_TABLE(of, axp20x_gpio_match);
175
176static struct platform_driver axp20x_gpio_driver = {
177	.probe		= axp20x_gpio_probe,
178	.driver = {
179		.name		= "axp20x-gpio",
180		.of_match_table	= axp20x_gpio_match,
181	},
182};
183
184module_platform_driver(axp20x_gpio_driver);
185
186MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
187MODULE_DESCRIPTION("AXP20x PMIC GPIO driver");
188MODULE_LICENSE("GPL");