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 | |
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 | mask: 1 << gpio); |
27 | else |
28 | ret = wm8350_set_bits(wm8350, |
29 | WM8350_GPIO_CONFIGURATION_I_O, |
30 | mask: 1 << gpio); |
31 | wm8350_reg_lock(wm8350); |
32 | return ret; |
33 | } |
34 | |
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 | mask: 1 << gpio); |
40 | else |
41 | return wm8350_clear_bits(wm8350, |
42 | WM8350_GPIO_DEBOUNCE, mask: 1 << gpio); |
43 | } |
44 | |
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 | val: 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 | val: 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 | val: 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 | val: 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 | val: 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 | val: 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 | val: 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 | val: 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 | val: 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 | val: 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 | val: 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 | val: 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 | val: 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 | |
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 | mask: 1 << gpio); |
144 | else |
145 | return wm8350_clear_bits(wm8350, |
146 | WM8350_GPIO_PIN_PULL_UP_CONTROL, |
147 | mask: 1 << gpio); |
148 | } |
149 | |
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 | mask: 1 << gpio); |
156 | else |
157 | return wm8350_clear_bits(wm8350, |
158 | WM8350_GPIO_PULL_DOWN_CONTROL, |
159 | mask: 1 << gpio); |
160 | } |
161 | |
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 | mask: 1 << gpio); |
168 | else |
169 | return wm8350_clear_bits(wm8350, |
170 | WM8350_GPIO_PIN_POLARITY_TYPE, |
171 | mask: 1 << gpio); |
172 | } |
173 | |
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, mask: 1 << gpio); |
178 | else |
179 | return wm8350_clear_bits(wm8350, |
180 | WM8350_GPIO_INT_MODE, mask: 1 << gpio); |
181 | } |
182 | |
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, up: 0)) |
189 | goto err; |
190 | if (gpio_set_pull_down(wm8350, gpio, down: 0)) |
191 | goto err; |
192 | } else if (pull == WM8350_GPIO_PULL_UP) { |
193 | if (gpio_set_pull_down(wm8350, gpio, down: 0)) |
194 | goto err; |
195 | if (gpio_set_pull_up(wm8350, gpio, up: 1)) |
196 | goto err; |
197 | } else if (pull == WM8350_GPIO_PULL_DOWN) { |
198 | if (gpio_set_pull_up(wm8350, gpio, up: 0)) |
199 | goto err; |
200 | if (gpio_set_pull_down(wm8350, gpio, down: 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, db: 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 | |