Blame view

drivers/gpio/gpio-mvebu.c 32.9 KB
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  /*
   * GPIO driver for Marvell SoCs
   *
   * Copyright (C) 2012 Marvell
   *
   * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
   * Andrew Lunn <andrew@lunn.ch>
   * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
   *
   * This file is licensed under the terms of the GNU General Public
   * License version 2.  This program is licensed "as is" without any
   * warranty of any kind, whether express or implied.
   *
   * This driver is a fairly straightforward GPIO driver for the
   * complete family of Marvell EBU SoC platforms (Orion, Dove,
   * Kirkwood, Discovery, Armada 370/XP). The only complexity of this
   * driver is the different register layout that exists between the
   * non-SMP platforms (Orion, Dove, Kirkwood, Armada 370) and the SMP
   * platforms (MV78200 from the Discovery family and the Armada
   * XP). Therefore, this driver handles three variants of the GPIO
   * block:
   * - the basic variant, called "orion-gpio", with the simplest
   *   register set. Used on Orion, Dove, Kirkwoord, Armada 370 and
   *   non-SMP Discovery systems
   * - the mv78200 variant for MV78200 Discovery systems. This variant
   *   turns the edge mask and level mask registers into CPU0 edge
   *   mask/level mask registers, and adds CPU1 edge mask/level mask
   *   registers.
   * - the armadaxp variant for Armada XP systems. This variant keeps
   *   the normal cause/edge mask/level mask registers when the global
   *   interrupts are used, but adds per-CPU cause/edge mask/level mask
   *   registers n a separate memory area for the per-CPU GPIO
   *   interrupts.
   */
6ec015d61   Gregory CLEMENT   gpio: mvebu: sort...
35
36
  #include <linux/bitops.h>
  #include <linux/clk.h>
641d03422   Thierry Reding   gpio: Convert to ...
37
  #include <linux/err.h>
fefe7b092   Thomas Petazzoni   gpio: introduce g...
38
  #include <linux/gpio.h>
6ec015d61   Gregory CLEMENT   gpio: mvebu: sort...
39
40
  #include <linux/init.h>
  #include <linux/io.h>
fefe7b092   Thomas Petazzoni   gpio: introduce g...
41
  #include <linux/irq.h>
6ec015d61   Gregory CLEMENT   gpio: mvebu: sort...
42
  #include <linux/irqchip/chained_irq.h>
fefe7b092   Thomas Petazzoni   gpio: introduce g...
43
  #include <linux/irqdomain.h>
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
44
  #include <linux/mfd/syscon.h>
fefe7b092   Thomas Petazzoni   gpio: introduce g...
45
  #include <linux/of_device.h>
6ec015d61   Gregory CLEMENT   gpio: mvebu: sort...
46
  #include <linux/of_irq.h>
fefe7b092   Thomas Petazzoni   gpio: introduce g...
47
  #include <linux/pinctrl/consumer.h>
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
48
  #include <linux/platform_device.h>
6ec015d61   Gregory CLEMENT   gpio: mvebu: sort...
49
  #include <linux/pwm.h>
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
50
  #include <linux/regmap.h>
6ec015d61   Gregory CLEMENT   gpio: mvebu: sort...
51
  #include <linux/slab.h>
fefe7b092   Thomas Petazzoni   gpio: introduce g...
52

757642f9a   Andrew Lunn   gpio: mvebu: Add ...
53
  #include "gpiolib.h"
fefe7b092   Thomas Petazzoni   gpio: introduce g...
54
55
56
  /*
   * GPIO unit register offsets.
   */
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  #define GPIO_OUT_OFF			0x0000
  #define GPIO_IO_CONF_OFF		0x0004
  #define GPIO_BLINK_EN_OFF		0x0008
  #define GPIO_IN_POL_OFF			0x000c
  #define GPIO_DATA_IN_OFF		0x0010
  #define GPIO_EDGE_CAUSE_OFF		0x0014
  #define GPIO_EDGE_MASK_OFF		0x0018
  #define GPIO_LEVEL_MASK_OFF		0x001c
  #define GPIO_BLINK_CNT_SELECT_OFF	0x0020
  
  /*
   * PWM register offsets.
   */
  #define PWM_BLINK_ON_DURATION_OFF	0x0
  #define PWM_BLINK_OFF_DURATION_OFF	0x4
fefe7b092   Thomas Petazzoni   gpio: introduce g...
72
73
  
  /* The MV78200 has per-CPU registers for edge mask and level mask */
a4319a611   Andrew Lunn   gpio: mvebu: chec...
74
  #define GPIO_EDGE_MASK_MV78200_OFF(cpu)	  ((cpu) ? 0x30 : 0x18)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
75
  #define GPIO_LEVEL_MASK_MV78200_OFF(cpu)  ((cpu) ? 0x34 : 0x1C)
7077f4cc1   Ralph Sennhauser   gpio: mvebu: chec...
76
77
  /*
   * The Armada XP has per-CPU registers for interrupt cause, interrupt
fefe7b092   Thomas Petazzoni   gpio: introduce g...
78
   * mask and interrupt level mask. Those are relative to the
7077f4cc1   Ralph Sennhauser   gpio: mvebu: chec...
79
80
   * percpu_membase.
   */
fefe7b092   Thomas Petazzoni   gpio: introduce g...
81
82
83
  #define GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu) ((cpu) * 0x4)
  #define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu)  (0x10 + (cpu) * 0x4)
  #define GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu) (0x20 + (cpu) * 0x4)
a4319a611   Andrew Lunn   gpio: mvebu: chec...
84
85
  #define MVEBU_GPIO_SOC_VARIANT_ORION	0x1
  #define MVEBU_GPIO_SOC_VARIANT_MV78200	0x2
fefe7b092   Thomas Petazzoni   gpio: introduce g...
86
  #define MVEBU_GPIO_SOC_VARIANT_ARMADAXP 0x3
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
87
  #define MVEBU_GPIO_SOC_VARIANT_A8K	0x4
fefe7b092   Thomas Petazzoni   gpio: introduce g...
88

a4319a611   Andrew Lunn   gpio: mvebu: chec...
89
  #define MVEBU_MAX_GPIO_PER_BANK		32
fefe7b092   Thomas Petazzoni   gpio: introduce g...
90

757642f9a   Andrew Lunn   gpio: mvebu: Add ...
91
92
93
94
95
96
97
98
99
100
101
102
103
  struct mvebu_pwm {
  	void __iomem		*membase;
  	unsigned long		 clk_rate;
  	struct gpio_desc	*gpiod;
  	struct pwm_chip		 chip;
  	spinlock_t		 lock;
  	struct mvebu_gpio_chip	*mvchip;
  
  	/* Used to preserve GPIO/PWM registers across suspend/resume */
  	u32			 blink_select;
  	u32			 blink_on_duration;
  	u32			 blink_off_duration;
  };
fefe7b092   Thomas Petazzoni   gpio: introduce g...
104
105
  struct mvebu_gpio_chip {
  	struct gpio_chip   chip;
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
106
  	struct regmap     *regs;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
107
  	u32		   offset;
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
108
  	struct regmap     *percpu_regs;
d53592269   Dan Carpenter   gpio: mvebu: make...
109
  	int		   irqbase;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
110
  	struct irq_domain *domain;
a4319a611   Andrew Lunn   gpio: mvebu: chec...
111
  	int		   soc_variant;
b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
112

757642f9a   Andrew Lunn   gpio: mvebu: Add ...
113
114
115
  	/* Used for PWM support */
  	struct clk	  *clk;
  	struct mvebu_pwm  *mvpwm;
a4319a611   Andrew Lunn   gpio: mvebu: chec...
116
  	/* Used to preserve GPIO registers across suspend/resume */
f4c240ca4   Ralph Sennhauser   gpio: mvebu: extr...
117
118
119
120
121
122
  	u32		   out_reg;
  	u32		   io_conf_reg;
  	u32		   blink_en_reg;
  	u32		   in_pol_reg;
  	u32		   edge_mask_regs[4];
  	u32		   level_mask_regs[4];
fefe7b092   Thomas Petazzoni   gpio: introduce g...
123
124
125
126
127
128
  };
  
  /*
   * Functions returning addresses of individual registers for a given
   * GPIO controller.
   */
fefe7b092   Thomas Petazzoni   gpio: introduce g...
129

2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
130
131
  static void mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip,
  			 struct regmap **map, unsigned int *offset)
e91337609   Jamie Lentin   mvebu-gpio: Disab...
132
  {
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
133
  	int cpu;
e91337609   Jamie Lentin   mvebu-gpio: Disab...
134

2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
135
136
137
  	switch (mvchip->soc_variant) {
  	case MVEBU_GPIO_SOC_VARIANT_ORION:
  	case MVEBU_GPIO_SOC_VARIANT_MV78200:
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
138
  	case MVEBU_GPIO_SOC_VARIANT_A8K:
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
139
  		*map = mvchip->regs;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
140
  		*offset = GPIO_EDGE_CAUSE_OFF + mvchip->offset;
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
141
142
143
144
145
146
147
148
149
  		break;
  	case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
  		cpu = smp_processor_id();
  		*map = mvchip->percpu_regs;
  		*offset = GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu);
  		break;
  	default:
  		BUG();
  	}
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
150
  }
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
151
152
  static u32
  mvebu_gpio_read_edge_cause(struct mvebu_gpio_chip *mvchip)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
153
  {
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
154
155
156
  	struct regmap *map;
  	unsigned int offset;
  	u32 val;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
157

2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
158
159
160
161
  	mvebu_gpioreg_edge_cause(mvchip, &map, &offset);
  	regmap_read(map, offset, &val);
  
  	return val;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
162
  }
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
163
164
  static void
  mvebu_gpio_write_edge_cause(struct mvebu_gpio_chip *mvchip, u32 val)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
165
  {
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
166
167
168
169
170
  	struct regmap *map;
  	unsigned int offset;
  
  	mvebu_gpioreg_edge_cause(mvchip, &map, &offset);
  	regmap_write(map, offset, val);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
171
  }
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
172
173
174
  static inline void
  mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip,
  			struct regmap **map, unsigned int *offset)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
175
176
  {
  	int cpu;
f4dcd2d94   Laurent Navet   gpio: gpio-mvebu....
177
  	switch (mvchip->soc_variant) {
fefe7b092   Thomas Petazzoni   gpio: introduce g...
178
  	case MVEBU_GPIO_SOC_VARIANT_ORION:
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
179
  	case MVEBU_GPIO_SOC_VARIANT_A8K:
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
180
  		*map = mvchip->regs;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
181
  		*offset = GPIO_EDGE_MASK_OFF + mvchip->offset;
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
182
  		break;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
183
  	case MVEBU_GPIO_SOC_VARIANT_MV78200:
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
184
185
186
187
  		cpu = smp_processor_id();
  		*map = mvchip->regs;
  		*offset = GPIO_EDGE_MASK_MV78200_OFF(cpu);
  		break;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
188
189
  	case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
  		cpu = smp_processor_id();
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
190
191
192
  		*map = mvchip->percpu_regs;
  		*offset = GPIO_EDGE_MASK_ARMADAXP_OFF(cpu);
  		break;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
193
194
195
196
  	default:
  		BUG();
  	}
  }
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
197
198
  static u32
  mvebu_gpio_read_edge_mask(struct mvebu_gpio_chip *mvchip)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
199
  {
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
200
201
202
  	struct regmap *map;
  	unsigned int offset;
  	u32 val;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
203

2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
204
205
206
207
  	mvebu_gpioreg_edge_mask(mvchip, &map, &offset);
  	regmap_read(map, offset, &val);
  
  	return val;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
208
  }
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
209
210
211
212
213
214
215
216
217
218
219
220
221
  static void
  mvebu_gpio_write_edge_mask(struct mvebu_gpio_chip *mvchip, u32 val)
  {
  	struct regmap *map;
  	unsigned int offset;
  
  	mvebu_gpioreg_edge_mask(mvchip, &map, &offset);
  	regmap_write(map, offset, val);
  }
  
  static void
  mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip,
  			 struct regmap **map, unsigned int *offset)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
222
223
  {
  	int cpu;
f4dcd2d94   Laurent Navet   gpio: gpio-mvebu....
224
  	switch (mvchip->soc_variant) {
fefe7b092   Thomas Petazzoni   gpio: introduce g...
225
  	case MVEBU_GPIO_SOC_VARIANT_ORION:
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
226
  	case MVEBU_GPIO_SOC_VARIANT_A8K:
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
227
  		*map = mvchip->regs;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
228
  		*offset = GPIO_LEVEL_MASK_OFF + mvchip->offset;
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
229
  		break;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
230
231
  	case MVEBU_GPIO_SOC_VARIANT_MV78200:
  		cpu = smp_processor_id();
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
232
233
234
  		*map = mvchip->regs;
  		*offset = GPIO_LEVEL_MASK_MV78200_OFF(cpu);
  		break;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
235
236
  	case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
  		cpu = smp_processor_id();
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
237
238
239
  		*map = mvchip->percpu_regs;
  		*offset = GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu);
  		break;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
240
241
242
243
  	default:
  		BUG();
  	}
  }
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
  static u32
  mvebu_gpio_read_level_mask(struct mvebu_gpio_chip *mvchip)
  {
  	struct regmap *map;
  	unsigned int offset;
  	u32 val;
  
  	mvebu_gpioreg_level_mask(mvchip, &map, &offset);
  	regmap_read(map, offset, &val);
  
  	return val;
  }
  
  static void
  mvebu_gpio_write_level_mask(struct mvebu_gpio_chip *mvchip, u32 val)
  {
  	struct regmap *map;
  	unsigned int offset;
  
  	mvebu_gpioreg_level_mask(mvchip, &map, &offset);
  	regmap_write(map, offset, val);
  }
fefe7b092   Thomas Petazzoni   gpio: introduce g...
266
  /*
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
   * Functions returning addresses of individual registers for a given
   * PWM controller.
   */
  static void __iomem *mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm)
  {
  	return mvpwm->membase + PWM_BLINK_ON_DURATION_OFF;
  }
  
  static void __iomem *mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm)
  {
  	return mvpwm->membase + PWM_BLINK_OFF_DURATION_OFF;
  }
  
  /*
fefe7b092   Thomas Petazzoni   gpio: introduce g...
281
282
   * Functions implementing the gpio_chip methods
   */
d276de70d   Ralph Sennhauser   gpio: mvebu: chec...
283
  static void mvebu_gpio_set(struct gpio_chip *chip, unsigned int pin, int value)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
284
  {
bbe760041   Linus Walleij   gpio: mvebu: use ...
285
  	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
286

b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
287
  	regmap_update_bits(mvchip->regs, GPIO_OUT_OFF + mvchip->offset,
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
288
  			   BIT(pin), value ? BIT(pin) : 0);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
289
  }
d276de70d   Ralph Sennhauser   gpio: mvebu: chec...
290
  static int mvebu_gpio_get(struct gpio_chip *chip, unsigned int pin)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
291
  {
bbe760041   Linus Walleij   gpio: mvebu: use ...
292
  	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
293
  	u32 u;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
294
  	regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &u);
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
295
296
297
  
  	if (u & BIT(pin)) {
  		u32 data_in, in_pol;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
298
299
300
301
  		regmap_read(mvchip->regs, GPIO_DATA_IN_OFF + mvchip->offset,
  			    &data_in);
  		regmap_read(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset,
  			    &in_pol);
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
302
  		u = data_in ^ in_pol;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
303
  	} else {
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
304
  		regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, &u);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
305
306
307
308
  	}
  
  	return (u >> pin) & 1;
  }
d276de70d   Ralph Sennhauser   gpio: mvebu: chec...
309
310
  static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned int pin,
  			     int value)
e91337609   Jamie Lentin   mvebu-gpio: Disab...
311
  {
bbe760041   Linus Walleij   gpio: mvebu: use ...
312
  	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
e91337609   Jamie Lentin   mvebu-gpio: Disab...
313

b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
314
  	regmap_update_bits(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset,
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
315
  			   BIT(pin), value ? BIT(pin) : 0);
e91337609   Jamie Lentin   mvebu-gpio: Disab...
316
  }
d276de70d   Ralph Sennhauser   gpio: mvebu: chec...
317
  static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
318
  {
bbe760041   Linus Walleij   gpio: mvebu: use ...
319
  	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
320
  	int ret;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
321

7077f4cc1   Ralph Sennhauser   gpio: mvebu: chec...
322
323
324
325
  	/*
  	 * Check with the pinctrl driver whether this pin is usable as
  	 * an input GPIO
  	 */
fefe7b092   Thomas Petazzoni   gpio: introduce g...
326
327
328
  	ret = pinctrl_gpio_direction_input(chip->base + pin);
  	if (ret)
  		return ret;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
329
  	regmap_update_bits(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset,
43a2dcecd   Gregory CLEMENT   gpio: mvebu: fix ...
330
  			   BIT(pin), BIT(pin));
fefe7b092   Thomas Petazzoni   gpio: introduce g...
331
332
333
  
  	return 0;
  }
d276de70d   Ralph Sennhauser   gpio: mvebu: chec...
334
  static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned int pin,
fefe7b092   Thomas Petazzoni   gpio: introduce g...
335
336
  				       int value)
  {
bbe760041   Linus Walleij   gpio: mvebu: use ...
337
  	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
338
  	int ret;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
339

7077f4cc1   Ralph Sennhauser   gpio: mvebu: chec...
340
341
342
343
  	/*
  	 * Check with the pinctrl driver whether this pin is usable as
  	 * an output GPIO
  	 */
fefe7b092   Thomas Petazzoni   gpio: introduce g...
344
345
346
  	ret = pinctrl_gpio_direction_output(chip->base + pin);
  	if (ret)
  		return ret;
e91337609   Jamie Lentin   mvebu-gpio: Disab...
347
  	mvebu_gpio_blink(chip, pin, 0);
c57d75c09   Thomas Petazzoni   gpio: mvebu: corr...
348
  	mvebu_gpio_set(chip, pin, value);
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
349
  	regmap_update_bits(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset,
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
350
  			   BIT(pin), 0);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
351
352
353
  
  	return 0;
  }
d276de70d   Ralph Sennhauser   gpio: mvebu: chec...
354
  static int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned int pin)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
355
  {
bbe760041   Linus Walleij   gpio: mvebu: use ...
356
  	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
163ad364c   Ralph Sennhauser   gpio: mvebu: chec...
357

fefe7b092   Thomas Petazzoni   gpio: introduce g...
358
359
360
361
362
363
364
365
366
367
  	return irq_create_mapping(mvchip->domain, pin);
  }
  
  /*
   * Functions implementing the irq_chip methods
   */
  static void mvebu_gpio_irq_ack(struct irq_data *d)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  	struct mvebu_gpio_chip *mvchip = gc->private;
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
368
  	u32 mask = d->mask;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
369
370
  
  	irq_gc_lock(gc);
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
371
  	mvebu_gpio_write_edge_cause(mvchip, ~mask);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
372
373
374
375
376
377
378
  	irq_gc_unlock(gc);
  }
  
  static void mvebu_gpio_edge_irq_mask(struct irq_data *d)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  	struct mvebu_gpio_chip *mvchip = gc->private;
61819549f   Gregory CLEMENT   gpio: mvebu: Fix ...
379
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
380
  	u32 mask = d->mask;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
381
382
  
  	irq_gc_lock(gc);
61819549f   Gregory CLEMENT   gpio: mvebu: Fix ...
383
  	ct->mask_cache_priv &= ~mask;
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
384
  	mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
385
386
387
388
389
390
391
  	irq_gc_unlock(gc);
  }
  
  static void mvebu_gpio_edge_irq_unmask(struct irq_data *d)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  	struct mvebu_gpio_chip *mvchip = gc->private;
61819549f   Gregory CLEMENT   gpio: mvebu: Fix ...
392
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
393
  	u32 mask = d->mask;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
394
395
  
  	irq_gc_lock(gc);
61819549f   Gregory CLEMENT   gpio: mvebu: Fix ...
396
  	ct->mask_cache_priv |= mask;
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
397
  	mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
398
399
400
401
402
403
404
  	irq_gc_unlock(gc);
  }
  
  static void mvebu_gpio_level_irq_mask(struct irq_data *d)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  	struct mvebu_gpio_chip *mvchip = gc->private;
61819549f   Gregory CLEMENT   gpio: mvebu: Fix ...
405
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
406
  	u32 mask = d->mask;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
407
408
  
  	irq_gc_lock(gc);
61819549f   Gregory CLEMENT   gpio: mvebu: Fix ...
409
  	ct->mask_cache_priv &= ~mask;
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
410
  	mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
411
412
413
414
415
416
417
  	irq_gc_unlock(gc);
  }
  
  static void mvebu_gpio_level_irq_unmask(struct irq_data *d)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  	struct mvebu_gpio_chip *mvchip = gc->private;
61819549f   Gregory CLEMENT   gpio: mvebu: Fix ...
418
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
419
  	u32 mask = d->mask;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
420
421
  
  	irq_gc_lock(gc);
61819549f   Gregory CLEMENT   gpio: mvebu: Fix ...
422
  	ct->mask_cache_priv |= mask;
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
423
  	mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
424
425
426
427
428
429
430
431
432
433
  	irq_gc_unlock(gc);
  }
  
  /*****************************************************************************
   * MVEBU GPIO IRQ
   *
   * GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same
   * value of the line or the opposite value.
   *
   * Level IRQ handlers: DATA_IN is used directly as cause register.
a4319a611   Andrew Lunn   gpio: mvebu: chec...
434
   *		       Interrupt are masked by LEVEL_MASK registers.
fefe7b092   Thomas Petazzoni   gpio: introduce g...
435
   * Edge IRQ handlers:  Change in DATA_IN are latched in EDGE_CAUSE.
a4319a611   Andrew Lunn   gpio: mvebu: chec...
436
   *		       Interrupt are masked by EDGE_MASK registers.
fefe7b092   Thomas Petazzoni   gpio: introduce g...
437
   * Both-edge handlers: Similar to regular Edge handlers, but also swaps
a4319a611   Andrew Lunn   gpio: mvebu: chec...
438
439
440
   *		       the polarity to catch the next line transaction.
   *		       This is a race condition that might not perfectly
   *		       work on some use cases.
fefe7b092   Thomas Petazzoni   gpio: introduce g...
441
442
443
444
   *
   * Every eight GPIO lines are grouped (OR'ed) before going up to main
   * cause register.
   *
a4319a611   Andrew Lunn   gpio: mvebu: chec...
445
446
447
448
449
   *		      EDGE  cause    mask
   *	  data-in   /--------| |-----| |----\
   *     -----| |-----			     ---- to main cause reg
   *	     X	    \----------------| |----/
   *	  polarity    LEVEL	     mask
fefe7b092   Thomas Petazzoni   gpio: introduce g...
450
451
452
453
454
455
456
457
458
459
460
461
   *
   ****************************************************************************/
  
  static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type)
  {
  	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  	struct irq_chip_type *ct = irq_data_get_chip_type(d);
  	struct mvebu_gpio_chip *mvchip = gc->private;
  	int pin;
  	u32 u;
  
  	pin = d->hwirq;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
462
  	regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &u);
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
463
  	if ((u & BIT(pin)) == 0)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
464
  		return -EINVAL;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
465
466
467
468
469
470
471
472
473
474
475
476
477
  
  	type &= IRQ_TYPE_SENSE_MASK;
  	if (type == IRQ_TYPE_NONE)
  		return -EINVAL;
  
  	/* Check if we need to change chip and handler */
  	if (!(ct->type & type))
  		if (irq_setup_alt_chip(d, type))
  			return -EINVAL;
  
  	/*
  	 * Configure interrupt polarity.
  	 */
f4dcd2d94   Laurent Navet   gpio: gpio-mvebu....
478
  	switch (type) {
fefe7b092   Thomas Petazzoni   gpio: introduce g...
479
480
  	case IRQ_TYPE_EDGE_RISING:
  	case IRQ_TYPE_LEVEL_HIGH:
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
481
482
  		regmap_update_bits(mvchip->regs,
  				   GPIO_IN_POL_OFF + mvchip->offset,
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
483
  				   BIT(pin), 0);
7cf8c9f78   Axel Lin   gpio: mvebu: Add ...
484
  		break;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
485
486
  	case IRQ_TYPE_EDGE_FALLING:
  	case IRQ_TYPE_LEVEL_LOW:
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
487
488
  		regmap_update_bits(mvchip->regs,
  				   GPIO_IN_POL_OFF + mvchip->offset,
43a2dcecd   Gregory CLEMENT   gpio: mvebu: fix ...
489
  				   BIT(pin), BIT(pin));
7cf8c9f78   Axel Lin   gpio: mvebu: Add ...
490
  		break;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
491
  	case IRQ_TYPE_EDGE_BOTH: {
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
492
  		u32 data_in, in_pol, val;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
493

b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
494
495
496
497
  		regmap_read(mvchip->regs,
  			    GPIO_IN_POL_OFF + mvchip->offset, &in_pol);
  		regmap_read(mvchip->regs,
  			    GPIO_DATA_IN_OFF + mvchip->offset, &data_in);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
498
499
500
501
  
  		/*
  		 * set initial polarity based on current input level
  		 */
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
502
503
  		if ((data_in ^ in_pol) & BIT(pin))
  			val = BIT(pin); /* falling */
fefe7b092   Thomas Petazzoni   gpio: introduce g...
504
  		else
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
505
  			val = 0; /* raising */
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
506
507
  		regmap_update_bits(mvchip->regs,
  				   GPIO_IN_POL_OFF + mvchip->offset,
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
508
  				   BIT(pin), val);
7cf8c9f78   Axel Lin   gpio: mvebu: Add ...
509
  		break;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
510
511
512
513
  	}
  	}
  	return 0;
  }
bd0b9ac40   Thomas Gleixner   genirq: Remove ir...
514
  static void mvebu_gpio_irq_handler(struct irq_desc *desc)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
515
  {
476f8b4c9   Jiang Liu   gpio: Use irq_des...
516
  	struct mvebu_gpio_chip *mvchip = irq_desc_get_handler_data(desc);
01ca59f1b   Thomas Petazzoni   gpio: mvebu: use ...
517
  	struct irq_chip *chip = irq_desc_get_chip(desc);
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
518
  	u32 cause, type, data_in, level_mask, edge_cause, edge_mask;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
519
520
521
522
  	int i;
  
  	if (mvchip == NULL)
  		return;
01ca59f1b   Thomas Petazzoni   gpio: mvebu: use ...
523
  	chained_irq_enter(chip, desc);
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
524
  	regmap_read(mvchip->regs, GPIO_DATA_IN_OFF + mvchip->offset, &data_in);
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
525
526
527
  	level_mask = mvebu_gpio_read_level_mask(mvchip);
  	edge_cause = mvebu_gpio_read_edge_cause(mvchip);
  	edge_mask  = mvebu_gpio_read_edge_mask(mvchip);
3f13b6a24   Gregory CLEMENT   gpio: mvebu: Fix ...
528
  	cause = (data_in & level_mask) | (edge_cause & edge_mask);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
529
530
531
  
  	for (i = 0; i < mvchip->chip.ngpio; i++) {
  		int irq;
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
532
  		irq = irq_find_mapping(mvchip->domain, i);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
533

d2cabc4a2   Ralph Sennhauser   gpio: mvebu: use ...
534
  		if (!(cause & BIT(i)))
fefe7b092   Thomas Petazzoni   gpio: introduce g...
535
  			continue;
fb90c22ab   Javier Martinez Canillas   gpio: mvebu: Use ...
536
  		type = irq_get_trigger_type(irq);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
537
538
539
  		if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) {
  			/* Swap polarity (race with GPIO line) */
  			u32 polarity;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
540
541
542
  			regmap_read(mvchip->regs,
  				    GPIO_IN_POL_OFF + mvchip->offset,
  				    &polarity);
d2cabc4a2   Ralph Sennhauser   gpio: mvebu: use ...
543
  			polarity ^= BIT(i);
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
544
545
546
  			regmap_write(mvchip->regs,
  				     GPIO_IN_POL_OFF + mvchip->offset,
  				     polarity);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
547
  		}
01ca59f1b   Thomas Petazzoni   gpio: mvebu: use ...
548

fefe7b092   Thomas Petazzoni   gpio: introduce g...
549
550
  		generic_handle_irq(irq);
  	}
01ca59f1b   Thomas Petazzoni   gpio: mvebu: use ...
551
552
  
  	chained_irq_exit(chip, desc);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
553
  }
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
  /*
   * Functions implementing the pwm_chip methods
   */
  static struct mvebu_pwm *to_mvebu_pwm(struct pwm_chip *chip)
  {
  	return container_of(chip, struct mvebu_pwm, chip);
  }
  
  static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
  {
  	struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
  	struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
  	struct gpio_desc *desc;
  	unsigned long flags;
  	int ret = 0;
  
  	spin_lock_irqsave(&mvpwm->lock, flags);
  
  	if (mvpwm->gpiod) {
  		ret = -EBUSY;
  	} else {
  		desc = gpio_to_desc(mvchip->chip.base + pwm->hwpwm);
  		if (!desc) {
  			ret = -ENODEV;
  			goto out;
  		}
  
  		ret = gpiod_request(desc, "mvebu-pwm");
  		if (ret)
  			goto out;
  
  		ret = gpiod_direction_output(desc, 0);
  		if (ret) {
  			gpiod_free(desc);
  			goto out;
  		}
  
  		mvpwm->gpiod = desc;
  	}
  out:
  	spin_unlock_irqrestore(&mvpwm->lock, flags);
  	return ret;
  }
  
  static void mvebu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
  {
  	struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
  	unsigned long flags;
  
  	spin_lock_irqsave(&mvpwm->lock, flags);
  	gpiod_free(mvpwm->gpiod);
  	mvpwm->gpiod = NULL;
  	spin_unlock_irqrestore(&mvpwm->lock, flags);
  }
  
  static void mvebu_pwm_get_state(struct pwm_chip *chip,
  				struct pwm_device *pwm,
  				struct pwm_state *state) {
  
  	struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
  	struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
  	unsigned long long val;
  	unsigned long flags;
  	u32 u;
  
  	spin_lock_irqsave(&mvpwm->lock, flags);
  
  	val = (unsigned long long)
  		readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
  	val *= NSEC_PER_SEC;
  	do_div(val, mvpwm->clk_rate);
  	if (val > UINT_MAX)
  		state->duty_cycle = UINT_MAX;
  	else if (val)
  		state->duty_cycle = val;
  	else
  		state->duty_cycle = 1;
  
  	val = (unsigned long long)
  		readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
  	val *= NSEC_PER_SEC;
  	do_div(val, mvpwm->clk_rate);
  	if (val < state->duty_cycle) {
  		state->period = 1;
  	} else {
  		val -= state->duty_cycle;
  		if (val > UINT_MAX)
  			state->period = UINT_MAX;
  		else if (val)
  			state->period = val;
  		else
  			state->period = 1;
  	}
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
647
  	regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u);
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
  	if (u)
  		state->enabled = true;
  	else
  		state->enabled = false;
  
  	spin_unlock_irqrestore(&mvpwm->lock, flags);
  }
  
  static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
  			   struct pwm_state *state)
  {
  	struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
  	struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
  	unsigned long long val;
  	unsigned long flags;
  	unsigned int on, off;
  
  	val = (unsigned long long) mvpwm->clk_rate * state->duty_cycle;
  	do_div(val, NSEC_PER_SEC);
  	if (val > UINT_MAX)
  		return -EINVAL;
  	if (val)
  		on = val;
  	else
  		on = 1;
  
  	val = (unsigned long long) mvpwm->clk_rate *
  		(state->period - state->duty_cycle);
  	do_div(val, NSEC_PER_SEC);
  	if (val > UINT_MAX)
  		return -EINVAL;
  	if (val)
  		off = val;
  	else
  		off = 1;
  
  	spin_lock_irqsave(&mvpwm->lock, flags);
  
  	writel_relaxed(on, mvebu_pwmreg_blink_on_duration(mvpwm));
  	writel_relaxed(off, mvebu_pwmreg_blink_off_duration(mvpwm));
  	if (state->enabled)
  		mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 1);
  	else
  		mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 0);
  
  	spin_unlock_irqrestore(&mvpwm->lock, flags);
  
  	return 0;
  }
  
  static const struct pwm_ops mvebu_pwm_ops = {
  	.request = mvebu_pwm_request,
  	.free = mvebu_pwm_free,
  	.get_state = mvebu_pwm_get_state,
  	.apply = mvebu_pwm_apply,
  	.owner = THIS_MODULE,
  };
  
  static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip)
  {
  	struct mvebu_pwm *mvpwm = mvchip->mvpwm;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
709
  	regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
710
  		    &mvpwm->blink_select);
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
711
712
713
714
715
716
717
718
719
  	mvpwm->blink_on_duration =
  		readl_relaxed(mvebu_pwmreg_blink_on_duration(mvpwm));
  	mvpwm->blink_off_duration =
  		readl_relaxed(mvebu_pwmreg_blink_off_duration(mvpwm));
  }
  
  static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
  {
  	struct mvebu_pwm *mvpwm = mvchip->mvpwm;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
720
  	regmap_write(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
721
  		     mvpwm->blink_select);
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
  	writel_relaxed(mvpwm->blink_on_duration,
  		       mvebu_pwmreg_blink_on_duration(mvpwm));
  	writel_relaxed(mvpwm->blink_off_duration,
  		       mvebu_pwmreg_blink_off_duration(mvpwm));
  }
  
  static int mvebu_pwm_probe(struct platform_device *pdev,
  			   struct mvebu_gpio_chip *mvchip,
  			   int id)
  {
  	struct device *dev = &pdev->dev;
  	struct mvebu_pwm *mvpwm;
  	struct resource *res;
  	u32 set;
  
  	if (!of_device_is_compatible(mvchip->chip.of_node,
6c7515c61   Ralph Sennhauser   gpio: mvebu: chan...
738
  				     "marvell,armada-370-gpio"))
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
  		return 0;
  
  	if (IS_ERR(mvchip->clk))
  		return PTR_ERR(mvchip->clk);
  
  	/*
  	 * There are only two sets of PWM configuration registers for
  	 * all the GPIO lines on those SoCs which this driver reserves
  	 * for the first two GPIO chips. So if the resource is missing
  	 * we can't treat it as an error.
  	 */
  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm");
  	if (!res)
  		return 0;
  
  	/*
  	 * Use set A for lines of GPIO chip with id 0, B for GPIO chip
  	 * with id 1. Don't allow further GPIO chips to be used for PWM.
  	 */
  	if (id == 0)
  		set = 0;
  	else if (id == 1)
  		set = U32_MAX;
  	else
  		return -EINVAL;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
764
  	regmap_write(mvchip->regs,
c7d28eca1   Linus Torvalds   Merge tag 'gpio-v...
765
  		     GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set);
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
  
  	mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL);
  	if (!mvpwm)
  		return -ENOMEM;
  	mvchip->mvpwm = mvpwm;
  	mvpwm->mvchip = mvchip;
  
  	mvpwm->membase = devm_ioremap_resource(dev, res);
  	if (IS_ERR(mvpwm->membase))
  		return PTR_ERR(mvpwm->membase);
  
  	mvpwm->clk_rate = clk_get_rate(mvchip->clk);
  	if (!mvpwm->clk_rate) {
  		dev_err(dev, "failed to get clock rate
  ");
  		return -EINVAL;
  	}
  
  	mvpwm->chip.dev = dev;
  	mvpwm->chip.ops = &mvebu_pwm_ops;
  	mvpwm->chip.npwm = mvchip->chip.ngpio;
fc7a90686   Richard Genoud   gpio: mvebu: fix ...
787
788
789
790
791
792
793
  	/*
  	 * There may already be some PWM allocated, so we can't force
  	 * mvpwm->chip.base to a fixed point like mvchip->chip.base.
  	 * So, we let pwmchip_add() do the numbering and take the next free
  	 * region.
  	 */
  	mvpwm->chip.base = -1;
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
794
795
796
797
798
  
  	spin_lock_init(&mvpwm->lock);
  
  	return pwmchip_add(&mvpwm->chip);
  }
a4ba5e1b9   Simon Guinot   gpio: mvebu: add ...
799
800
801
802
803
  #ifdef CONFIG_DEBUG_FS
  #include <linux/seq_file.h>
  
  static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
  {
bbe760041   Linus Walleij   gpio: mvebu: use ...
804
  	struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip);
a4ba5e1b9   Simon Guinot   gpio: mvebu: add ...
805
806
  	u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk;
  	int i;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
807
808
809
810
811
  	regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, &out);
  	regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &io_conf);
  	regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &blink);
  	regmap_read(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset, &in_pol);
  	regmap_read(mvchip->regs, GPIO_DATA_IN_OFF + mvchip->offset, &data_in);
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
812
813
814
  	cause	= mvebu_gpio_read_edge_cause(mvchip);
  	edg_msk	= mvebu_gpio_read_edge_mask(mvchip);
  	lvl_msk	= mvebu_gpio_read_level_mask(mvchip);
a4ba5e1b9   Simon Guinot   gpio: mvebu: add ...
815
816
817
818
819
820
821
822
823
  
  	for (i = 0; i < chip->ngpio; i++) {
  		const char *label;
  		u32 msk;
  		bool is_out;
  
  		label = gpiochip_is_requested(chip, i);
  		if (!label)
  			continue;
d2cabc4a2   Ralph Sennhauser   gpio: mvebu: use ...
824
  		msk = BIT(i);
a4ba5e1b9   Simon Guinot   gpio: mvebu: add ...
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
  		is_out = !(io_conf & msk);
  
  		seq_printf(s, " gpio-%-3d (%-20.20s)", chip->base + i, label);
  
  		if (is_out) {
  			seq_printf(s, " out %s %s
  ",
  				   out & msk ? "hi" : "lo",
  				   blink & msk ? "(blink )" : "");
  			continue;
  		}
  
  		seq_printf(s, " in  %s (act %s) - IRQ",
  			   (data_in ^ in_pol) & msk  ? "hi" : "lo",
  			   in_pol & msk ? "lo" : "hi");
  		if (!((edg_msk | lvl_msk) & msk)) {
a4319a611   Andrew Lunn   gpio: mvebu: chec...
841
842
  			seq_puts(s, " disabled
  ");
a4ba5e1b9   Simon Guinot   gpio: mvebu: add ...
843
844
845
  			continue;
  		}
  		if (edg_msk & msk)
a4319a611   Andrew Lunn   gpio: mvebu: chec...
846
  			seq_puts(s, " edge ");
a4ba5e1b9   Simon Guinot   gpio: mvebu: add ...
847
  		if (lvl_msk & msk)
a4319a611   Andrew Lunn   gpio: mvebu: chec...
848
  			seq_puts(s, " level");
a4ba5e1b9   Simon Guinot   gpio: mvebu: add ...
849
850
851
852
853
854
855
  		seq_printf(s, " (%s)
  ", cause & msk ? "pending" : "clear  ");
  	}
  }
  #else
  #define mvebu_gpio_dbg_show NULL
  #endif
271b17b69   Jingoo Han   gpio: mvebu: Make...
856
  static const struct of_device_id mvebu_gpio_of_match[] = {
fefe7b092   Thomas Petazzoni   gpio: introduce g...
857
858
  	{
  		.compatible = "marvell,orion-gpio",
a4319a611   Andrew Lunn   gpio: mvebu: chec...
859
  		.data	    = (void *) MVEBU_GPIO_SOC_VARIANT_ORION,
fefe7b092   Thomas Petazzoni   gpio: introduce g...
860
861
862
  	},
  	{
  		.compatible = "marvell,mv78200-gpio",
a4319a611   Andrew Lunn   gpio: mvebu: chec...
863
  		.data	    = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200,
fefe7b092   Thomas Petazzoni   gpio: introduce g...
864
865
866
  	},
  	{
  		.compatible = "marvell,armadaxp-gpio",
a4319a611   Andrew Lunn   gpio: mvebu: chec...
867
  		.data	    = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP,
fefe7b092   Thomas Petazzoni   gpio: introduce g...
868
869
  	},
  	{
6c7515c61   Ralph Sennhauser   gpio: mvebu: chan...
870
  		.compatible = "marvell,armada-370-gpio",
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
871
872
873
  		.data	    = (void *) MVEBU_GPIO_SOC_VARIANT_ORION,
  	},
  	{
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
874
875
876
877
  		.compatible = "marvell,armada-8k-gpio",
  		.data       = (void *) MVEBU_GPIO_SOC_VARIANT_A8K,
  	},
  	{
fefe7b092   Thomas Petazzoni   gpio: introduce g...
878
879
880
  		/* sentinel */
  	},
  };
fefe7b092   Thomas Petazzoni   gpio: introduce g...
881

b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
882
883
884
885
  static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
  {
  	struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev);
  	int i;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
886
887
888
889
890
891
892
893
  	regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset,
  		    &mvchip->out_reg);
  	regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset,
  		    &mvchip->io_conf_reg);
  	regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset,
  		    &mvchip->blink_en_reg);
  	regmap_read(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset,
  		    &mvchip->in_pol_reg);
b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
894
895
896
  
  	switch (mvchip->soc_variant) {
  	case MVEBU_GPIO_SOC_VARIANT_ORION:
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
897
898
  	case MVEBU_GPIO_SOC_VARIANT_A8K:
  		regmap_read(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset,
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
899
  			    &mvchip->edge_mask_regs[0]);
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
900
  		regmap_read(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset,
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
901
  			    &mvchip->level_mask_regs[0]);
b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
902
903
904
  		break;
  	case MVEBU_GPIO_SOC_VARIANT_MV78200:
  		for (i = 0; i < 2; i++) {
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
905
906
907
908
909
910
  			regmap_read(mvchip->regs,
  				    GPIO_EDGE_MASK_MV78200_OFF(i),
  				    &mvchip->edge_mask_regs[i]);
  			regmap_read(mvchip->regs,
  				    GPIO_LEVEL_MASK_MV78200_OFF(i),
  				    &mvchip->level_mask_regs[i]);
b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
911
912
913
914
  		}
  		break;
  	case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
  		for (i = 0; i < 4; i++) {
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
915
916
917
918
919
920
  			regmap_read(mvchip->regs,
  				    GPIO_EDGE_MASK_ARMADAXP_OFF(i),
  				    &mvchip->edge_mask_regs[i]);
  			regmap_read(mvchip->regs,
  				    GPIO_LEVEL_MASK_ARMADAXP_OFF(i),
  				    &mvchip->level_mask_regs[i]);
b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
921
922
923
924
925
  		}
  		break;
  	default:
  		BUG();
  	}
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
926
927
  	if (IS_ENABLED(CONFIG_PWM))
  		mvebu_pwm_suspend(mvchip);
b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
928
929
930
931
932
933
934
  	return 0;
  }
  
  static int mvebu_gpio_resume(struct platform_device *pdev)
  {
  	struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev);
  	int i;
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
935
936
937
938
939
940
941
942
  	regmap_write(mvchip->regs, GPIO_OUT_OFF + mvchip->offset,
  		     mvchip->out_reg);
  	regmap_write(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset,
  		     mvchip->io_conf_reg);
  	regmap_write(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset,
  		     mvchip->blink_en_reg);
  	regmap_write(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset,
  		     mvchip->in_pol_reg);
b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
943
944
945
  
  	switch (mvchip->soc_variant) {
  	case MVEBU_GPIO_SOC_VARIANT_ORION:
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
946
947
  	case MVEBU_GPIO_SOC_VARIANT_A8K:
  		regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset,
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
948
  			     mvchip->edge_mask_regs[0]);
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
949
  		regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset,
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
950
  			     mvchip->level_mask_regs[0]);
b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
951
952
953
  		break;
  	case MVEBU_GPIO_SOC_VARIANT_MV78200:
  		for (i = 0; i < 2; i++) {
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
954
955
956
957
958
959
  			regmap_write(mvchip->regs,
  				     GPIO_EDGE_MASK_MV78200_OFF(i),
  				     mvchip->edge_mask_regs[i]);
  			regmap_write(mvchip->regs,
  				     GPIO_LEVEL_MASK_MV78200_OFF(i),
  				     mvchip->level_mask_regs[i]);
b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
960
961
962
963
  		}
  		break;
  	case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
  		for (i = 0; i < 4; i++) {
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
964
965
966
967
968
969
  			regmap_write(mvchip->regs,
  				     GPIO_EDGE_MASK_ARMADAXP_OFF(i),
  				     mvchip->edge_mask_regs[i]);
  			regmap_write(mvchip->regs,
  				     GPIO_LEVEL_MASK_ARMADAXP_OFF(i),
  				     mvchip->level_mask_regs[i]);
b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
970
971
972
973
974
  		}
  		break;
  	default:
  		BUG();
  	}
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
975
976
  	if (IS_ENABLED(CONFIG_PWM))
  		mvebu_pwm_resume(mvchip);
b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
977
978
  	return 0;
  }
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
979
980
981
982
983
984
  static const struct regmap_config mvebu_gpio_regmap_config = {
  	.reg_bits = 32,
  	.reg_stride = 4,
  	.val_bits = 32,
  	.fast_io = true,
  };
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
  static int mvebu_gpio_probe_raw(struct platform_device *pdev,
  				struct mvebu_gpio_chip *mvchip)
  {
  	struct resource *res;
  	void __iomem *base;
  
  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	base = devm_ioremap_resource(&pdev->dev, res);
  	if (IS_ERR(base))
  		return PTR_ERR(base);
  
  	mvchip->regs = devm_regmap_init_mmio(&pdev->dev, base,
  					     &mvebu_gpio_regmap_config);
  	if (IS_ERR(mvchip->regs))
  		return PTR_ERR(mvchip->regs);
  
  	/*
  	 * For the legacy SoCs, the regmap directly maps to the GPIO
  	 * registers, so no offset is needed.
  	 */
  	mvchip->offset = 0;
  
  	/*
  	 * The Armada XP has a second range of registers for the
  	 * per-CPU registers
  	 */
  	if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) {
  		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
  		base = devm_ioremap_resource(&pdev->dev, res);
  		if (IS_ERR(base))
  			return PTR_ERR(base);
  
  		mvchip->percpu_regs =
  			devm_regmap_init_mmio(&pdev->dev, base,
  					      &mvebu_gpio_regmap_config);
  		if (IS_ERR(mvchip->percpu_regs))
  			return PTR_ERR(mvchip->percpu_regs);
  	}
  
  	return 0;
  }
  
  static int mvebu_gpio_probe_syscon(struct platform_device *pdev,
  				   struct mvebu_gpio_chip *mvchip)
  {
  	mvchip->regs = syscon_node_to_regmap(pdev->dev.parent->of_node);
  	if (IS_ERR(mvchip->regs))
  		return PTR_ERR(mvchip->regs);
  
  	if (of_property_read_u32(pdev->dev.of_node, "offset", &mvchip->offset))
  		return -EINVAL;
  
  	return 0;
  }
3836309d9   Bill Pemberton   gpio: remove use ...
1039
  static int mvebu_gpio_probe(struct platform_device *pdev)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1040
1041
1042
1043
  {
  	struct mvebu_gpio_chip *mvchip;
  	const struct of_device_id *match;
  	struct device_node *np = pdev->dev.of_node;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1044
1045
1046
  	struct irq_chip_generic *gc;
  	struct irq_chip_type *ct;
  	unsigned int ngpios;
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
1047
  	bool have_irqs;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1048
1049
  	int soc_variant;
  	int i, cpu, id;
f1d2d081e   Andrew Lunn   gpio: mvebu: Fix ...
1050
  	int err;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1051
1052
1053
  
  	match = of_match_device(mvebu_gpio_of_match, &pdev->dev);
  	if (match)
f0d504607   Russell King   gpio: mvebu: fix ...
1054
  		soc_variant = (unsigned long) match->data;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1055
1056
  	else
  		soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
1057
1058
  	/* Some gpio controllers do not provide irq support */
  	have_irqs = of_irq_count(np) != 0;
a4319a611   Andrew Lunn   gpio: mvebu: chec...
1059
1060
  	mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip),
  			      GFP_KERNEL);
6c8365f68   Jingoo Han   gpio: mvebu: remo...
1061
  	if (!mvchip)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1062
  		return -ENOMEM;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1063

b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
1064
  	platform_set_drvdata(pdev, mvchip);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
  	if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) {
  		dev_err(&pdev->dev, "Missing ngpios OF property
  ");
  		return -ENODEV;
  	}
  
  	id = of_alias_get_id(pdev->dev.of_node, "gpio");
  	if (id < 0) {
  		dev_err(&pdev->dev, "Couldn't get OF id
  ");
  		return id;
  	}
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
1077
  	mvchip->clk = devm_clk_get(&pdev->dev, NULL);
de88747f5   Andrew Lunn   gpio: mvebu: Add ...
1078
  	/* Not all SoCs require a clock.*/
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
1079
1080
  	if (!IS_ERR(mvchip->clk))
  		clk_prepare_enable(mvchip->clk);
de88747f5   Andrew Lunn   gpio: mvebu: Add ...
1081

fefe7b092   Thomas Petazzoni   gpio: introduce g...
1082
1083
  	mvchip->soc_variant = soc_variant;
  	mvchip->chip.label = dev_name(&pdev->dev);
58383c784   Linus Walleij   gpio: change memb...
1084
  	mvchip->chip.parent = &pdev->dev;
203f0daaf   Jonas Gorski   gpio: replace tri...
1085
1086
  	mvchip->chip.request = gpiochip_generic_request;
  	mvchip->chip.free = gpiochip_generic_free;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1087
1088
1089
1090
  	mvchip->chip.direction_input = mvebu_gpio_direction_input;
  	mvchip->chip.get = mvebu_gpio_get;
  	mvchip->chip.direction_output = mvebu_gpio_direction_output;
  	mvchip->chip.set = mvebu_gpio_set;
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
1091
1092
  	if (have_irqs)
  		mvchip->chip.to_irq = mvebu_gpio_to_irq;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1093
1094
  	mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK;
  	mvchip->chip.ngpio = ngpios;
9fb1f39eb   Linus Walleij   gpio/pinctrl: mak...
1095
  	mvchip->chip.can_sleep = false;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1096
  	mvchip->chip.of_node = np;
a4ba5e1b9   Simon Guinot   gpio: mvebu: add ...
1097
  	mvchip->chip.dbg_show = mvebu_gpio_dbg_show;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1098

b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
1099
1100
1101
1102
  	if (soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K)
  		err = mvebu_gpio_probe_syscon(pdev, mvchip);
  	else
  		err = mvebu_gpio_probe_raw(pdev, mvchip);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1103

b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
1104
1105
  	if (err)
  		return err;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1106
1107
1108
1109
  
  	/*
  	 * Mask and clear GPIO interrupts.
  	 */
f4dcd2d94   Laurent Navet   gpio: gpio-mvebu....
1110
  	switch (soc_variant) {
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1111
  	case MVEBU_GPIO_SOC_VARIANT_ORION:
b6730b208   Gregory CLEMENT   gpio: mvebu: Add ...
1112
1113
1114
1115
1116
1117
1118
  	case MVEBU_GPIO_SOC_VARIANT_A8K:
  		regmap_write(mvchip->regs,
  			     GPIO_EDGE_CAUSE_OFF + mvchip->offset, 0);
  		regmap_write(mvchip->regs,
  			     GPIO_EDGE_MASK_OFF + mvchip->offset, 0);
  		regmap_write(mvchip->regs,
  			     GPIO_LEVEL_MASK_OFF + mvchip->offset, 0);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1119
1120
  		break;
  	case MVEBU_GPIO_SOC_VARIANT_MV78200:
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
1121
  		regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1122
  		for (cpu = 0; cpu < 2; cpu++) {
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
1123
1124
1125
1126
  			regmap_write(mvchip->regs,
  				     GPIO_EDGE_MASK_MV78200_OFF(cpu), 0);
  			regmap_write(mvchip->regs,
  				     GPIO_LEVEL_MASK_MV78200_OFF(cpu), 0);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1127
1128
1129
  		}
  		break;
  	case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
1130
1131
1132
  		regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0);
  		regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF, 0);
  		regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF, 0);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1133
  		for (cpu = 0; cpu < 4; cpu++) {
2233bf7a9   Thomas Petazzoni   gpio: mvebu: swit...
1134
1135
1136
1137
1138
1139
  			regmap_write(mvchip->percpu_regs,
  				     GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu), 0);
  			regmap_write(mvchip->percpu_regs,
  				     GPIO_EDGE_MASK_ARMADAXP_OFF(cpu), 0);
  			regmap_write(mvchip->percpu_regs,
  				     GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu), 0);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1140
1141
1142
1143
1144
  		}
  		break;
  	default:
  		BUG();
  	}
00b9ab4a2   Laxman Dewangan   gpio: mvebu: Use ...
1145
  	devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1146
1147
  
  	/* Some gpio controllers do not provide irq support */
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
1148
  	if (!have_irqs)
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1149
  		return 0;
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
1150
1151
1152
1153
1154
1155
1156
  	mvchip->domain =
  	    irq_domain_add_linear(np, ngpios, &irq_generic_chip_ops, NULL);
  	if (!mvchip->domain) {
  		dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).
  ",
  			mvchip->chip.label);
  		return -ENODEV;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1157
  	}
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
1158
1159
1160
1161
1162
1163
1164
1165
  	err = irq_alloc_domain_generic_chips(
  	    mvchip->domain, ngpios, 2, np->name, handle_level_irq,
  	    IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0);
  	if (err) {
  		dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).
  ",
  			mvchip->chip.label);
  		goto err_domain;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1166
  	}
899c37edf   Ralph Sennhauser   gpio: mvebu: star...
1167
1168
  	/*
  	 * NOTE: The common accessors cannot be used because of the percpu
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
1169
1170
1171
  	 * access to the mask registers
  	 */
  	gc = irq_get_domain_generic_chip(mvchip->domain, 0);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
  	gc->private = mvchip;
  	ct = &gc->chip_types[0];
  	ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
  	ct->chip.irq_mask = mvebu_gpio_level_irq_mask;
  	ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask;
  	ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
  	ct->chip.name = mvchip->chip.label;
  
  	ct = &gc->chip_types[1];
  	ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
  	ct->chip.irq_ack = mvebu_gpio_irq_ack;
  	ct->chip.irq_mask = mvebu_gpio_edge_irq_mask;
  	ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask;
  	ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
  	ct->handler = handle_edge_irq;
  	ct->chip.name = mvchip->chip.label;
899c37edf   Ralph Sennhauser   gpio: mvebu: star...
1188
1189
  	/*
  	 * Setup the interrupt handlers. Each chip can have up to 4
812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
1190
1191
1192
1193
1194
  	 * interrupt handlers, with each handler dealing with 8 GPIO
  	 * pins.
  	 */
  	for (i = 0; i < 4; i++) {
  		int irq = platform_get_irq(pdev, i);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1195

812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
1196
1197
1198
1199
  		if (irq < 0)
  			continue;
  		irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler,
  						 mvchip);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1200
  	}
6c7515c61   Ralph Sennhauser   gpio: mvebu: chan...
1201
  	/* Some MVEBU SoCs have simple PWM support for GPIO lines */
757642f9a   Andrew Lunn   gpio: mvebu: Add ...
1202
1203
  	if (IS_ENABLED(CONFIG_PWM))
  		return mvebu_pwm_probe(pdev, mvchip, id);
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1204
  	return 0;
f1d2d081e   Andrew Lunn   gpio: mvebu: Fix ...
1205

812d47889   Jason Gunthorpe   gpio/mvebu: Use i...
1206
1207
  err_domain:
  	irq_domain_remove(mvchip->domain);
f1d2d081e   Andrew Lunn   gpio: mvebu: Fix ...
1208

f1d2d081e   Andrew Lunn   gpio: mvebu: Fix ...
1209
  	return err;
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1210
1211
1212
1213
  }
  
  static struct platform_driver mvebu_gpio_driver = {
  	.driver		= {
a4319a611   Andrew Lunn   gpio: mvebu: chec...
1214
  		.name		= "mvebu-gpio",
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1215
1216
1217
  		.of_match_table = mvebu_gpio_of_match,
  	},
  	.probe		= mvebu_gpio_probe,
b5b7b4874   Thomas Petazzoni   gpio: mvebu: add ...
1218
1219
  	.suspend        = mvebu_gpio_suspend,
  	.resume         = mvebu_gpio_resume,
fefe7b092   Thomas Petazzoni   gpio: introduce g...
1220
  };
ed329f3a6   Paul Gortmaker   gpio: mvebu: make...
1221
  builtin_platform_driver(mvebu_gpio_driver);