1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * wm8350-core.c  --  Device access for Wolfson WM8350
4 *
5 * Copyright 2007, 2008 Wolfson Microelectronics PLC.
6 *
7 * Author: Liam Girdwood
8 */
9
10#include <linux/kernel.h>
11#include <linux/module.h>
12#include <linux/errno.h>
13
14#include <linux/mfd/wm8350/core.h>
15#include <linux/mfd/wm8350/gpio.h>
16#include <linux/mfd/wm8350/pmic.h>
17
18static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir)
19{
20	int ret;
21
22	wm8350_reg_unlock(wm8350);
23	if (dir == WM8350_GPIO_DIR_OUT)
24		ret = wm8350_clear_bits(wm8350,
25					WM8350_GPIO_CONFIGURATION_I_O,
26					1 << gpio);
27	else
28		ret = wm8350_set_bits(wm8350,
29				      WM8350_GPIO_CONFIGURATION_I_O,
30				      1 << gpio);
31	wm8350_reg_lock(wm8350);
32	return ret;
33}
34
35static int wm8350_gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
36{
37	if (db == WM8350_GPIO_DEBOUNCE_ON)
38		return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE,
39				       1 << gpio);
40	else
41		return wm8350_clear_bits(wm8350,
42					 WM8350_GPIO_DEBOUNCE, 1 << gpio);
43}
44
45static int gpio_set_func(struct wm8350 *wm8350, int gpio, int func)
46{
47	u16 reg;
48
49	wm8350_reg_unlock(wm8350);
50	switch (gpio) {
51	case 0:
52		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
53		    & ~WM8350_GP0_FN_MASK;
54		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
55				 reg | ((func & 0xf) << 0));
56		break;
57	case 1:
58		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
59		    & ~WM8350_GP1_FN_MASK;
60		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
61				 reg | ((func & 0xf) << 4));
62		break;
63	case 2:
64		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
65		    & ~WM8350_GP2_FN_MASK;
66		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
67				 reg | ((func & 0xf) << 8));
68		break;
69	case 3:
70		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
71		    & ~WM8350_GP3_FN_MASK;
72		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
73				 reg | ((func & 0xf) << 12));
74		break;
75	case 4:
76		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
77		    & ~WM8350_GP4_FN_MASK;
78		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
79				 reg | ((func & 0xf) << 0));
80		break;
81	case 5:
82		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
83		    & ~WM8350_GP5_FN_MASK;
84		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
85				 reg | ((func & 0xf) << 4));
86		break;
87	case 6:
88		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
89		    & ~WM8350_GP6_FN_MASK;
90		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
91				 reg | ((func & 0xf) << 8));
92		break;
93	case 7:
94		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
95		    & ~WM8350_GP7_FN_MASK;
96		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
97				 reg | ((func & 0xf) << 12));
98		break;
99	case 8:
100		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
101		    & ~WM8350_GP8_FN_MASK;
102		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
103				 reg | ((func & 0xf) << 0));
104		break;
105	case 9:
106		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
107		    & ~WM8350_GP9_FN_MASK;
108		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
109				 reg | ((func & 0xf) << 4));
110		break;
111	case 10:
112		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
113		    & ~WM8350_GP10_FN_MASK;
114		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
115				 reg | ((func & 0xf) << 8));
116		break;
117	case 11:
118		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
119		    & ~WM8350_GP11_FN_MASK;
120		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
121				 reg | ((func & 0xf) << 12));
122		break;
123	case 12:
124		reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_4)
125		    & ~WM8350_GP12_FN_MASK;
126		wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_4,
127				 reg | ((func & 0xf) << 0));
128		break;
129	default:
130		wm8350_reg_lock(wm8350);
131		return -EINVAL;
132	}
133
134	wm8350_reg_lock(wm8350);
135	return 0;
136}
137
138static int gpio_set_pull_up(struct wm8350 *wm8350, int gpio, int up)
139{
140	if (up)
141		return wm8350_set_bits(wm8350,
142				       WM8350_GPIO_PIN_PULL_UP_CONTROL,
143				       1 << gpio);
144	else
145		return wm8350_clear_bits(wm8350,
146					 WM8350_GPIO_PIN_PULL_UP_CONTROL,
147					 1 << gpio);
148}
149
150static int gpio_set_pull_down(struct wm8350 *wm8350, int gpio, int down)
151{
152	if (down)
153		return wm8350_set_bits(wm8350,
154				       WM8350_GPIO_PULL_DOWN_CONTROL,
155				       1 << gpio);
156	else
157		return wm8350_clear_bits(wm8350,
158					 WM8350_GPIO_PULL_DOWN_CONTROL,
159					 1 << gpio);
160}
161
162static int gpio_set_polarity(struct wm8350 *wm8350, int gpio, int pol)
163{
164	if (pol == WM8350_GPIO_ACTIVE_HIGH)
165		return wm8350_set_bits(wm8350,
166				       WM8350_GPIO_PIN_POLARITY_TYPE,
167				       1 << gpio);
168	else
169		return wm8350_clear_bits(wm8350,
170					 WM8350_GPIO_PIN_POLARITY_TYPE,
171					 1 << gpio);
172}
173
174static int gpio_set_invert(struct wm8350 *wm8350, int gpio, int invert)
175{
176	if (invert == WM8350_GPIO_INVERT_ON)
177		return wm8350_set_bits(wm8350, WM8350_GPIO_INT_MODE, 1 << gpio);
178	else
179		return wm8350_clear_bits(wm8350,
180					 WM8350_GPIO_INT_MODE, 1 << gpio);
181}
182
183int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
184		       int pol, int pull, int invert, int debounce)
185{
186	/* make sure we never pull up and down at the same time */
187	if (pull == WM8350_GPIO_PULL_NONE) {
188		if (gpio_set_pull_up(wm8350, gpio, 0))
189			goto err;
190		if (gpio_set_pull_down(wm8350, gpio, 0))
191			goto err;
192	} else if (pull == WM8350_GPIO_PULL_UP) {
193		if (gpio_set_pull_down(wm8350, gpio, 0))
194			goto err;
195		if (gpio_set_pull_up(wm8350, gpio, 1))
196			goto err;
197	} else if (pull == WM8350_GPIO_PULL_DOWN) {
198		if (gpio_set_pull_up(wm8350, gpio, 0))
199			goto err;
200		if (gpio_set_pull_down(wm8350, gpio, 1))
201			goto err;
202	}
203
204	if (gpio_set_invert(wm8350, gpio, invert))
205		goto err;
206	if (gpio_set_polarity(wm8350, gpio, pol))
207		goto err;
208	if (wm8350_gpio_set_debounce(wm8350, gpio, debounce))
209		goto err;
210	if (gpio_set_dir(wm8350, gpio, dir))
211		goto err;
212	return gpio_set_func(wm8350, gpio, func);
213
214err:
215	return -EIO;
216}
217EXPORT_SYMBOL_GPL(wm8350_gpio_config);
218