Blame view

drivers/pinctrl/pinctrl-digicolor.c 8.38 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
38b0e5071   Baruch Siach   pinctrl: driver f...
2
3
4
5
6
7
8
  /*
   *  Driver for Conexant Digicolor General Purpose Pin Mapping
   *
   * Author: Baruch Siach <baruch@tkos.co.il>
   *
   * Copyright (C) 2015 Paradox Innovation Ltd.
   *
38b0e5071   Baruch Siach   pinctrl: driver f...
9
10
11
12
   * TODO:
   * - GPIO interrupt support
   * - Pin pad configuration (pull up/down, strength)
   */
546c6d793   Paul Gortmaker   pinctrl: digicolo...
13
  #include <linux/init.h>
38b0e5071   Baruch Siach   pinctrl: driver f...
14
15
16
17
  #include <linux/platform_device.h>
  #include <linux/of.h>
  #include <linux/of_device.h>
  #include <linux/io.h>
38b0e5071   Baruch Siach   pinctrl: driver f...
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  #include <linux/gpio/driver.h>
  #include <linux/spinlock.h>
  #include <linux/pinctrl/machine.h>
  #include <linux/pinctrl/pinconf.h>
  #include <linux/pinctrl/pinconf-generic.h>
  #include <linux/pinctrl/pinctrl.h>
  #include <linux/pinctrl/pinmux.h>
  #include "pinctrl-utils.h"
  
  #define DRIVER_NAME	"pinctrl-digicolor"
  
  #define GP_CLIENTSEL(clct)	((clct)*8 + 0x20)
  #define GP_DRIVE0(clct)		(GP_CLIENTSEL(clct) + 2)
  #define GP_OUTPUT0(clct)	(GP_CLIENTSEL(clct) + 3)
  #define GP_INPUT(clct)		(GP_CLIENTSEL(clct) + 6)
  
  #define PIN_COLLECTIONS		('R' - 'A' + 1)
  #define PINS_PER_COLLECTION	8
  #define PINS_COUNT		(PIN_COLLECTIONS * PINS_PER_COLLECTION)
  
  struct dc_pinmap {
  	void __iomem		*regs;
  	struct device		*dev;
  	struct pinctrl_dev	*pctl;
  
  	struct pinctrl_desc	*desc;
  	const char		*pin_names[PINS_COUNT];
  
  	struct gpio_chip	chip;
  	spinlock_t		lock;
  };
  
  static int dc_get_groups_count(struct pinctrl_dev *pctldev)
  {
  	return PINS_COUNT;
  }
  
  static const char *dc_get_group_name(struct pinctrl_dev *pctldev,
  				     unsigned selector)
  {
  	struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev);
  
  	/* Exactly one group per pin */
  	return pmap->desc->pins[selector].name;
  }
  
  static int dc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
  			     const unsigned **pins,
  			     unsigned *num_pins)
  {
  	struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev);
  
  	*pins = &pmap->desc->pins[selector].number;
  	*num_pins = 1;
  
  	return 0;
  }
db74f96d6   Julia Lawall   pinctrl: digicolo...
75
  static const struct pinctrl_ops dc_pinctrl_ops = {
38b0e5071   Baruch Siach   pinctrl: driver f...
76
77
78
79
  	.get_groups_count	= dc_get_groups_count,
  	.get_group_name		= dc_get_group_name,
  	.get_group_pins		= dc_get_group_pins,
  	.dt_node_to_map		= pinconf_generic_dt_node_to_map_pin,
d32f7fd3b   Irina Tirdea   pinctrl: Rename p...
80
  	.dt_free_map		= pinctrl_utils_free_map,
38b0e5071   Baruch Siach   pinctrl: driver f...
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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
152
153
154
155
  };
  
  static const char *const dc_functions[] = {
  	"gpio",
  	"client_a",
  	"client_b",
  	"client_c",
  };
  
  static int dc_get_functions_count(struct pinctrl_dev *pctldev)
  {
  	return ARRAY_SIZE(dc_functions);
  }
  
  static const char *dc_get_fname(struct pinctrl_dev *pctldev, unsigned selector)
  {
  	return dc_functions[selector];
  }
  
  static int dc_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
  			 const char * const **groups,
  			 unsigned * const num_groups)
  {
  	struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev);
  
  	*groups = pmap->pin_names;
  	*num_groups = PINS_COUNT;
  
  	return 0;
  }
  
  static void dc_client_sel(int pin_num, int *reg, int *bit)
  {
  	*bit = (pin_num % PINS_PER_COLLECTION) * 2;
  	*reg = GP_CLIENTSEL(pin_num/PINS_PER_COLLECTION);
  
  	if (*bit >= PINS_PER_COLLECTION) {
  		*bit -= PINS_PER_COLLECTION;
  		*reg += 1;
  	}
  }
  
  static int dc_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
  		      unsigned group)
  {
  	struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev);
  	int bit_off, reg_off;
  	u8 reg;
  
  	dc_client_sel(group, &reg_off, &bit_off);
  
  	reg = readb_relaxed(pmap->regs + reg_off);
  	reg &= ~(3 << bit_off);
  	reg |= (selector << bit_off);
  	writeb_relaxed(reg, pmap->regs + reg_off);
  
  	return 0;
  }
  
  static int dc_pmx_request_gpio(struct pinctrl_dev *pcdev,
  			       struct pinctrl_gpio_range *range,
  			       unsigned offset)
  {
  	struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pcdev);
  	int bit_off, reg_off;
  	u8 reg;
  
  	dc_client_sel(offset, &reg_off, &bit_off);
  
  	reg = readb_relaxed(pmap->regs + reg_off);
  	if ((reg & (3 << bit_off)) != 0)
  		return -EBUSY;
  
  	return 0;
  }
db74f96d6   Julia Lawall   pinctrl: digicolo...
156
  static const struct pinmux_ops dc_pmxops = {
38b0e5071   Baruch Siach   pinctrl: driver f...
157
158
159
160
161
162
  	.get_functions_count	= dc_get_functions_count,
  	.get_function_name	= dc_get_fname,
  	.get_function_groups	= dc_get_groups,
  	.set_mux		= dc_set_mux,
  	.gpio_request_enable	= dc_pmx_request_gpio,
  };
38b0e5071   Baruch Siach   pinctrl: driver f...
163
164
  static int dc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
  {
573718337   Linus Walleij   pinctrl: digicolo...
165
  	struct dc_pinmap *pmap = gpiochip_get_data(chip);
38b0e5071   Baruch Siach   pinctrl: driver f...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
  	int reg_off = GP_DRIVE0(gpio/PINS_PER_COLLECTION);
  	int bit_off = gpio % PINS_PER_COLLECTION;
  	u8 drive;
  	unsigned long flags;
  
  	spin_lock_irqsave(&pmap->lock, flags);
  	drive = readb_relaxed(pmap->regs + reg_off);
  	drive &= ~BIT(bit_off);
  	writeb_relaxed(drive, pmap->regs + reg_off);
  	spin_unlock_irqrestore(&pmap->lock, flags);
  
  	return 0;
  }
  
  static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value);
  
  static int dc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
  				    int value)
  {
573718337   Linus Walleij   pinctrl: digicolo...
185
  	struct dc_pinmap *pmap = gpiochip_get_data(chip);
38b0e5071   Baruch Siach   pinctrl: driver f...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
  	int reg_off = GP_DRIVE0(gpio/PINS_PER_COLLECTION);
  	int bit_off = gpio % PINS_PER_COLLECTION;
  	u8 drive;
  	unsigned long flags;
  
  	dc_gpio_set(chip, gpio, value);
  
  	spin_lock_irqsave(&pmap->lock, flags);
  	drive = readb_relaxed(pmap->regs + reg_off);
  	drive |= BIT(bit_off);
  	writeb_relaxed(drive, pmap->regs + reg_off);
  	spin_unlock_irqrestore(&pmap->lock, flags);
  
  	return 0;
  }
  
  static int dc_gpio_get(struct gpio_chip *chip, unsigned gpio)
  {
573718337   Linus Walleij   pinctrl: digicolo...
204
  	struct dc_pinmap *pmap = gpiochip_get_data(chip);
38b0e5071   Baruch Siach   pinctrl: driver f...
205
206
207
208
209
210
211
212
213
214
215
  	int reg_off = GP_INPUT(gpio/PINS_PER_COLLECTION);
  	int bit_off = gpio % PINS_PER_COLLECTION;
  	u8 input;
  
  	input = readb_relaxed(pmap->regs + reg_off);
  
  	return !!(input & BIT(bit_off));
  }
  
  static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
  {
573718337   Linus Walleij   pinctrl: digicolo...
216
  	struct dc_pinmap *pmap = gpiochip_get_data(chip);
38b0e5071   Baruch Siach   pinctrl: driver f...
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  	int reg_off = GP_OUTPUT0(gpio/PINS_PER_COLLECTION);
  	int bit_off = gpio % PINS_PER_COLLECTION;
  	u8 output;
  	unsigned long flags;
  
  	spin_lock_irqsave(&pmap->lock, flags);
  	output = readb_relaxed(pmap->regs + reg_off);
  	if (value)
  		output |= BIT(bit_off);
  	else
  		output &= ~BIT(bit_off);
  	writeb_relaxed(output, pmap->regs + reg_off);
  	spin_unlock_irqrestore(&pmap->lock, flags);
  }
  
  static int dc_gpiochip_add(struct dc_pinmap *pmap, struct device_node *np)
  {
  	struct gpio_chip *chip = &pmap->chip;
  	int ret;
  
  	chip->label		= DRIVER_NAME;
58383c784   Linus Walleij   gpio: change memb...
238
  	chip->parent		= pmap->dev;
98c85d583   Jonas Gorski   pinctrl: replace ...
239
240
  	chip->request		= gpiochip_generic_request;
  	chip->free		= gpiochip_generic_free;
38b0e5071   Baruch Siach   pinctrl: driver f...
241
242
243
244
245
246
247
248
249
250
  	chip->direction_input	= dc_gpio_direction_input;
  	chip->direction_output	= dc_gpio_direction_output;
  	chip->get		= dc_gpio_get;
  	chip->set		= dc_gpio_set;
  	chip->base		= -1;
  	chip->ngpio		= PINS_COUNT;
  	chip->of_node		= np;
  	chip->of_gpio_n_cells	= 2;
  
  	spin_lock_init(&pmap->lock);
573718337   Linus Walleij   pinctrl: digicolo...
251
  	ret = gpiochip_add_data(chip, pmap);
38b0e5071   Baruch Siach   pinctrl: driver f...
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  	if (ret < 0)
  		return ret;
  
  	ret = gpiochip_add_pin_range(chip, dev_name(pmap->dev), 0, 0,
  				     PINS_COUNT);
  	if (ret < 0) {
  		gpiochip_remove(chip);
  		return ret;
  	}
  
  	return 0;
  }
  
  static int dc_pinctrl_probe(struct platform_device *pdev)
  {
  	struct dc_pinmap *pmap;
38b0e5071   Baruch Siach   pinctrl: driver f...
268
269
270
271
  	struct pinctrl_pin_desc *pins;
  	struct pinctrl_desc *pctl_desc;
  	char *pin_names;
  	int name_len = strlen("GP_xx") + 1;
8f91ed478   Laxman Dewangan   pinctrl: digicolo...
272
  	int i, j;
38b0e5071   Baruch Siach   pinctrl: driver f...
273
274
275
276
  
  	pmap = devm_kzalloc(&pdev->dev, sizeof(*pmap), GFP_KERNEL);
  	if (!pmap)
  		return -ENOMEM;
4b024225c   YueHaibing   pinctrl: use devm...
277
  	pmap->regs = devm_platform_ioremap_resource(pdev, 0);
38b0e5071   Baruch Siach   pinctrl: driver f...
278
279
  	if (IS_ERR(pmap->regs))
  		return PTR_ERR(pmap->regs);
a86854d0c   Kees Cook   treewide: devm_kz...
280
281
  	pins = devm_kcalloc(&pdev->dev, PINS_COUNT, sizeof(*pins),
  			    GFP_KERNEL);
38b0e5071   Baruch Siach   pinctrl: driver f...
282
283
  	if (!pins)
  		return -ENOMEM;
a86854d0c   Kees Cook   treewide: devm_kz...
284
  	pin_names = devm_kcalloc(&pdev->dev, PINS_COUNT, name_len,
38b0e5071   Baruch Siach   pinctrl: driver f...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
  				 GFP_KERNEL);
  	if (!pin_names)
  		return -ENOMEM;
  
  	for (i = 0; i < PIN_COLLECTIONS; i++) {
  		for (j = 0; j < PINS_PER_COLLECTION; j++) {
  			int pin_id = i*PINS_PER_COLLECTION + j;
  			char *name = &pin_names[pin_id * name_len];
  
  			snprintf(name, name_len, "GP_%c%c", 'A'+i, '0'+j);
  
  			pins[pin_id].number = pin_id;
  			pins[pin_id].name = name;
  			pmap->pin_names[pin_id] = name;
  		}
  	}
  
  	pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL);
  	if (!pctl_desc)
  		return -ENOMEM;
  
  	pctl_desc->name	= DRIVER_NAME,
  	pctl_desc->owner = THIS_MODULE,
  	pctl_desc->pctlops = &dc_pinctrl_ops,
  	pctl_desc->pmxops = &dc_pmxops,
  	pctl_desc->npins = PINS_COUNT;
  	pctl_desc->pins = pins;
  	pmap->desc = pctl_desc;
  
  	pmap->dev = &pdev->dev;
8f91ed478   Laxman Dewangan   pinctrl: digicolo...
315
  	pmap->pctl = devm_pinctrl_register(&pdev->dev, pctl_desc, pmap);
5a99233e9   Julia Lawall   pinctrl: digicolo...
316
  	if (IS_ERR(pmap->pctl)) {
38b0e5071   Baruch Siach   pinctrl: driver f...
317
318
  		dev_err(&pdev->dev, "pinctrl driver registration failed
  ");
5a99233e9   Julia Lawall   pinctrl: digicolo...
319
  		return PTR_ERR(pmap->pctl);
38b0e5071   Baruch Siach   pinctrl: driver f...
320
  	}
8f91ed478   Laxman Dewangan   pinctrl: digicolo...
321
  	return dc_gpiochip_add(pmap, pdev->dev.of_node);
38b0e5071   Baruch Siach   pinctrl: driver f...
322
  }
38b0e5071   Baruch Siach   pinctrl: driver f...
323
324
325
326
  static const struct of_device_id dc_pinctrl_ids[] = {
  	{ .compatible = "cnxt,cx92755-pinctrl" },
  	{ /* sentinel */ }
  };
38b0e5071   Baruch Siach   pinctrl: driver f...
327
328
329
330
331
  
  static struct platform_driver dc_pinctrl_driver = {
  	.driver = {
  		.name = DRIVER_NAME,
  		.of_match_table = dc_pinctrl_ids,
546c6d793   Paul Gortmaker   pinctrl: digicolo...
332
  		.suppress_bind_attrs = true,
38b0e5071   Baruch Siach   pinctrl: driver f...
333
334
  	},
  	.probe = dc_pinctrl_probe,
38b0e5071   Baruch Siach   pinctrl: driver f...
335
  };
546c6d793   Paul Gortmaker   pinctrl: digicolo...
336
  builtin_platform_driver(dc_pinctrl_driver);