Blame view

drivers/bcma/driver_gpio.c 5.46 KB
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
1
2
3
4
5
6
7
8
9
  /*
   * Broadcom specific AMBA
   * GPIO driver
   *
   * Copyright 2011, Broadcom Corporation
   * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>
   *
   * Licensed under the GNU/GPL. See COPYING for details.
   */
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
10
  #include <linux/gpio/driver.h>
2997609eb   Rafał Miłecki   bcma: gpio: add o...
11
  #include <linux/interrupt.h>
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
12
13
14
15
  #include <linux/export.h>
  #include <linux/bcma/bcma.h>
  
  #include "bcma_private.h"
057fcd426   Rafał Miłecki   bcma: gpio: use p...
16
  #define BCMA_GPIO_MAX_PINS	32
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
17
18
  static int bcma_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
  {
78d455a2e   Linus Walleij   bcma: gpio: use g...
19
  	struct bcma_drv_cc *cc = gpiochip_get_data(chip);
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
20
21
22
23
24
25
26
  
  	return !!bcma_chipco_gpio_in(cc, 1 << gpio);
  }
  
  static void bcma_gpio_set_value(struct gpio_chip *chip, unsigned gpio,
  				int value)
  {
78d455a2e   Linus Walleij   bcma: gpio: use g...
27
  	struct bcma_drv_cc *cc = gpiochip_get_data(chip);
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
28
29
30
31
32
33
  
  	bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0);
  }
  
  static int bcma_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
  {
78d455a2e   Linus Walleij   bcma: gpio: use g...
34
  	struct bcma_drv_cc *cc = gpiochip_get_data(chip);
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
35
36
37
38
39
40
41
42
  
  	bcma_chipco_gpio_outen(cc, 1 << gpio, 0);
  	return 0;
  }
  
  static int bcma_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
  				      int value)
  {
78d455a2e   Linus Walleij   bcma: gpio: use g...
43
  	struct bcma_drv_cc *cc = gpiochip_get_data(chip);
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
44
45
46
47
48
49
50
51
  
  	bcma_chipco_gpio_outen(cc, 1 << gpio, 1 << gpio);
  	bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0);
  	return 0;
  }
  
  static int bcma_gpio_request(struct gpio_chip *chip, unsigned gpio)
  {
78d455a2e   Linus Walleij   bcma: gpio: use g...
52
  	struct bcma_drv_cc *cc = gpiochip_get_data(chip);
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
53
54
55
56
57
58
59
60
61
62
63
64
  
  	bcma_chipco_gpio_control(cc, 1 << gpio, 0);
  	/* clear pulldown */
  	bcma_chipco_gpio_pulldown(cc, 1 << gpio, 0);
  	/* Set pullup */
  	bcma_chipco_gpio_pullup(cc, 1 << gpio, 1 << gpio);
  
  	return 0;
  }
  
  static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio)
  {
78d455a2e   Linus Walleij   bcma: gpio: use g...
65
  	struct bcma_drv_cc *cc = gpiochip_get_data(chip);
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
66
67
68
69
  
  	/* clear pullup */
  	bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
  }
0cbfc065f   Rafał Miłecki   bcma: gpio: enabl...
70
  #if IS_BUILTIN(CONFIG_BCM47XX) || IS_BUILTIN(CONFIG_ARCH_BCM_5301X)
8f1ca2683   Hauke Mehrtens   bcma: add gpio_to...
71

2997609eb   Rafał Miłecki   bcma: gpio: add o...
72
73
  static void bcma_gpio_irq_unmask(struct irq_data *d)
  {
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
74
  	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
78d455a2e   Linus Walleij   bcma: gpio: use g...
75
  	struct bcma_drv_cc *cc = gpiochip_get_data(gc);
2997609eb   Rafał Miłecki   bcma: gpio: add o...
76
  	int gpio = irqd_to_hwirq(d);
978e55d2d   Hauke Mehrtens   bcma: prevent irq...
77
  	u32 val = bcma_chipco_gpio_in(cc, BIT(gpio));
2997609eb   Rafał Miłecki   bcma: gpio: add o...
78

978e55d2d   Hauke Mehrtens   bcma: prevent irq...
79
  	bcma_chipco_gpio_polarity(cc, BIT(gpio), val);
2997609eb   Rafał Miłecki   bcma: gpio: add o...
80
81
82
83
84
  	bcma_chipco_gpio_intmask(cc, BIT(gpio), BIT(gpio));
  }
  
  static void bcma_gpio_irq_mask(struct irq_data *d)
  {
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
85
  	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
78d455a2e   Linus Walleij   bcma: gpio: use g...
86
  	struct bcma_drv_cc *cc = gpiochip_get_data(gc);
2997609eb   Rafał Miłecki   bcma: gpio: add o...
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  	int gpio = irqd_to_hwirq(d);
  
  	bcma_chipco_gpio_intmask(cc, BIT(gpio), 0);
  }
  
  static struct irq_chip bcma_gpio_irq_chip = {
  	.name		= "BCMA-GPIO",
  	.irq_mask	= bcma_gpio_irq_mask,
  	.irq_unmask	= bcma_gpio_irq_unmask,
  };
  
  static irqreturn_t bcma_gpio_irq_handler(int irq, void *dev_id)
  {
  	struct bcma_drv_cc *cc = dev_id;
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
101
  	struct gpio_chip *gc = &cc->gpio;
2997609eb   Rafał Miłecki   bcma: gpio: add o...
102
103
104
  	u32 val = bcma_cc_read32(cc, BCMA_CC_GPIOIN);
  	u32 mask = bcma_cc_read32(cc, BCMA_CC_GPIOIRQ);
  	u32 pol = bcma_cc_read32(cc, BCMA_CC_GPIOPOL);
d5ab2adbc   Rafał Miłecki   bcma: gpio: don't...
105
  	unsigned long irqs = (val ^ pol) & mask;
2997609eb   Rafał Miłecki   bcma: gpio: add o...
106
107
108
109
  	int gpio;
  
  	if (!irqs)
  		return IRQ_NONE;
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
110
111
  	for_each_set_bit(gpio, &irqs, gc->ngpio)
  		generic_handle_irq(irq_find_mapping(gc->irqdomain, gpio));
2997609eb   Rafał Miłecki   bcma: gpio: add o...
112
113
114
115
  	bcma_chipco_gpio_polarity(cc, irqs, val & irqs);
  
  	return IRQ_HANDLED;
  }
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
116
  static int bcma_gpio_irq_init(struct bcma_drv_cc *cc)
2997609eb   Rafał Miłecki   bcma: gpio: add o...
117
118
  {
  	struct gpio_chip *chip = &cc->gpio;
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
119
  	int hwirq, err;
2997609eb   Rafał Miłecki   bcma: gpio: add o...
120
121
122
  
  	if (cc->core->bus->hosttype != BCMA_HOSTTYPE_SOC)
  		return 0;
85eb92e81   Hauke Mehrtens   bcma: make it pos...
123
  	hwirq = bcma_core_irq(cc->core, 0);
2997609eb   Rafał Miłecki   bcma: gpio: add o...
124
125
126
  	err = request_irq(hwirq, bcma_gpio_irq_handler, IRQF_SHARED, "gpio",
  			  cc);
  	if (err)
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
127
  		return err;
2997609eb   Rafał Miłecki   bcma: gpio: add o...
128

978e55d2d   Hauke Mehrtens   bcma: prevent irq...
129
  	bcma_chipco_gpio_intmask(cc, ~0, 0);
2997609eb   Rafał Miłecki   bcma: gpio: add o...
130
  	bcma_cc_set32(cc, BCMA_CC_IRQMASK, BCMA_CC_IRQ_GPIO);
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
131
132
133
134
135
136
137
138
  	err =  gpiochip_irqchip_add(chip,
  				    &bcma_gpio_irq_chip,
  				    0,
  				    handle_simple_irq,
  				    IRQ_TYPE_NONE);
  	if (err) {
  		free_irq(hwirq, cc);
  		return err;
2997609eb   Rafał Miłecki   bcma: gpio: add o...
139
  	}
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
140
141
  
  	return 0;
2997609eb   Rafał Miłecki   bcma: gpio: add o...
142
  }
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
143
  static void bcma_gpio_irq_exit(struct bcma_drv_cc *cc)
2997609eb   Rafał Miłecki   bcma: gpio: add o...
144
  {
2997609eb   Rafał Miłecki   bcma: gpio: add o...
145
146
147
148
  	if (cc->core->bus->hosttype != BCMA_HOSTTYPE_SOC)
  		return;
  
  	bcma_cc_mask32(cc, BCMA_CC_IRQMASK, ~BCMA_CC_IRQ_GPIO);
85eb92e81   Hauke Mehrtens   bcma: make it pos...
149
  	free_irq(bcma_core_irq(cc->core, 0), cc);
2997609eb   Rafał Miłecki   bcma: gpio: add o...
150
151
  }
  #else
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
152
  static int bcma_gpio_irq_init(struct bcma_drv_cc *cc)
2997609eb   Rafał Miłecki   bcma: gpio: add o...
153
154
155
  {
  	return 0;
  }
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
156
  static void bcma_gpio_irq_exit(struct bcma_drv_cc *cc)
2997609eb   Rafał Miłecki   bcma: gpio: add o...
157
158
159
  {
  }
  #endif
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
160
161
  int bcma_gpio_init(struct bcma_drv_cc *cc)
  {
057fcd426   Rafał Miłecki   bcma: gpio: use p...
162
  	struct bcma_bus *bus = cc->core->bus;
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
163
  	struct gpio_chip *chip = &cc->gpio;
2997609eb   Rafał Miłecki   bcma: gpio: add o...
164
  	int err;
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
165
166
167
168
169
170
171
172
173
  
  	chip->label		= "bcma_gpio";
  	chip->owner		= THIS_MODULE;
  	chip->request		= bcma_gpio_request;
  	chip->free		= bcma_gpio_free;
  	chip->get		= bcma_gpio_get_value;
  	chip->set		= bcma_gpio_set_value;
  	chip->direction_input	= bcma_gpio_direction_input;
  	chip->direction_output	= bcma_gpio_direction_output;
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
174
  	chip->owner		= THIS_MODULE;
58383c784   Linus Walleij   gpio: change memb...
175
  	chip->parent		= bcma_bus_get_host_dev(bus);
a0196d111   Rafał Miłecki   bcma: use chipcom...
176
  #if IS_BUILTIN(CONFIG_OF)
a4bb5b1b4   Rafał Miłecki   bcma: gpio: set o...
177
  	chip->of_node		= cc->core->dev.of_node;
a0196d111   Rafał Miłecki   bcma: use chipcom...
178
  #endif
057fcd426   Rafał Miłecki   bcma: gpio: use p...
179
  	switch (bus->chipinfo.id) {
f022ea52d   Felix Fietkau   bcma: enable 32 G...
180
  	case BCMA_CHIP_ID_BCM4707:
0f8ca0146   Rafał Miłecki   bcma: gpio: regis...
181
  	case BCMA_CHIP_ID_BCM5357:
f0db59e1c   Rafał Miłecki   bcma: gpio: regis...
182
  	case BCMA_CHIP_ID_BCM53572:
459c35148   Florian Fainelli   bcma: gpio: Corre...
183
  	case BCMA_CHIP_ID_BCM53573:
61dba73cd   Rafał Miłecki   bcma: add support...
184
  	case BCMA_CHIP_ID_BCM47094:
0f8ca0146   Rafał Miłecki   bcma: gpio: regis...
185
186
187
188
189
  		chip->ngpio	= 32;
  		break;
  	default:
  		chip->ngpio	= 16;
  	}
057fcd426   Rafał Miłecki   bcma: gpio: use p...
190
  	/*
2d57b7126   Felix Fietkau   bcma: use absolut...
191
192
193
194
195
  	 * Register SoC GPIO devices with absolute GPIO pin base.
  	 * On MIPS, we don't have Device Tree and we can't use relative (per chip)
  	 * GPIO numbers.
  	 * On some ARM devices, user space may want to access some system GPIO
  	 * pins directly, which is easier to do with a predictable GPIO base.
057fcd426   Rafał Miłecki   bcma: gpio: use p...
196
  	 */
2d57b7126   Felix Fietkau   bcma: use absolut...
197
198
199
200
201
  	if (IS_BUILTIN(CONFIG_BCM47XX) ||
  	    cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
  		chip->base		= bus->num * BCMA_GPIO_MAX_PINS;
  	else
  		chip->base		= -1;
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
202

78d455a2e   Linus Walleij   bcma: gpio: use g...
203
  	err = gpiochip_add_data(chip, cc);
2997609eb   Rafał Miłecki   bcma: gpio: add o...
204
205
  	if (err)
  		return err;
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
206
  	err = bcma_gpio_irq_init(cc);
2997609eb   Rafał Miłecki   bcma: gpio: add o...
207
  	if (err) {
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
208
  		gpiochip_remove(chip);
2997609eb   Rafał Miłecki   bcma: gpio: add o...
209
210
211
212
  		return err;
  	}
  
  	return 0;
cf0936b06   Hauke Mehrtens   bcma: add GPIO dr...
213
  }
c50ae9470   Hauke Mehrtens   bcma: unregister ...
214
215
216
  
  int bcma_gpio_unregister(struct bcma_drv_cc *cc)
  {
74f4e0cc6   Linus Walleij   bcma: switch GPIO...
217
  	bcma_gpio_irq_exit(cc);
88d5e520a   abdoulaye berthe   driver:gpio remov...
218
219
  	gpiochip_remove(&cc->gpio);
  	return 0;
c50ae9470   Hauke Mehrtens   bcma: unregister ...
220
  }