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