xref: /openbmc/linux/drivers/gpio/gpio-arizona.c (revision efe4a1ac)
1 /*
2  * gpiolib support for Wolfson Arizona class devices
3  *
4  * Copyright 2012 Wolfson Microelectronics PLC.
5  *
6  * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
7  *
8  *  This program is free software; you can redistribute  it and/or modify it
9  *  under  the terms of  the GNU General  Public License as published by the
10  *  Free Software Foundation;  either version 2 of the  License, or (at your
11  *  option) any later version.
12  *
13  */
14 
15 #include <linux/kernel.h>
16 #include <linux/slab.h>
17 #include <linux/module.h>
18 #include <linux/gpio.h>
19 #include <linux/platform_device.h>
20 #include <linux/pm_runtime.h>
21 #include <linux/seq_file.h>
22 
23 #include <linux/mfd/arizona/core.h>
24 #include <linux/mfd/arizona/pdata.h>
25 #include <linux/mfd/arizona/registers.h>
26 
27 struct arizona_gpio {
28 	struct arizona *arizona;
29 	struct gpio_chip gpio_chip;
30 };
31 
32 static int arizona_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
33 {
34 	struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
35 	struct arizona *arizona = arizona_gpio->arizona;
36 
37 	return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
38 				  ARIZONA_GPN_DIR, ARIZONA_GPN_DIR);
39 }
40 
41 static int arizona_gpio_get(struct gpio_chip *chip, unsigned offset)
42 {
43 	struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
44 	struct arizona *arizona = arizona_gpio->arizona;
45 	unsigned int reg, val;
46 	int ret;
47 
48 	reg = ARIZONA_GPIO1_CTRL + offset;
49 	ret = regmap_read(arizona->regmap, reg, &val);
50 	if (ret < 0)
51 		return ret;
52 
53 	/* Resume to read actual registers for input pins */
54 	if (val & ARIZONA_GPN_DIR) {
55 		ret = pm_runtime_get_sync(chip->parent);
56 		if (ret < 0) {
57 			dev_err(chip->parent, "Failed to resume: %d\n", ret);
58 			return ret;
59 		}
60 
61 		/* Register is cached, drop it to ensure a physical read */
62 		ret = regcache_drop_region(arizona->regmap, reg, reg);
63 		if (ret < 0) {
64 			dev_err(chip->parent, "Failed to drop cache: %d\n",
65 				ret);
66 			return ret;
67 		}
68 
69 		ret = regmap_read(arizona->regmap, reg, &val);
70 		if (ret < 0)
71 			return ret;
72 
73 		pm_runtime_mark_last_busy(chip->parent);
74 		pm_runtime_put_autosuspend(chip->parent);
75 	}
76 
77 	if (val & ARIZONA_GPN_LVL)
78 		return 1;
79 	else
80 		return 0;
81 }
82 
83 static int arizona_gpio_direction_out(struct gpio_chip *chip,
84 				     unsigned offset, int value)
85 {
86 	struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
87 	struct arizona *arizona = arizona_gpio->arizona;
88 
89 	if (value)
90 		value = ARIZONA_GPN_LVL;
91 
92 	return regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
93 				  ARIZONA_GPN_DIR | ARIZONA_GPN_LVL, value);
94 }
95 
96 static void arizona_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
97 {
98 	struct arizona_gpio *arizona_gpio = gpiochip_get_data(chip);
99 	struct arizona *arizona = arizona_gpio->arizona;
100 
101 	if (value)
102 		value = ARIZONA_GPN_LVL;
103 
104 	regmap_update_bits(arizona->regmap, ARIZONA_GPIO1_CTRL + offset,
105 			   ARIZONA_GPN_LVL, value);
106 }
107 
108 static const struct gpio_chip template_chip = {
109 	.label			= "arizona",
110 	.owner			= THIS_MODULE,
111 	.direction_input	= arizona_gpio_direction_in,
112 	.get			= arizona_gpio_get,
113 	.direction_output	= arizona_gpio_direction_out,
114 	.set			= arizona_gpio_set,
115 	.can_sleep		= true,
116 };
117 
118 static int arizona_gpio_probe(struct platform_device *pdev)
119 {
120 	struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
121 	struct arizona_pdata *pdata = dev_get_platdata(arizona->dev);
122 	struct arizona_gpio *arizona_gpio;
123 	int ret;
124 
125 	arizona_gpio = devm_kzalloc(&pdev->dev, sizeof(*arizona_gpio),
126 				    GFP_KERNEL);
127 	if (!arizona_gpio)
128 		return -ENOMEM;
129 
130 	arizona_gpio->arizona = arizona;
131 	arizona_gpio->gpio_chip = template_chip;
132 	arizona_gpio->gpio_chip.parent = &pdev->dev;
133 #ifdef CONFIG_OF_GPIO
134 	arizona_gpio->gpio_chip.of_node = arizona->dev->of_node;
135 #endif
136 
137 	switch (arizona->type) {
138 	case WM5102:
139 	case WM5110:
140 	case WM8280:
141 	case WM8997:
142 	case WM8998:
143 	case WM1814:
144 		arizona_gpio->gpio_chip.ngpio = 5;
145 		break;
146 	case WM1831:
147 	case CS47L24:
148 		arizona_gpio->gpio_chip.ngpio = 2;
149 		break;
150 	default:
151 		dev_err(&pdev->dev, "Unknown chip variant %d\n",
152 			arizona->type);
153 		return -EINVAL;
154 	}
155 
156 	if (pdata && pdata->gpio_base)
157 		arizona_gpio->gpio_chip.base = pdata->gpio_base;
158 	else
159 		arizona_gpio->gpio_chip.base = -1;
160 
161 	ret = devm_gpiochip_add_data(&pdev->dev, &arizona_gpio->gpio_chip,
162 				     arizona_gpio);
163 	if (ret < 0) {
164 		dev_err(&pdev->dev, "Could not register gpiochip, %d\n",
165 			ret);
166 		return ret;
167 	}
168 
169 	return 0;
170 }
171 
172 static struct platform_driver arizona_gpio_driver = {
173 	.driver.name	= "arizona-gpio",
174 	.probe		= arizona_gpio_probe,
175 };
176 
177 module_platform_driver(arizona_gpio_driver);
178 
179 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
180 MODULE_DESCRIPTION("GPIO interface for Arizona devices");
181 MODULE_LICENSE("GPL");
182 MODULE_ALIAS("platform:arizona-gpio");
183