Commit | Line | Data |
---|---|---|
c31f625d MV |
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 | ||
c31f625d | 13 | struct bd71828_gpio { |
82bf0afd MV |
14 | struct regmap *regmap; |
15 | struct device *dev; | |
c31f625d MV |
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(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 | ||
82bf0afd | 33 | ret = regmap_update_bits(bdgpio->regmap, GPIO_OUT_REG(offset), |
c31f625d MV |
34 | BD71828_GPIO_OUT_MASK, val); |
35 | if (ret) | |
82bf0afd | 36 | dev_err(bdgpio->dev, "Could not set gpio to %d\n", value); |
c31f625d MV |
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(chip); | |
44 | ||
45 | if (offset == HALL_GPIO_OFFSET) | |
82bf0afd | 46 | ret = regmap_read(bdgpio->regmap, BD71828_REG_IO_STAT, |
c31f625d MV |
47 | &val); |
48 | else | |
82bf0afd | 49 | ret = regmap_read(bdgpio->regmap, GPIO_OUT_REG(offset), |
c31f625d MV |
50 | &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(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: | |
82bf0afd | 67 | return regmap_update_bits(bdgpio->regmap, |
c31f625d MV |
68 | GPIO_OUT_REG(offset), |
69 | BD71828_GPIO_DRIVE_MASK, | |
70 | BD71828_GPIO_OPEN_DRAIN); | |
71 | case PIN_CONFIG_DRIVE_PUSH_PULL: | |
82bf0afd | 72 | return regmap_update_bits(bdgpio->regmap, |
c31f625d MV |
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 | { | |
cb38cd70 | 100 | struct device *dev = &pdev->dev; |
c31f625d | 101 | struct bd71828_gpio *bdgpio; |
c31f625d | 102 | |
cb38cd70 | 103 | bdgpio = devm_kzalloc(dev, sizeof(*bdgpio), GFP_KERNEL); |
c31f625d MV |
104 | if (!bdgpio) |
105 | return -ENOMEM; | |
106 | ||
cb38cd70 BG |
107 | bdgpio->dev = dev; |
108 | bdgpio->gpio.parent = dev->parent; | |
c31f625d MV |
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; | |
cb38cd70 | 124 | bdgpio->regmap = dev_get_regmap(dev->parent, NULL); |
82bf0afd MV |
125 | if (!bdgpio->regmap) |
126 | return -ENODEV; | |
c31f625d | 127 | |
cb38cd70 | 128 | return devm_gpiochip_add_data(dev, &bdgpio->gpio, bdgpio); |
c31f625d MV |
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"); |