1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // CS42L43 Pinctrl and GPIO driver |
4 | // |
5 | // Copyright (c) 2023 Cirrus Logic, Inc. and |
6 | // Cirrus Logic International Semiconductor Ltd. |
7 | |
8 | #include <linux/array_size.h> |
9 | #include <linux/bits.h> |
10 | #include <linux/build_bug.h> |
11 | #include <linux/err.h> |
12 | #include <linux/gpio/driver.h> |
13 | #include <linux/mfd/cs42l43.h> |
14 | #include <linux/mfd/cs42l43-regs.h> |
15 | #include <linux/module.h> |
16 | #include <linux/of.h> |
17 | #include <linux/platform_device.h> |
18 | #include <linux/pm_runtime.h> |
19 | #include <linux/regmap.h> |
20 | #include <linux/string_choices.h> |
21 | |
22 | #include <linux/pinctrl/consumer.h> |
23 | #include <linux/pinctrl/pinctrl.h> |
24 | #include <linux/pinctrl/pinconf.h> |
25 | #include <linux/pinctrl/pinconf-generic.h> |
26 | #include <linux/pinctrl/pinmux.h> |
27 | |
28 | #include "../pinctrl-utils.h" |
29 | |
30 | #define CS42L43_NUM_GPIOS 3 |
31 | |
32 | struct cs42l43_pin { |
33 | struct gpio_chip gpio_chip; |
34 | |
35 | struct device *dev; |
36 | struct regmap *regmap; |
37 | bool shutters_locked; |
38 | }; |
39 | |
40 | struct cs42l43_pin_data { |
41 | unsigned int reg; |
42 | unsigned int shift; |
43 | unsigned int mask; |
44 | }; |
45 | |
46 | #define CS42L43_PIN(_number, _name, _reg, _field) { \ |
47 | .number = _number, .name = _name, \ |
48 | .drv_data = &((struct cs42l43_pin_data){ \ |
49 | .reg = CS42L43_##_reg, \ |
50 | .shift = CS42L43_##_field##_DRV_SHIFT, \ |
51 | .mask = CS42L43_##_field##_DRV_MASK, \ |
52 | }), \ |
53 | } |
54 | |
55 | static const struct pinctrl_pin_desc cs42l43_pin_pins[] = { |
56 | CS42L43_PIN(0, "gpio1" , DRV_CTRL4, GPIO1), |
57 | CS42L43_PIN(1, "gpio2" , DRV_CTRL4, GPIO2), |
58 | CS42L43_PIN(2, "gpio3" , DRV_CTRL4, GPIO3), |
59 | CS42L43_PIN(3, "asp_dout" , DRV_CTRL1, ASP_DOUT), |
60 | CS42L43_PIN(4, "asp_fsync" , DRV_CTRL1, ASP_FSYNC), |
61 | CS42L43_PIN(5, "asp_bclk" , DRV_CTRL1, ASP_BCLK), |
62 | CS42L43_PIN(6, "pdmout2_clk" , DRV_CTRL3, PDMOUT2_CLK), |
63 | CS42L43_PIN(7, "pdmout2_data" , DRV_CTRL3, PDMOUT2_DATA), |
64 | CS42L43_PIN(8, "pdmout1_clk" , DRV_CTRL3, PDMOUT1_CLK), |
65 | CS42L43_PIN(9, "pdmout1_data" , DRV_CTRL3, PDMOUT1_DATA), |
66 | CS42L43_PIN(10, "i2c_sda" , DRV_CTRL3, I2C_SDA), |
67 | CS42L43_PIN(11, "i2c_scl" , DRV_CTRL_5, I2C_SCL), |
68 | CS42L43_PIN(12, "spi_miso" , DRV_CTRL3, SPI_MISO), |
69 | CS42L43_PIN(13, "spi_sck" , DRV_CTRL_5, SPI_SCK), |
70 | CS42L43_PIN(14, "spi_ssb" , DRV_CTRL_5, SPI_SSB), |
71 | }; |
72 | |
73 | static const unsigned int cs42l43_pin_gpio1_pins[] = { 0 }; |
74 | static const unsigned int cs42l43_pin_gpio2_pins[] = { 1 }; |
75 | static const unsigned int cs42l43_pin_gpio3_pins[] = { 2 }; |
76 | static const unsigned int cs42l43_pin_asp_pins[] = { 3, 4, 5 }; |
77 | static const unsigned int cs42l43_pin_pdmout2_pins[] = { 6, 7 }; |
78 | static const unsigned int cs42l43_pin_pdmout1_pins[] = { 8, 9 }; |
79 | static const unsigned int cs42l43_pin_i2c_pins[] = { 10, 11 }; |
80 | static const unsigned int cs42l43_pin_spi_pins[] = { 12, 13, 14 }; |
81 | |
82 | #define CS42L43_PINGROUP(_name) \ |
83 | PINCTRL_PINGROUP(#_name, cs42l43_pin_##_name##_pins, \ |
84 | ARRAY_SIZE(cs42l43_pin_##_name##_pins)) |
85 | |
86 | static const struct pingroup cs42l43_pin_groups[] = { |
87 | CS42L43_PINGROUP(gpio1), |
88 | CS42L43_PINGROUP(gpio2), |
89 | CS42L43_PINGROUP(gpio3), |
90 | CS42L43_PINGROUP(asp), |
91 | CS42L43_PINGROUP(pdmout2), |
92 | CS42L43_PINGROUP(pdmout1), |
93 | CS42L43_PINGROUP(i2c), |
94 | CS42L43_PINGROUP(spi), |
95 | }; |
96 | |
97 | static int cs42l43_pin_get_groups_count(struct pinctrl_dev *pctldev) |
98 | { |
99 | return ARRAY_SIZE(cs42l43_pin_groups); |
100 | } |
101 | |
102 | static const char *cs42l43_pin_get_group_name(struct pinctrl_dev *pctldev, |
103 | unsigned int group_idx) |
104 | { |
105 | return cs42l43_pin_groups[group_idx].name; |
106 | } |
107 | |
108 | static int cs42l43_pin_get_group_pins(struct pinctrl_dev *pctldev, |
109 | unsigned int group_idx, |
110 | const unsigned int **pins, |
111 | unsigned int *num_pins) |
112 | { |
113 | *pins = cs42l43_pin_groups[group_idx].pins; |
114 | *num_pins = cs42l43_pin_groups[group_idx].npins; |
115 | |
116 | return 0; |
117 | } |
118 | |
119 | static const struct pinctrl_ops cs42l43_pin_group_ops = { |
120 | .get_groups_count = cs42l43_pin_get_groups_count, |
121 | .get_group_name = cs42l43_pin_get_group_name, |
122 | .get_group_pins = cs42l43_pin_get_group_pins, |
123 | #if IS_ENABLED(CONFIG_OF) |
124 | .dt_node_to_map = pinconf_generic_dt_node_to_map_all, |
125 | .dt_free_map = pinconf_generic_dt_free_map, |
126 | #endif |
127 | }; |
128 | |
129 | enum cs42l43_pin_funcs { |
130 | CS42L43_FUNC_GPIO, |
131 | CS42L43_FUNC_SPDIF, |
132 | CS42L43_FUNC_IRQ, |
133 | CS42L43_FUNC_MIC_SHT, |
134 | CS42L43_FUNC_SPK_SHT, |
135 | CS42L43_FUNC_MAX |
136 | }; |
137 | |
138 | static const char * const cs42l43_pin_funcs[] = { |
139 | "gpio" , "spdif" , "irq" , "mic-shutter" , "spk-shutter" , |
140 | }; |
141 | |
142 | static const char * const cs42l43_pin_gpio_groups[] = { "gpio1" , "gpio3" }; |
143 | static const char * const cs42l43_pin_spdif_groups[] = { "gpio3" }; |
144 | static const char * const cs42l43_pin_irq_groups[] = { "gpio1" }; |
145 | static const char * const cs42l43_pin_shutter_groups[] = { "gpio1" , "gpio2" , "gpio3" }; |
146 | |
147 | static const struct pinfunction cs42l43_pin_func_groups[] = { |
148 | PINCTRL_PINFUNCTION("gpio" , cs42l43_pin_gpio_groups, |
149 | ARRAY_SIZE(cs42l43_pin_gpio_groups)), |
150 | PINCTRL_PINFUNCTION("spdif" , cs42l43_pin_spdif_groups, |
151 | ARRAY_SIZE(cs42l43_pin_spdif_groups)), |
152 | PINCTRL_PINFUNCTION("irq" , cs42l43_pin_irq_groups, |
153 | ARRAY_SIZE(cs42l43_pin_irq_groups)), |
154 | PINCTRL_PINFUNCTION("mic-shutter" , cs42l43_pin_shutter_groups, |
155 | ARRAY_SIZE(cs42l43_pin_shutter_groups)), |
156 | PINCTRL_PINFUNCTION("spk-shutter" , cs42l43_pin_shutter_groups, |
157 | ARRAY_SIZE(cs42l43_pin_shutter_groups)), |
158 | }; |
159 | |
160 | static_assert(ARRAY_SIZE(cs42l43_pin_funcs) == CS42L43_FUNC_MAX); |
161 | static_assert(ARRAY_SIZE(cs42l43_pin_func_groups) == CS42L43_FUNC_MAX); |
162 | |
163 | static int cs42l43_pin_get_func_count(struct pinctrl_dev *pctldev) |
164 | { |
165 | return ARRAY_SIZE(cs42l43_pin_funcs); |
166 | } |
167 | |
168 | static const char *cs42l43_pin_get_func_name(struct pinctrl_dev *pctldev, |
169 | unsigned int func_idx) |
170 | { |
171 | return cs42l43_pin_funcs[func_idx]; |
172 | } |
173 | |
174 | static int cs42l43_pin_get_func_groups(struct pinctrl_dev *pctldev, |
175 | unsigned int func_idx, |
176 | const char * const **groups, |
177 | unsigned int * const num_groups) |
178 | { |
179 | *groups = cs42l43_pin_func_groups[func_idx].groups; |
180 | *num_groups = cs42l43_pin_func_groups[func_idx].ngroups; |
181 | |
182 | return 0; |
183 | } |
184 | |
185 | static int cs42l43_pin_set_mux(struct pinctrl_dev *pctldev, |
186 | unsigned int func_idx, unsigned int group_idx) |
187 | { |
188 | struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev); |
189 | unsigned int reg, mask, val; |
190 | |
191 | dev_dbg(priv->dev, "Setting %s to %s\n" , |
192 | cs42l43_pin_groups[group_idx].name, cs42l43_pin_funcs[func_idx]); |
193 | |
194 | switch (func_idx) { |
195 | case CS42L43_FUNC_MIC_SHT: |
196 | reg = CS42L43_SHUTTER_CONTROL; |
197 | mask = CS42L43_MIC_SHUTTER_CFG_MASK; |
198 | val = 0x2 << (group_idx + CS42L43_MIC_SHUTTER_CFG_SHIFT); |
199 | break; |
200 | case CS42L43_FUNC_SPK_SHT: |
201 | reg = CS42L43_SHUTTER_CONTROL; |
202 | mask = CS42L43_SPK_SHUTTER_CFG_MASK; |
203 | val = 0x2 << (group_idx + CS42L43_SPK_SHUTTER_CFG_SHIFT); |
204 | break; |
205 | default: |
206 | reg = CS42L43_GPIO_FN_SEL; |
207 | mask = BIT(group_idx + CS42L43_GPIO1_FN_SEL_SHIFT); |
208 | val = (func_idx == CS42L43_FUNC_GPIO) ? |
209 | (0x1 << (group_idx + CS42L43_GPIO1_FN_SEL_SHIFT)) : 0; |
210 | break; |
211 | } |
212 | |
213 | if (priv->shutters_locked && reg == CS42L43_SHUTTER_CONTROL) { |
214 | dev_err(priv->dev, "Shutter configuration not available\n" ); |
215 | return -EPERM; |
216 | } |
217 | |
218 | return regmap_update_bits(map: priv->regmap, reg, mask, val); |
219 | } |
220 | |
221 | static int cs42l43_gpio_set_direction(struct pinctrl_dev *pctldev, |
222 | struct pinctrl_gpio_range *range, |
223 | unsigned int offset, bool input) |
224 | { |
225 | struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev); |
226 | unsigned int shift = offset + CS42L43_GPIO1_DIR_SHIFT; |
227 | int ret; |
228 | |
229 | dev_dbg(priv->dev, "Setting gpio%d to %s\n" , |
230 | offset + 1, input ? "input" : "output" ); |
231 | |
232 | ret = pm_runtime_resume_and_get(dev: priv->dev); |
233 | if (ret) { |
234 | dev_err(priv->dev, "Failed to resume for direction: %d\n" , ret); |
235 | return ret; |
236 | } |
237 | |
238 | ret = regmap_update_bits(map: priv->regmap, CS42L43_GPIO_CTRL1, |
239 | BIT(shift), val: !!input << shift); |
240 | if (ret) |
241 | dev_err(priv->dev, "Failed to set gpio%d direction: %d\n" , |
242 | offset + 1, ret); |
243 | |
244 | pm_runtime_put(dev: priv->dev); |
245 | |
246 | return ret; |
247 | } |
248 | |
249 | static int cs42l43_gpio_request_enable(struct pinctrl_dev *pctldev, |
250 | struct pinctrl_gpio_range *range, |
251 | unsigned int offset) |
252 | { |
253 | return cs42l43_pin_set_mux(pctldev, func_idx: 0, group_idx: offset); |
254 | } |
255 | |
256 | static void cs42l43_gpio_disable_free(struct pinctrl_dev *pctldev, |
257 | struct pinctrl_gpio_range *range, |
258 | unsigned int offset) |
259 | { |
260 | cs42l43_gpio_set_direction(pctldev, range, offset, input: true); |
261 | } |
262 | |
263 | static const struct pinmux_ops cs42l43_pin_mux_ops = { |
264 | .get_functions_count = cs42l43_pin_get_func_count, |
265 | .get_function_name = cs42l43_pin_get_func_name, |
266 | .get_function_groups = cs42l43_pin_get_func_groups, |
267 | |
268 | .set_mux = cs42l43_pin_set_mux, |
269 | |
270 | .gpio_request_enable = cs42l43_gpio_request_enable, |
271 | .gpio_disable_free = cs42l43_gpio_disable_free, |
272 | .gpio_set_direction = cs42l43_gpio_set_direction, |
273 | |
274 | .strict = true, |
275 | }; |
276 | |
277 | static const unsigned int cs42l43_pin_drv_str_ma[] = { 1, 2, 4, 8, 9, 10, 12, 16 }; |
278 | |
279 | static int cs42l43_pin_get_drv_str(struct cs42l43_pin *priv, unsigned int pin) |
280 | { |
281 | const struct cs42l43_pin_data *pdat = cs42l43_pin_pins[pin].drv_data; |
282 | unsigned int val; |
283 | int ret; |
284 | |
285 | ret = regmap_read(map: priv->regmap, reg: pdat->reg, val: &val); |
286 | if (ret) |
287 | return ret; |
288 | |
289 | return cs42l43_pin_drv_str_ma[(val & pdat->mask) >> pdat->shift]; |
290 | } |
291 | |
292 | static int cs42l43_pin_set_drv_str(struct cs42l43_pin *priv, unsigned int pin, |
293 | unsigned int ma) |
294 | { |
295 | const struct cs42l43_pin_data *pdat = cs42l43_pin_pins[pin].drv_data; |
296 | int i; |
297 | |
298 | for (i = 0; i < ARRAY_SIZE(cs42l43_pin_drv_str_ma); i++) { |
299 | if (ma == cs42l43_pin_drv_str_ma[i]) { |
300 | if ((i << pdat->shift) > pdat->mask) |
301 | goto err; |
302 | |
303 | dev_dbg(priv->dev, "Set drive strength for %s to %d mA\n" , |
304 | cs42l43_pin_pins[pin].name, ma); |
305 | |
306 | return regmap_update_bits(map: priv->regmap, reg: pdat->reg, |
307 | mask: pdat->mask, val: i << pdat->shift); |
308 | } |
309 | } |
310 | |
311 | err: |
312 | dev_err(priv->dev, "Invalid drive strength for %s: %d mA\n" , |
313 | cs42l43_pin_pins[pin].name, ma); |
314 | return -EINVAL; |
315 | } |
316 | |
317 | static int cs42l43_pin_get_db(struct cs42l43_pin *priv, unsigned int pin) |
318 | { |
319 | unsigned int val; |
320 | int ret; |
321 | |
322 | if (pin >= CS42L43_NUM_GPIOS) |
323 | return -ENOTSUPP; |
324 | |
325 | ret = regmap_read(map: priv->regmap, CS42L43_GPIO_CTRL2, val: &val); |
326 | if (ret) |
327 | return ret; |
328 | |
329 | if (val & (CS42L43_GPIO1_DEGLITCH_BYP_MASK << pin)) |
330 | return 0; |
331 | |
332 | return 85; // Debounce is roughly 85uS |
333 | } |
334 | |
335 | static int cs42l43_pin_set_db(struct cs42l43_pin *priv, unsigned int pin, |
336 | unsigned int us) |
337 | { |
338 | if (pin >= CS42L43_NUM_GPIOS) |
339 | return -ENOTSUPP; |
340 | |
341 | dev_dbg(priv->dev, "Set debounce %s for %s\n" , |
342 | str_on_off(us), cs42l43_pin_pins[pin].name); |
343 | |
344 | return regmap_update_bits(map: priv->regmap, CS42L43_GPIO_CTRL2, |
345 | CS42L43_GPIO1_DEGLITCH_BYP_MASK << pin, |
346 | val: !!us << pin); |
347 | } |
348 | |
349 | static int cs42l43_pin_config_get(struct pinctrl_dev *pctldev, |
350 | unsigned int pin, unsigned long *config) |
351 | { |
352 | struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev); |
353 | unsigned int param = pinconf_to_config_param(config: *config); |
354 | int ret; |
355 | |
356 | switch (param) { |
357 | case PIN_CONFIG_DRIVE_STRENGTH: |
358 | ret = cs42l43_pin_get_drv_str(priv, pin); |
359 | if (ret < 0) |
360 | return ret; |
361 | break; |
362 | case PIN_CONFIG_INPUT_DEBOUNCE: |
363 | ret = cs42l43_pin_get_db(priv, pin); |
364 | if (ret < 0) |
365 | return ret; |
366 | break; |
367 | default: |
368 | return -ENOTSUPP; |
369 | } |
370 | |
371 | *config = pinconf_to_config_packed(param, argument: ret); |
372 | |
373 | return 0; |
374 | } |
375 | |
376 | static int cs42l43_pin_config_set(struct pinctrl_dev *pctldev, unsigned int pin, |
377 | unsigned long *configs, unsigned int num_configs) |
378 | { |
379 | struct cs42l43_pin *priv = pinctrl_dev_get_drvdata(pctldev); |
380 | unsigned int val; |
381 | int ret; |
382 | |
383 | while (num_configs) { |
384 | val = pinconf_to_config_argument(config: *configs); |
385 | |
386 | switch (pinconf_to_config_param(config: *configs)) { |
387 | case PIN_CONFIG_DRIVE_STRENGTH: |
388 | ret = cs42l43_pin_set_drv_str(priv, pin, ma: val); |
389 | if (ret) |
390 | return ret; |
391 | break; |
392 | case PIN_CONFIG_INPUT_DEBOUNCE: |
393 | ret = cs42l43_pin_set_db(priv, pin, us: val); |
394 | if (ret) |
395 | return ret; |
396 | break; |
397 | default: |
398 | return -ENOTSUPP; |
399 | } |
400 | |
401 | configs++; |
402 | num_configs--; |
403 | } |
404 | |
405 | return 0; |
406 | } |
407 | |
408 | static int cs42l43_pin_config_group_get(struct pinctrl_dev *pctldev, |
409 | unsigned int selector, unsigned long *config) |
410 | { |
411 | int i, ret; |
412 | |
413 | for (i = 0; i < cs42l43_pin_groups[selector].npins; ++i) { |
414 | ret = cs42l43_pin_config_get(pctldev, |
415 | pin: cs42l43_pin_groups[selector].pins[i], |
416 | config); |
417 | if (ret) |
418 | return ret; |
419 | } |
420 | |
421 | return 0; |
422 | } |
423 | |
424 | static int cs42l43_pin_config_group_set(struct pinctrl_dev *pctldev, |
425 | unsigned int selector, |
426 | unsigned long *configs, |
427 | unsigned int num_configs) |
428 | { |
429 | int i, ret; |
430 | |
431 | for (i = 0; i < cs42l43_pin_groups[selector].npins; ++i) { |
432 | ret = cs42l43_pin_config_set(pctldev, |
433 | pin: cs42l43_pin_groups[selector].pins[i], |
434 | configs, num_configs); |
435 | if (ret) |
436 | return ret; |
437 | } |
438 | |
439 | return 0; |
440 | } |
441 | |
442 | static const struct pinconf_ops cs42l43_pin_conf_ops = { |
443 | .is_generic = true, |
444 | |
445 | .pin_config_get = cs42l43_pin_config_get, |
446 | .pin_config_set = cs42l43_pin_config_set, |
447 | .pin_config_group_get = cs42l43_pin_config_group_get, |
448 | .pin_config_group_set = cs42l43_pin_config_group_set, |
449 | }; |
450 | |
451 | static struct pinctrl_desc cs42l43_pin_desc = { |
452 | .name = "cs42l43-pinctrl" , |
453 | .owner = THIS_MODULE, |
454 | |
455 | .pins = cs42l43_pin_pins, |
456 | .npins = ARRAY_SIZE(cs42l43_pin_pins), |
457 | |
458 | .pctlops = &cs42l43_pin_group_ops, |
459 | .pmxops = &cs42l43_pin_mux_ops, |
460 | .confops = &cs42l43_pin_conf_ops, |
461 | }; |
462 | |
463 | static int cs42l43_gpio_get(struct gpio_chip *chip, unsigned int offset) |
464 | { |
465 | struct cs42l43_pin *priv = gpiochip_get_data(gc: chip); |
466 | unsigned int val; |
467 | int ret; |
468 | |
469 | ret = pm_runtime_resume_and_get(dev: priv->dev); |
470 | if (ret) { |
471 | dev_err(priv->dev, "Failed to resume for get: %d\n" , ret); |
472 | return ret; |
473 | } |
474 | |
475 | ret = regmap_read(map: priv->regmap, CS42L43_GPIO_STS, val: &val); |
476 | if (ret) |
477 | dev_err(priv->dev, "Failed to get gpio%d: %d\n" , offset + 1, ret); |
478 | else |
479 | ret = !!(val & BIT(offset + CS42L43_GPIO1_STS_SHIFT)); |
480 | |
481 | pm_runtime_put(dev: priv->dev); |
482 | |
483 | return ret; |
484 | } |
485 | |
486 | static void cs42l43_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) |
487 | { |
488 | struct cs42l43_pin *priv = gpiochip_get_data(gc: chip); |
489 | unsigned int shift = offset + CS42L43_GPIO1_LVL_SHIFT; |
490 | int ret; |
491 | |
492 | dev_dbg(priv->dev, "Setting gpio%d to %s\n" , |
493 | offset + 1, str_high_low(value)); |
494 | |
495 | ret = pm_runtime_resume_and_get(dev: priv->dev); |
496 | if (ret) { |
497 | dev_err(priv->dev, "Failed to resume for set: %d\n" , ret); |
498 | return; |
499 | } |
500 | |
501 | ret = regmap_update_bits(map: priv->regmap, CS42L43_GPIO_CTRL1, |
502 | BIT(shift), val: value << shift); |
503 | if (ret) |
504 | dev_err(priv->dev, "Failed to set gpio%d: %d\n" , offset + 1, ret); |
505 | |
506 | pm_runtime_put(dev: priv->dev); |
507 | } |
508 | |
509 | static int cs42l43_gpio_direction_out(struct gpio_chip *chip, |
510 | unsigned int offset, int value) |
511 | { |
512 | cs42l43_gpio_set(chip, offset, value); |
513 | |
514 | return pinctrl_gpio_direction_output(gc: chip, offset); |
515 | } |
516 | |
517 | static int cs42l43_gpio_add_pin_ranges(struct gpio_chip *chip) |
518 | { |
519 | struct cs42l43_pin *priv = gpiochip_get_data(gc: chip); |
520 | int ret; |
521 | |
522 | ret = gpiochip_add_pin_range(gc: &priv->gpio_chip, pinctl_name: priv->gpio_chip.label, |
523 | gpio_offset: 0, pin_offset: 0, CS42L43_NUM_GPIOS); |
524 | if (ret) |
525 | dev_err(priv->dev, "Failed to add GPIO pin range: %d\n" , ret); |
526 | |
527 | return ret; |
528 | } |
529 | |
530 | static int cs42l43_pin_probe(struct platform_device *pdev) |
531 | { |
532 | struct cs42l43 *cs42l43 = dev_get_drvdata(dev: pdev->dev.parent); |
533 | struct cs42l43_pin *priv; |
534 | struct pinctrl_dev *pctldev; |
535 | struct fwnode_handle *fwnode = dev_fwnode(cs42l43->dev); |
536 | int ret; |
537 | |
538 | priv = devm_kzalloc(dev: &pdev->dev, size: sizeof(*priv), GFP_KERNEL); |
539 | if (!priv) |
540 | return -ENOMEM; |
541 | |
542 | priv->dev = &pdev->dev; |
543 | priv->regmap = cs42l43->regmap; |
544 | |
545 | priv->shutters_locked = cs42l43->hw_lock; |
546 | |
547 | priv->gpio_chip.request = gpiochip_generic_request; |
548 | priv->gpio_chip.free = gpiochip_generic_free; |
549 | priv->gpio_chip.direction_input = pinctrl_gpio_direction_input; |
550 | priv->gpio_chip.direction_output = cs42l43_gpio_direction_out; |
551 | priv->gpio_chip.add_pin_ranges = cs42l43_gpio_add_pin_ranges; |
552 | priv->gpio_chip.get = cs42l43_gpio_get; |
553 | priv->gpio_chip.set = cs42l43_gpio_set; |
554 | priv->gpio_chip.label = dev_name(dev: priv->dev); |
555 | priv->gpio_chip.parent = priv->dev; |
556 | priv->gpio_chip.can_sleep = true; |
557 | priv->gpio_chip.base = -1; |
558 | priv->gpio_chip.ngpio = CS42L43_NUM_GPIOS; |
559 | |
560 | if (is_of_node(fwnode)) { |
561 | fwnode = fwnode_get_named_child_node(fwnode, childname: "pinctrl" ); |
562 | |
563 | if (fwnode && !fwnode->dev) |
564 | fwnode->dev = priv->dev; |
565 | } |
566 | |
567 | priv->gpio_chip.fwnode = fwnode; |
568 | |
569 | device_set_node(dev: priv->dev, fwnode); |
570 | |
571 | devm_pm_runtime_enable(dev: priv->dev); |
572 | pm_runtime_idle(dev: priv->dev); |
573 | |
574 | pctldev = devm_pinctrl_register(dev: priv->dev, pctldesc: &cs42l43_pin_desc, driver_data: priv); |
575 | if (IS_ERR(ptr: pctldev)) |
576 | return dev_err_probe(dev: priv->dev, err: PTR_ERR(ptr: pctldev), |
577 | fmt: "Failed to register pinctrl\n" ); |
578 | |
579 | ret = devm_gpiochip_add_data(priv->dev, &priv->gpio_chip, priv); |
580 | if (ret) |
581 | return dev_err_probe(dev: priv->dev, err: ret, |
582 | fmt: "Failed to register gpiochip\n" ); |
583 | |
584 | return 0; |
585 | } |
586 | |
587 | static const struct platform_device_id cs42l43_pin_id_table[] = { |
588 | { "cs42l43-pinctrl" , }, |
589 | {} |
590 | }; |
591 | MODULE_DEVICE_TABLE(platform, cs42l43_pin_id_table); |
592 | |
593 | static struct platform_driver cs42l43_pin_driver = { |
594 | .driver = { |
595 | .name = "cs42l43-pinctrl" , |
596 | }, |
597 | .probe = cs42l43_pin_probe, |
598 | .id_table = cs42l43_pin_id_table, |
599 | }; |
600 | module_platform_driver(cs42l43_pin_driver); |
601 | |
602 | MODULE_DESCRIPTION("CS42L43 Pinctrl Driver" ); |
603 | MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>" ); |
604 | MODULE_LICENSE("GPL" ); |
605 | |