1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * GPIO Driver for Dialog DA9052 PMICs.
5 * Copyright(c) 2011 Dialog Semiconductor Ltd.
7 * Author: David Dajun Chen <dchen@diasemi.com>
9 #include <linux/module.h>
11 #include <linux/uaccess.h>
12 #include <linux/platform_device.h>
13 #include <linux/gpio/driver.h>
14 #include <linux/syscalls.h>
15 #include <linux/seq_file.h>
17 #include <linux/mfd/da9052/da9052.h>
18 #include <linux/mfd/da9052/reg.h>
19 #include <linux/mfd/da9052/pdata.h>
21 #define DA9052_INPUT 1
22 #define DA9052_OUTPUT_OPENDRAIN 2
23 #define DA9052_OUTPUT_PUSHPULL 3
25 #define DA9052_SUPPLY_VDD_IO1 0
27 #define DA9052_DEBOUNCING_OFF 0
28 #define DA9052_DEBOUNCING_ON 1
30 #define DA9052_OUTPUT_LOWLEVEL 0
32 #define DA9052_ACTIVE_LOW 0
33 #define DA9052_ACTIVE_HIGH 1
35 #define DA9052_GPIO_MAX_PORTS_PER_REGISTER 8
36 #define DA9052_GPIO_SHIFT_COUNT(no) (no%8)
37 #define DA9052_GPIO_MASK_UPPER_NIBBLE 0xF0
38 #define DA9052_GPIO_MASK_LOWER_NIBBLE 0x0F
39 #define DA9052_GPIO_NIBBLE_SHIFT 4
40 #define DA9052_IRQ_GPI0 16
41 #define DA9052_GPIO_ODD_SHIFT 7
42 #define DA9052_GPIO_EVEN_SHIFT 3
45 struct da9052
*da9052
;
49 static unsigned char da9052_gpio_port_odd(unsigned offset
)
54 static int da9052_gpio_get(struct gpio_chip
*gc
, unsigned offset
)
56 struct da9052_gpio
*gpio
= gpiochip_get_data(gc
);
57 int da9052_port_direction
= 0;
60 ret
= da9052_reg_read(gpio
->da9052
,
61 DA9052_GPIO_0_1_REG
+ (offset
>> 1));
65 if (da9052_gpio_port_odd(offset
)) {
66 da9052_port_direction
= ret
& DA9052_GPIO_ODD_PORT_PIN
;
67 da9052_port_direction
>>= 4;
69 da9052_port_direction
= ret
& DA9052_GPIO_EVEN_PORT_PIN
;
72 switch (da9052_port_direction
) {
74 if (offset
< DA9052_GPIO_MAX_PORTS_PER_REGISTER
)
75 ret
= da9052_reg_read(gpio
->da9052
,
78 ret
= da9052_reg_read(gpio
->da9052
,
82 return !!(ret
& (1 << DA9052_GPIO_SHIFT_COUNT(offset
)));
83 case DA9052_OUTPUT_PUSHPULL
:
84 if (da9052_gpio_port_odd(offset
))
85 return !!(ret
& DA9052_GPIO_ODD_PORT_MODE
);
87 return !!(ret
& DA9052_GPIO_EVEN_PORT_MODE
);
93 static void da9052_gpio_set(struct gpio_chip
*gc
, unsigned offset
, int value
)
95 struct da9052_gpio
*gpio
= gpiochip_get_data(gc
);
98 if (da9052_gpio_port_odd(offset
)) {
99 ret
= da9052_reg_update(gpio
->da9052
, (offset
>> 1) +
101 DA9052_GPIO_ODD_PORT_MODE
,
102 value
<< DA9052_GPIO_ODD_SHIFT
);
104 dev_err(gpio
->da9052
->dev
,
105 "Failed to updated gpio odd reg,%d",
108 ret
= da9052_reg_update(gpio
->da9052
, (offset
>> 1) +
110 DA9052_GPIO_EVEN_PORT_MODE
,
111 value
<< DA9052_GPIO_EVEN_SHIFT
);
113 dev_err(gpio
->da9052
->dev
,
114 "Failed to updated gpio even reg,%d",
119 static int da9052_gpio_direction_input(struct gpio_chip
*gc
, unsigned offset
)
121 struct da9052_gpio
*gpio
= gpiochip_get_data(gc
);
122 unsigned char register_value
;
125 /* Format: function - 2 bits type - 1 bit mode - 1 bit */
126 register_value
= DA9052_INPUT
| DA9052_ACTIVE_LOW
<< 2 |
127 DA9052_DEBOUNCING_ON
<< 3;
129 if (da9052_gpio_port_odd(offset
))
130 ret
= da9052_reg_update(gpio
->da9052
, (offset
>> 1) +
132 DA9052_GPIO_MASK_UPPER_NIBBLE
,
134 DA9052_GPIO_NIBBLE_SHIFT
));
136 ret
= da9052_reg_update(gpio
->da9052
, (offset
>> 1) +
138 DA9052_GPIO_MASK_LOWER_NIBBLE
,
144 static int da9052_gpio_direction_output(struct gpio_chip
*gc
,
145 unsigned offset
, int value
)
147 struct da9052_gpio
*gpio
= gpiochip_get_data(gc
);
148 unsigned char register_value
;
151 /* Format: Function - 2 bits Type - 1 bit Mode - 1 bit */
152 register_value
= DA9052_OUTPUT_PUSHPULL
| DA9052_SUPPLY_VDD_IO1
<< 2 |
155 if (da9052_gpio_port_odd(offset
))
156 ret
= da9052_reg_update(gpio
->da9052
, (offset
>> 1) +
158 DA9052_GPIO_MASK_UPPER_NIBBLE
,
160 DA9052_GPIO_NIBBLE_SHIFT
));
162 ret
= da9052_reg_update(gpio
->da9052
, (offset
>> 1) +
164 DA9052_GPIO_MASK_LOWER_NIBBLE
,
170 static int da9052_gpio_to_irq(struct gpio_chip
*gc
, u32 offset
)
172 struct da9052_gpio
*gpio
= gpiochip_get_data(gc
);
173 struct da9052
*da9052
= gpio
->da9052
;
177 irq
= regmap_irq_get_virq(da9052
->irq_data
, DA9052_IRQ_GPI0
+ offset
);
182 static const struct gpio_chip reference_gp
= {
183 .label
= "da9052-gpio",
184 .owner
= THIS_MODULE
,
185 .get
= da9052_gpio_get
,
186 .set
= da9052_gpio_set
,
187 .direction_input
= da9052_gpio_direction_input
,
188 .direction_output
= da9052_gpio_direction_output
,
189 .to_irq
= da9052_gpio_to_irq
,
195 static int da9052_gpio_probe(struct platform_device
*pdev
)
197 struct da9052_gpio
*gpio
;
198 struct da9052_pdata
*pdata
;
201 gpio
= devm_kzalloc(&pdev
->dev
, sizeof(*gpio
), GFP_KERNEL
);
205 gpio
->da9052
= dev_get_drvdata(pdev
->dev
.parent
);
206 pdata
= dev_get_platdata(gpio
->da9052
->dev
);
208 gpio
->gp
= reference_gp
;
209 if (pdata
&& pdata
->gpio_base
)
210 gpio
->gp
.base
= pdata
->gpio_base
;
212 ret
= devm_gpiochip_add_data(&pdev
->dev
, &gpio
->gp
, gpio
);
214 dev_err(&pdev
->dev
, "Could not register gpiochip, %d\n", ret
);
218 platform_set_drvdata(pdev
, gpio
);
223 static struct platform_driver da9052_gpio_driver
= {
224 .probe
= da9052_gpio_probe
,
226 .name
= "da9052-gpio",
230 module_platform_driver(da9052_gpio_driver
);
232 MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
233 MODULE_DESCRIPTION("DA9052 GPIO Device Driver");
234 MODULE_LICENSE("GPL");
235 MODULE_ALIAS("platform:da9052-gpio");