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 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
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 mask: 1 << gpio);
40 else
41 return wm8350_clear_bits(wm8350,
42 WM8350_GPIO_DEBOUNCE, mask: 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 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
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 mask: 1 << gpio);
144 else
145 return wm8350_clear_bits(wm8350,
146 WM8350_GPIO_PIN_PULL_UP_CONTROL,
147 mask: 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 mask: 1 << gpio);
156 else
157 return wm8350_clear_bits(wm8350,
158 WM8350_GPIO_PULL_DOWN_CONTROL,
159 mask: 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 mask: 1 << gpio);
168 else
169 return wm8350_clear_bits(wm8350,
170 WM8350_GPIO_PIN_POLARITY_TYPE,
171 mask: 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, mask: 1 << gpio);
178 else
179 return wm8350_clear_bits(wm8350,
180 WM8350_GPIO_INT_MODE, mask: 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, 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
214err:
215 return -EIO;
216}
217EXPORT_SYMBOL_GPL(wm8350_gpio_config);
218

source code of linux/drivers/mfd/wm8350-gpio.c