1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // Copyright (C) 2018 ROHM Semiconductors |
3 | |
4 | #include <linux/gpio/driver.h> |
5 | #include <linux/mfd/rohm-bd71828.h> |
6 | #include <linux/module.h> |
7 | #include <linux/platform_device.h> |
8 | #include <linux/regmap.h> |
9 | |
10 | #define GPIO_OUT_REG(off) (BD71828_REG_GPIO_CTRL1 + (off)) |
11 | #define HALL_GPIO_OFFSET 3 |
12 | |
13 | struct bd71828_gpio { |
14 | struct regmap *regmap; |
15 | struct device *dev; |
16 | struct gpio_chip gpio; |
17 | }; |
18 | |
19 | static void bd71828_gpio_set(struct gpio_chip *chip, unsigned int offset, |
20 | int value) |
21 | { |
22 | int ret; |
23 | struct bd71828_gpio *bdgpio = gpiochip_get_data(gc: chip); |
24 | u8 val = (value) ? BD71828_GPIO_OUT_HI : BD71828_GPIO_OUT_LO; |
25 | |
26 | /* |
27 | * The HALL input pin can only be used as input. If this is the pin |
28 | * we are dealing with - then we are done |
29 | */ |
30 | if (offset == HALL_GPIO_OFFSET) |
31 | return; |
32 | |
33 | ret = regmap_update_bits(map: bdgpio->regmap, GPIO_OUT_REG(offset), |
34 | BD71828_GPIO_OUT_MASK, val); |
35 | if (ret) |
36 | dev_err(bdgpio->dev, "Could not set gpio to %d\n" , value); |
37 | } |
38 | |
39 | static int bd71828_gpio_get(struct gpio_chip *chip, unsigned int offset) |
40 | { |
41 | int ret; |
42 | unsigned int val; |
43 | struct bd71828_gpio *bdgpio = gpiochip_get_data(gc: chip); |
44 | |
45 | if (offset == HALL_GPIO_OFFSET) |
46 | ret = regmap_read(map: bdgpio->regmap, BD71828_REG_IO_STAT, |
47 | val: &val); |
48 | else |
49 | ret = regmap_read(map: bdgpio->regmap, GPIO_OUT_REG(offset), |
50 | val: &val); |
51 | if (!ret) |
52 | ret = (val & BD71828_GPIO_OUT_MASK); |
53 | |
54 | return ret; |
55 | } |
56 | |
57 | static int bd71828_gpio_set_config(struct gpio_chip *chip, unsigned int offset, |
58 | unsigned long config) |
59 | { |
60 | struct bd71828_gpio *bdgpio = gpiochip_get_data(gc: chip); |
61 | |
62 | if (offset == HALL_GPIO_OFFSET) |
63 | return -ENOTSUPP; |
64 | |
65 | switch (pinconf_to_config_param(config)) { |
66 | case PIN_CONFIG_DRIVE_OPEN_DRAIN: |
67 | return regmap_update_bits(map: bdgpio->regmap, |
68 | GPIO_OUT_REG(offset), |
69 | BD71828_GPIO_DRIVE_MASK, |
70 | BD71828_GPIO_OPEN_DRAIN); |
71 | case PIN_CONFIG_DRIVE_PUSH_PULL: |
72 | return regmap_update_bits(map: bdgpio->regmap, |
73 | GPIO_OUT_REG(offset), |
74 | BD71828_GPIO_DRIVE_MASK, |
75 | BD71828_GPIO_PUSH_PULL); |
76 | default: |
77 | break; |
78 | } |
79 | return -ENOTSUPP; |
80 | } |
81 | |
82 | static int bd71828_get_direction(struct gpio_chip *chip, unsigned int offset) |
83 | { |
84 | /* |
85 | * Pin usage is selected by OTP data. We can't read it runtime. Hence |
86 | * we trust that if the pin is not excluded by "gpio-reserved-ranges" |
87 | * the OTP configuration is set to OUT. (Other pins but HALL input pin |
88 | * on BD71828 can't really be used for general purpose input - input |
89 | * states are used for specific cases like regulator control or |
90 | * PMIC_ON_REQ. |
91 | */ |
92 | if (offset == HALL_GPIO_OFFSET) |
93 | return GPIO_LINE_DIRECTION_IN; |
94 | |
95 | return GPIO_LINE_DIRECTION_OUT; |
96 | } |
97 | |
98 | static int bd71828_probe(struct platform_device *pdev) |
99 | { |
100 | struct device *dev = &pdev->dev; |
101 | struct bd71828_gpio *bdgpio; |
102 | |
103 | bdgpio = devm_kzalloc(dev, size: sizeof(*bdgpio), GFP_KERNEL); |
104 | if (!bdgpio) |
105 | return -ENOMEM; |
106 | |
107 | bdgpio->dev = dev; |
108 | bdgpio->gpio.parent = dev->parent; |
109 | bdgpio->gpio.label = "bd71828-gpio" ; |
110 | bdgpio->gpio.owner = THIS_MODULE; |
111 | bdgpio->gpio.get_direction = bd71828_get_direction; |
112 | bdgpio->gpio.set_config = bd71828_gpio_set_config; |
113 | bdgpio->gpio.can_sleep = true; |
114 | bdgpio->gpio.get = bd71828_gpio_get; |
115 | bdgpio->gpio.set = bd71828_gpio_set; |
116 | bdgpio->gpio.base = -1; |
117 | |
118 | /* |
119 | * See if we need some implementation to mark some PINs as |
120 | * not controllable based on DT info or if core can handle |
121 | * "gpio-reserved-ranges" and exclude them from control |
122 | */ |
123 | bdgpio->gpio.ngpio = 4; |
124 | bdgpio->regmap = dev_get_regmap(dev: dev->parent, NULL); |
125 | if (!bdgpio->regmap) |
126 | return -ENODEV; |
127 | |
128 | return devm_gpiochip_add_data(dev, &bdgpio->gpio, bdgpio); |
129 | } |
130 | |
131 | static struct platform_driver bd71828_gpio = { |
132 | .driver = { |
133 | .name = "bd71828-gpio" |
134 | }, |
135 | .probe = bd71828_probe, |
136 | }; |
137 | |
138 | module_platform_driver(bd71828_gpio); |
139 | |
140 | MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>" ); |
141 | MODULE_DESCRIPTION("BD71828 voltage regulator driver" ); |
142 | MODULE_LICENSE("GPL" ); |
143 | MODULE_ALIAS("platform:bd71828-gpio" ); |
144 | |