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 
gpio_set_dir(struct wm8350 * wm8350,int gpio,int dir)18 static 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 
wm8350_gpio_set_debounce(struct wm8350 * wm8350,int gpio,int db)35 static 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 
gpio_set_func(struct wm8350 * wm8350,int gpio,int func)45 static 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 
gpio_set_pull_up(struct wm8350 * wm8350,int gpio,int up)138 static 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 
gpio_set_pull_down(struct wm8350 * wm8350,int gpio,int down)150 static 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 
gpio_set_polarity(struct wm8350 * wm8350,int gpio,int pol)162 static 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 
gpio_set_invert(struct wm8350 * wm8350,int gpio,int invert)174 static 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 
wm8350_gpio_config(struct wm8350 * wm8350,int gpio,int dir,int func,int pol,int pull,int invert,int debounce)183 int 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 
214 err:
215 	return -EIO;
216 }
217 EXPORT_SYMBOL_GPL(wm8350_gpio_config);
218