1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * ROHM BD9571MWV-M GPIO driver
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * This program is free software; you can redistribute it and/or
7*4882a593Smuzhiyun * modify it under the terms of the GNU General Public License version 2 as
8*4882a593Smuzhiyun * published by the Free Software Foundation.
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * This program is distributed "as is" WITHOUT ANY WARRANTY of any
11*4882a593Smuzhiyun * kind, whether expressed or implied; without even the implied warranty
12*4882a593Smuzhiyun * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*4882a593Smuzhiyun * GNU General Public License version 2 for more details.
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * Based on the TPS65086 driver
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * NOTE: Interrupts are not supported yet.
18*4882a593Smuzhiyun */
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <linux/gpio/driver.h>
21*4882a593Smuzhiyun #include <linux/module.h>
22*4882a593Smuzhiyun #include <linux/platform_device.h>
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun #include <linux/mfd/bd9571mwv.h>
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun struct bd9571mwv_gpio {
27*4882a593Smuzhiyun struct gpio_chip chip;
28*4882a593Smuzhiyun struct bd9571mwv *bd;
29*4882a593Smuzhiyun };
30*4882a593Smuzhiyun
bd9571mwv_gpio_get_direction(struct gpio_chip * chip,unsigned int offset)31*4882a593Smuzhiyun static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip,
32*4882a593Smuzhiyun unsigned int offset)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
35*4882a593Smuzhiyun int ret, val;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_DIR, &val);
38*4882a593Smuzhiyun if (ret < 0)
39*4882a593Smuzhiyun return ret;
40*4882a593Smuzhiyun if (val & BIT(offset))
41*4882a593Smuzhiyun return GPIO_LINE_DIRECTION_IN;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun return GPIO_LINE_DIRECTION_OUT;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
bd9571mwv_gpio_direction_input(struct gpio_chip * chip,unsigned int offset)46*4882a593Smuzhiyun static int bd9571mwv_gpio_direction_input(struct gpio_chip *chip,
47*4882a593Smuzhiyun unsigned int offset)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR,
52*4882a593Smuzhiyun BIT(offset), 0);
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun return 0;
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun
bd9571mwv_gpio_direction_output(struct gpio_chip * chip,unsigned int offset,int value)57*4882a593Smuzhiyun static int bd9571mwv_gpio_direction_output(struct gpio_chip *chip,
58*4882a593Smuzhiyun unsigned int offset, int value)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /* Set the initial value */
63*4882a593Smuzhiyun regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT,
64*4882a593Smuzhiyun BIT(offset), value ? BIT(offset) : 0);
65*4882a593Smuzhiyun regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR,
66*4882a593Smuzhiyun BIT(offset), BIT(offset));
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun return 0;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
bd9571mwv_gpio_get(struct gpio_chip * chip,unsigned int offset)71*4882a593Smuzhiyun static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
74*4882a593Smuzhiyun int ret, val;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_IN, &val);
77*4882a593Smuzhiyun if (ret < 0)
78*4882a593Smuzhiyun return ret;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun return val & BIT(offset);
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
bd9571mwv_gpio_set(struct gpio_chip * chip,unsigned int offset,int value)83*4882a593Smuzhiyun static void bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset,
84*4882a593Smuzhiyun int value)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT,
89*4882a593Smuzhiyun BIT(offset), value ? BIT(offset) : 0);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun static const struct gpio_chip template_chip = {
93*4882a593Smuzhiyun .label = "bd9571mwv-gpio",
94*4882a593Smuzhiyun .owner = THIS_MODULE,
95*4882a593Smuzhiyun .get_direction = bd9571mwv_gpio_get_direction,
96*4882a593Smuzhiyun .direction_input = bd9571mwv_gpio_direction_input,
97*4882a593Smuzhiyun .direction_output = bd9571mwv_gpio_direction_output,
98*4882a593Smuzhiyun .get = bd9571mwv_gpio_get,
99*4882a593Smuzhiyun .set = bd9571mwv_gpio_set,
100*4882a593Smuzhiyun .base = -1,
101*4882a593Smuzhiyun .ngpio = 2,
102*4882a593Smuzhiyun .can_sleep = true,
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun
bd9571mwv_gpio_probe(struct platform_device * pdev)105*4882a593Smuzhiyun static int bd9571mwv_gpio_probe(struct platform_device *pdev)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun struct bd9571mwv_gpio *gpio;
108*4882a593Smuzhiyun int ret;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
111*4882a593Smuzhiyun if (!gpio)
112*4882a593Smuzhiyun return -ENOMEM;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun platform_set_drvdata(pdev, gpio);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun gpio->bd = dev_get_drvdata(pdev->dev.parent);
117*4882a593Smuzhiyun gpio->chip = template_chip;
118*4882a593Smuzhiyun gpio->chip.parent = gpio->bd->dev;
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
121*4882a593Smuzhiyun if (ret < 0) {
122*4882a593Smuzhiyun dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
123*4882a593Smuzhiyun return ret;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun return 0;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun static const struct platform_device_id bd9571mwv_gpio_id_table[] = {
130*4882a593Smuzhiyun { "bd9571mwv-gpio", },
131*4882a593Smuzhiyun { /* sentinel */ }
132*4882a593Smuzhiyun };
133*4882a593Smuzhiyun MODULE_DEVICE_TABLE(platform, bd9571mwv_gpio_id_table);
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun static struct platform_driver bd9571mwv_gpio_driver = {
136*4882a593Smuzhiyun .driver = {
137*4882a593Smuzhiyun .name = "bd9571mwv-gpio",
138*4882a593Smuzhiyun },
139*4882a593Smuzhiyun .probe = bd9571mwv_gpio_probe,
140*4882a593Smuzhiyun .id_table = bd9571mwv_gpio_id_table,
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun module_platform_driver(bd9571mwv_gpio_driver);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun MODULE_AUTHOR("Marek Vasut <marek.vasut+renesas@gmail.com>");
145*4882a593Smuzhiyun MODULE_DESCRIPTION("BD9571MWV GPIO driver");
146*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
147