Blame view

drivers/gpio/gpio-max77620.c 9.01 KB
75a6faf61   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
2
3
4
5
  /*
   * MAXIM MAX77620 GPIO driver
   *
   * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   */
  
  #include <linux/gpio/driver.h>
  #include <linux/interrupt.h>
  #include <linux/mfd/max77620.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
  #include <linux/regmap.h>
  
  #define GPIO_REG_ADDR(offset) (MAX77620_REG_GPIO0 + offset)
  
  struct max77620_gpio {
  	struct gpio_chip	gpio_chip;
  	struct regmap		*rmap;
  	struct device		*dev;
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
21
22
23
  };
  
  static const struct regmap_irq max77620_gpio_irqs[] = {
ff93ec749   Laxman Dewangan   gpio: max77620: C...
24
  	[0] = {
ff93ec749   Laxman Dewangan   gpio: max77620: C...
25
  		.reg_offset = 0,
1c2928e3e   Matti Vaittinen   regmap: regmap-ir...
26
27
28
29
30
31
32
33
  		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE0,
  		.type = {
  			.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
  			.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
  			.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
  			.type_reg_offset = 0,
  			.types_supported = IRQ_TYPE_EDGE_BOTH,
  		},
ff93ec749   Laxman Dewangan   gpio: max77620: C...
34
35
  	},
  	[1] = {
ff93ec749   Laxman Dewangan   gpio: max77620: C...
36
  		.reg_offset = 0,
1c2928e3e   Matti Vaittinen   regmap: regmap-ir...
37
38
39
40
41
42
43
44
  		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE1,
  		.type = {
  			.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
  			.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
  			.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
  			.type_reg_offset = 1,
  			.types_supported = IRQ_TYPE_EDGE_BOTH,
  		},
ff93ec749   Laxman Dewangan   gpio: max77620: C...
45
46
  	},
  	[2] = {
ff93ec749   Laxman Dewangan   gpio: max77620: C...
47
  		.reg_offset = 0,
1c2928e3e   Matti Vaittinen   regmap: regmap-ir...
48
49
50
51
52
53
54
55
  		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE2,
  		.type = {
  			.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
  			.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
  			.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
  			.type_reg_offset = 2,
  			.types_supported = IRQ_TYPE_EDGE_BOTH,
  		},
ff93ec749   Laxman Dewangan   gpio: max77620: C...
56
57
  	},
  	[3] = {
ff93ec749   Laxman Dewangan   gpio: max77620: C...
58
  		.reg_offset = 0,
1c2928e3e   Matti Vaittinen   regmap: regmap-ir...
59
60
61
62
63
64
65
66
  		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE3,
  		.type = {
  			.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
  			.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
  			.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
  			.type_reg_offset = 3,
  			.types_supported = IRQ_TYPE_EDGE_BOTH,
  		},
ff93ec749   Laxman Dewangan   gpio: max77620: C...
67
68
  	},
  	[4] = {
ff93ec749   Laxman Dewangan   gpio: max77620: C...
69
  		.reg_offset = 0,
1c2928e3e   Matti Vaittinen   regmap: regmap-ir...
70
71
72
73
74
75
76
77
  		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE4,
  		.type = {
  			.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
  			.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
  			.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
  			.type_reg_offset = 4,
  			.types_supported = IRQ_TYPE_EDGE_BOTH,
  		},
ff93ec749   Laxman Dewangan   gpio: max77620: C...
78
79
  	},
  	[5] = {
ff93ec749   Laxman Dewangan   gpio: max77620: C...
80
  		.reg_offset = 0,
1c2928e3e   Matti Vaittinen   regmap: regmap-ir...
81
82
83
84
85
86
87
88
  		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE5,
  		.type = {
  			.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
  			.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
  			.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
  			.type_reg_offset = 5,
  			.types_supported = IRQ_TYPE_EDGE_BOTH,
  		},
ff93ec749   Laxman Dewangan   gpio: max77620: C...
89
90
  	},
  	[6] = {
ff93ec749   Laxman Dewangan   gpio: max77620: C...
91
  		.reg_offset = 0,
1c2928e3e   Matti Vaittinen   regmap: regmap-ir...
92
93
94
95
96
97
98
99
  		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE6,
  		.type = {
  			.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
  			.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
  			.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
  			.type_reg_offset = 6,
  			.types_supported = IRQ_TYPE_EDGE_BOTH,
  		},
ff93ec749   Laxman Dewangan   gpio: max77620: C...
100
101
  	},
  	[7] = {
ff93ec749   Laxman Dewangan   gpio: max77620: C...
102
  		.reg_offset = 0,
1c2928e3e   Matti Vaittinen   regmap: regmap-ir...
103
104
105
106
107
108
109
110
  		.mask = MAX77620_IRQ_LVL2_GPIO_EDGE7,
  		.type = {
  			.type_rising_val = MAX77620_CNFG_GPIO_INT_RISING,
  			.type_falling_val = MAX77620_CNFG_GPIO_INT_FALLING,
  			.type_reg_mask = MAX77620_CNFG_GPIO_INT_MASK,
  			.type_reg_offset = 7,
  			.types_supported = IRQ_TYPE_EDGE_BOTH,
  		},
ff93ec749   Laxman Dewangan   gpio: max77620: C...
111
  	},
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
112
  };
ee949b51e   Bhumika Goyal   gpio: max77620: M...
113
  static const struct regmap_irq_chip max77620_gpio_irq_chip = {
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
114
115
116
117
  	.name = "max77620-gpio",
  	.irqs = max77620_gpio_irqs,
  	.num_irqs = ARRAY_SIZE(max77620_gpio_irqs),
  	.num_regs = 1,
ff93ec749   Laxman Dewangan   gpio: max77620: C...
118
  	.num_type_reg = 8,
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
119
  	.irq_reg_stride = 1,
ff93ec749   Laxman Dewangan   gpio: max77620: C...
120
  	.type_reg_stride = 1,
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
121
  	.status_base = MAX77620_REG_IRQ_LVL2_GPIO,
ff93ec749   Laxman Dewangan   gpio: max77620: C...
122
  	.type_base = MAX77620_REG_GPIO0,
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  };
  
  static int max77620_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
  {
  	struct max77620_gpio *mgpio = gpiochip_get_data(gc);
  	int ret;
  
  	ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
  				 MAX77620_CNFG_GPIO_DIR_MASK,
  				 MAX77620_CNFG_GPIO_DIR_INPUT);
  	if (ret < 0)
  		dev_err(mgpio->dev, "CNFG_GPIOx dir update failed: %d
  ", ret);
  
  	return ret;
  }
  
  static int max77620_gpio_get(struct gpio_chip *gc, unsigned int offset)
  {
  	struct max77620_gpio *mgpio = gpiochip_get_data(gc);
  	unsigned int val;
  	int ret;
  
  	ret = regmap_read(mgpio->rmap, GPIO_REG_ADDR(offset), &val);
  	if (ret < 0) {
  		dev_err(mgpio->dev, "CNFG_GPIOx read failed: %d
  ", ret);
  		return ret;
  	}
1941b4419   Venkat Reddy Talla   gpio: max77620: g...
152
153
154
155
  	if  (val & MAX77620_CNFG_GPIO_DIR_MASK)
  		return !!(val & MAX77620_CNFG_GPIO_INPUT_VAL_MASK);
  	else
  		return !!(val & MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK);
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
  }
  
  static int max77620_gpio_dir_output(struct gpio_chip *gc, unsigned int offset,
  				    int value)
  {
  	struct max77620_gpio *mgpio = gpiochip_get_data(gc);
  	u8 val;
  	int ret;
  
  	val = (value) ? MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH :
  				MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW;
  
  	ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
  				 MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK, val);
  	if (ret < 0) {
  		dev_err(mgpio->dev, "CNFG_GPIOx val update failed: %d
  ", ret);
  		return ret;
  	}
  
  	ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
  				 MAX77620_CNFG_GPIO_DIR_MASK,
  				 MAX77620_CNFG_GPIO_DIR_OUTPUT);
  	if (ret < 0)
  		dev_err(mgpio->dev, "CNFG_GPIOx dir update failed: %d
  ", ret);
  
  	return ret;
  }
2956b5d94   Mika Westerberg   pinctrl / gpio: I...
185
  static int max77620_gpio_set_debounce(struct max77620_gpio *mgpio,
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
186
187
188
  				      unsigned int offset,
  				      unsigned int debounce)
  {
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
189
190
191
192
193
194
195
  	u8 val;
  	int ret;
  
  	switch (debounce) {
  	case 0:
  		val = MAX77620_CNFG_GPIO_DBNC_None;
  		break;
b0391479a   Thierry Reding   gpio: max77620: F...
196
  	case 1 ... 8000:
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
197
198
  		val = MAX77620_CNFG_GPIO_DBNC_8ms;
  		break;
b0391479a   Thierry Reding   gpio: max77620: F...
199
  	case 8001 ... 16000:
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
200
201
  		val = MAX77620_CNFG_GPIO_DBNC_16ms;
  		break;
b0391479a   Thierry Reding   gpio: max77620: F...
202
  	case 16001 ... 32000:
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  		val = MAX77620_CNFG_GPIO_DBNC_32ms;
  		break;
  	default:
  		dev_err(mgpio->dev, "Illegal value %u
  ", debounce);
  		return -EINVAL;
  	}
  
  	ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
  				 MAX77620_CNFG_GPIO_DBNC_MASK, val);
  	if (ret < 0)
  		dev_err(mgpio->dev, "CNFG_GPIOx_DBNC update failed: %d
  ", ret);
  
  	return ret;
  }
  
  static void max77620_gpio_set(struct gpio_chip *gc, unsigned int offset,
  			      int value)
  {
  	struct max77620_gpio *mgpio = gpiochip_get_data(gc);
  	u8 val;
  	int ret;
  
  	val = (value) ? MAX77620_CNFG_GPIO_OUTPUT_VAL_HIGH :
  				MAX77620_CNFG_GPIO_OUTPUT_VAL_LOW;
  
  	ret = regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
  				 MAX77620_CNFG_GPIO_OUTPUT_VAL_MASK, val);
  	if (ret < 0)
  		dev_err(mgpio->dev, "CNFG_GPIO_OUT update failed: %d
  ", ret);
  }
2956b5d94   Mika Westerberg   pinctrl / gpio: I...
236
237
  static int max77620_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
  				    unsigned long config)
23087a050   Laxman Dewangan   gpio: max77620: u...
238
239
  {
  	struct max77620_gpio *mgpio = gpiochip_get_data(gc);
2956b5d94   Mika Westerberg   pinctrl / gpio: I...
240
241
  	switch (pinconf_to_config_param(config)) {
  	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
23087a050   Laxman Dewangan   gpio: max77620: u...
242
243
244
  		return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
  					  MAX77620_CNFG_GPIO_DRV_MASK,
  					  MAX77620_CNFG_GPIO_DRV_OPENDRAIN);
2956b5d94   Mika Westerberg   pinctrl / gpio: I...
245
  	case PIN_CONFIG_DRIVE_PUSH_PULL:
23087a050   Laxman Dewangan   gpio: max77620: u...
246
247
248
  		return regmap_update_bits(mgpio->rmap, GPIO_REG_ADDR(offset),
  					  MAX77620_CNFG_GPIO_DRV_MASK,
  					  MAX77620_CNFG_GPIO_DRV_PUSHPULL);
2956b5d94   Mika Westerberg   pinctrl / gpio: I...
249
250
251
  	case PIN_CONFIG_INPUT_DEBOUNCE:
  		return max77620_gpio_set_debounce(mgpio, offset,
  			pinconf_to_config_argument(config));
23087a050   Laxman Dewangan   gpio: max77620: u...
252
253
254
255
256
257
  	default:
  		break;
  	}
  
  	return -ENOTSUPP;
  }
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  static int max77620_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
  {
  	struct max77620_gpio *mgpio = gpiochip_get_data(gc);
  	struct max77620_chip *chip = dev_get_drvdata(mgpio->dev->parent);
  
  	return regmap_irq_get_virq(chip->gpio_irq_data, offset);
  }
  
  static int max77620_gpio_probe(struct platform_device *pdev)
  {
  	struct max77620_chip *chip =  dev_get_drvdata(pdev->dev.parent);
  	struct max77620_gpio *mgpio;
  	int gpio_irq;
  	int ret;
  
  	gpio_irq = platform_get_irq(pdev, 0);
15bddb7d7   Stephen Boyd   gpio: Remove dev_...
274
  	if (gpio_irq <= 0)
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
275
  		return -ENODEV;
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
276
277
278
279
280
281
282
  
  	mgpio = devm_kzalloc(&pdev->dev, sizeof(*mgpio), GFP_KERNEL);
  	if (!mgpio)
  		return -ENOMEM;
  
  	mgpio->rmap = chip->rmap;
  	mgpio->dev = &pdev->dev;
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
283
284
285
286
287
288
  
  	mgpio->gpio_chip.label = pdev->name;
  	mgpio->gpio_chip.parent = &pdev->dev;
  	mgpio->gpio_chip.direction_input = max77620_gpio_dir_input;
  	mgpio->gpio_chip.get = max77620_gpio_get;
  	mgpio->gpio_chip.direction_output = max77620_gpio_dir_output;
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
289
  	mgpio->gpio_chip.set = max77620_gpio_set;
2956b5d94   Mika Westerberg   pinctrl / gpio: I...
290
  	mgpio->gpio_chip.set_config = max77620_gpio_set_config;
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
291
292
293
294
  	mgpio->gpio_chip.to_irq = max77620_gpio_to_irq;
  	mgpio->gpio_chip.ngpio = MAX77620_GPIO_NR;
  	mgpio->gpio_chip.can_sleep = 1;
  	mgpio->gpio_chip.base = -1;
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
295
296
297
298
299
300
301
302
303
304
305
306
  #ifdef CONFIG_OF_GPIO
  	mgpio->gpio_chip.of_node = pdev->dev.parent->of_node;
  #endif
  
  	platform_set_drvdata(pdev, mgpio);
  
  	ret = devm_gpiochip_add_data(&pdev->dev, &mgpio->gpio_chip, mgpio);
  	if (ret < 0) {
  		dev_err(&pdev->dev, "gpio_init: Failed to add max77620_gpio
  ");
  		return ret;
  	}
fdf4332fd   Axel Lin   gpio: max77620: R...
307
308
  	ret = devm_regmap_add_irq_chip(&pdev->dev, chip->rmap, gpio_irq,
  				       IRQF_ONESHOT, -1,
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
309
310
311
312
313
314
315
316
317
318
319
320
321
  				       &max77620_gpio_irq_chip,
  				       &chip->gpio_irq_data);
  	if (ret < 0) {
  		dev_err(&pdev->dev, "Failed to add gpio irq_chip %d
  ", ret);
  		return ret;
  	}
  
  	return 0;
  }
  
  static const struct platform_device_id max77620_gpio_devtype[] = {
  	{ .name = "max77620-gpio", },
3107d5723   Venkat Reddy Talla   gpio: max77620: a...
322
  	{ .name = "max20024-gpio", },
02c5ba1ee   Laxman Dewangan   gpio: max77620: a...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
  	{},
  };
  MODULE_DEVICE_TABLE(platform, max77620_gpio_devtype);
  
  static struct platform_driver max77620_gpio_driver = {
  	.driver.name	= "max77620-gpio",
  	.probe		= max77620_gpio_probe,
  	.id_table	= max77620_gpio_devtype,
  };
  
  module_platform_driver(max77620_gpio_driver);
  
  MODULE_DESCRIPTION("GPIO interface for MAX77620 and MAX20024 PMIC");
  MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
  MODULE_AUTHOR("Chaitanya Bandi <bandik@nvidia.com>");
  MODULE_ALIAS("platform:max77620-gpio");
  MODULE_LICENSE("GPL v2");