1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2019, Linaro Limited |
3 | |
4 | #include <linux/mod_devicetable.h> |
5 | #include <linux/module.h> |
6 | #include <linux/gpio/driver.h> |
7 | #include <linux/platform_device.h> |
8 | #include <linux/regmap.h> |
9 | #include <linux/slab.h> |
10 | |
11 | #define WCD_PIN_MASK(p) BIT(p) |
12 | #define WCD_REG_DIR_CTL_OFFSET 0x42 |
13 | #define WCD_REG_VAL_CTL_OFFSET 0x43 |
14 | #define WCD934X_NPINS 5 |
15 | |
16 | struct wcd_gpio_data { |
17 | struct regmap *map; |
18 | struct gpio_chip chip; |
19 | }; |
20 | |
21 | static int wcd_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) |
22 | { |
23 | struct wcd_gpio_data *data = gpiochip_get_data(gc: chip); |
24 | unsigned int value; |
25 | int ret; |
26 | |
27 | ret = regmap_read(map: data->map, WCD_REG_DIR_CTL_OFFSET, val: &value); |
28 | if (ret < 0) |
29 | return ret; |
30 | |
31 | if (value & WCD_PIN_MASK(pin)) |
32 | return GPIO_LINE_DIRECTION_OUT; |
33 | |
34 | return GPIO_LINE_DIRECTION_IN; |
35 | } |
36 | |
37 | static int wcd_gpio_direction_input(struct gpio_chip *chip, unsigned int pin) |
38 | { |
39 | struct wcd_gpio_data *data = gpiochip_get_data(gc: chip); |
40 | |
41 | return regmap_update_bits(map: data->map, WCD_REG_DIR_CTL_OFFSET, |
42 | WCD_PIN_MASK(pin), val: 0); |
43 | } |
44 | |
45 | static int wcd_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, |
46 | int val) |
47 | { |
48 | struct wcd_gpio_data *data = gpiochip_get_data(gc: chip); |
49 | |
50 | regmap_update_bits(map: data->map, WCD_REG_DIR_CTL_OFFSET, |
51 | WCD_PIN_MASK(pin), WCD_PIN_MASK(pin)); |
52 | |
53 | return regmap_update_bits(map: data->map, WCD_REG_VAL_CTL_OFFSET, |
54 | WCD_PIN_MASK(pin), |
55 | val: val ? WCD_PIN_MASK(pin) : 0); |
56 | } |
57 | |
58 | static int wcd_gpio_get(struct gpio_chip *chip, unsigned int pin) |
59 | { |
60 | struct wcd_gpio_data *data = gpiochip_get_data(gc: chip); |
61 | unsigned int value; |
62 | |
63 | regmap_read(map: data->map, WCD_REG_VAL_CTL_OFFSET, val: &value); |
64 | |
65 | return !!(value & WCD_PIN_MASK(pin)); |
66 | } |
67 | |
68 | static void wcd_gpio_set(struct gpio_chip *chip, unsigned int pin, int val) |
69 | { |
70 | struct wcd_gpio_data *data = gpiochip_get_data(gc: chip); |
71 | |
72 | regmap_update_bits(map: data->map, WCD_REG_VAL_CTL_OFFSET, |
73 | WCD_PIN_MASK(pin), val: val ? WCD_PIN_MASK(pin) : 0); |
74 | } |
75 | |
76 | static int wcd_gpio_probe(struct platform_device *pdev) |
77 | { |
78 | struct device *dev = &pdev->dev; |
79 | struct wcd_gpio_data *data; |
80 | struct gpio_chip *chip; |
81 | |
82 | data = devm_kzalloc(dev, size: sizeof(*data), GFP_KERNEL); |
83 | if (!data) |
84 | return -ENOMEM; |
85 | |
86 | data->map = dev_get_regmap(dev: dev->parent, NULL); |
87 | if (!data->map) { |
88 | dev_err(dev, "%s: failed to get regmap\n" , __func__); |
89 | return -EINVAL; |
90 | } |
91 | |
92 | chip = &data->chip; |
93 | chip->direction_input = wcd_gpio_direction_input; |
94 | chip->direction_output = wcd_gpio_direction_output; |
95 | chip->get_direction = wcd_gpio_get_direction; |
96 | chip->get = wcd_gpio_get; |
97 | chip->set = wcd_gpio_set; |
98 | chip->parent = dev; |
99 | chip->base = -1; |
100 | chip->ngpio = WCD934X_NPINS; |
101 | chip->label = dev_name(dev); |
102 | chip->can_sleep = false; |
103 | |
104 | return devm_gpiochip_add_data(dev, chip, data); |
105 | } |
106 | |
107 | static const struct of_device_id wcd_gpio_of_match[] = { |
108 | { .compatible = "qcom,wcd9340-gpio" }, |
109 | { .compatible = "qcom,wcd9341-gpio" }, |
110 | { } |
111 | }; |
112 | MODULE_DEVICE_TABLE(of, wcd_gpio_of_match); |
113 | |
114 | static struct platform_driver wcd_gpio_driver = { |
115 | .driver = { |
116 | .name = "wcd934x-gpio" , |
117 | .of_match_table = wcd_gpio_of_match, |
118 | }, |
119 | .probe = wcd_gpio_probe, |
120 | }; |
121 | |
122 | module_platform_driver(wcd_gpio_driver); |
123 | MODULE_DESCRIPTION("Qualcomm Technologies, Inc WCD GPIO control driver" ); |
124 | MODULE_LICENSE("GPL v2" ); |
125 | |