aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pinctrl
diff options
context:
space:
mode:
authorTomasz Figa <t.figa@samsung.com>2012-10-11 04:11:16 -0400
committerLinus Walleij <linus.walleij@linaro.org>2012-10-15 03:10:12 -0400
commit595be7268a85735d229451821b56f122d09d7bdc (patch)
treeeefa13ddc638a1fc5e987dee179ac951aea7b90b /drivers/pinctrl
parent1b6056d6db2426cd612f03dabacf655ecb6a27ae (diff)
pinctrl: exynos: Use one IRQ domain per pin bank
Instead of registering one IRQ domain for all pin banks of a pin controller, this patch implements registration of per-bank domains. At a cost of a little memory overhead (~2.5KiB for all GPIO interrupts of Exynos4x12) it simplifies driver code and device tree sources, because GPIO interrupts can be now specified per banks. Example: device { /* ... */ interrupt-parent = <&gpa1>; interrupts = <3 0>; /* ... */ }; Signed-off-by: Tomasz Figa <t.figa@samsung.com> Reviewed-by: Kyungmin Park <kyungmin.park@samsung.com> Acked-by: Thomas Abraham <thomas.abraham@linaro.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/pinctrl')
-rw-r--r--drivers/pinctrl/pinctrl-exynos.c117
-rw-r--r--drivers/pinctrl/pinctrl-exynos.h12
-rw-r--r--drivers/pinctrl/pinctrl-samsung.c4
-rw-r--r--drivers/pinctrl/pinctrl-samsung.h7
4 files changed, 35 insertions, 105 deletions
diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c
index bd9f1307a793..be757b1d4fcd 100644
--- a/drivers/pinctrl/pinctrl-exynos.c
+++ b/drivers/pinctrl/pinctrl-exynos.c
@@ -40,46 +40,46 @@ static const struct of_device_id exynos_wkup_irq_ids[] = {
40 40
41static void exynos_gpio_irq_unmask(struct irq_data *irqd) 41static void exynos_gpio_irq_unmask(struct irq_data *irqd)
42{ 42{
43 struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; 43 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
44 struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); 44 struct samsung_pinctrl_drv_data *d = bank->drvdata;
45 unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; 45 unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset;
46 unsigned long mask; 46 unsigned long mask;
47 47
48 mask = readl(d->virt_base + reg_mask); 48 mask = readl(d->virt_base + reg_mask);
49 mask &= ~(1 << edata->pin); 49 mask &= ~(1 << irqd->hwirq);
50 writel(mask, d->virt_base + reg_mask); 50 writel(mask, d->virt_base + reg_mask);
51} 51}
52 52
53static void exynos_gpio_irq_mask(struct irq_data *irqd) 53static void exynos_gpio_irq_mask(struct irq_data *irqd)
54{ 54{
55 struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; 55 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
56 struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); 56 struct samsung_pinctrl_drv_data *d = bank->drvdata;
57 unsigned long reg_mask = d->ctrl->geint_mask + edata->eint_offset; 57 unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset;
58 unsigned long mask; 58 unsigned long mask;
59 59
60 mask = readl(d->virt_base + reg_mask); 60 mask = readl(d->virt_base + reg_mask);
61 mask |= 1 << edata->pin; 61 mask |= 1 << irqd->hwirq;
62 writel(mask, d->virt_base + reg_mask); 62 writel(mask, d->virt_base + reg_mask);
63} 63}
64 64
65static void exynos_gpio_irq_ack(struct irq_data *irqd) 65static void exynos_gpio_irq_ack(struct irq_data *irqd)
66{ 66{
67 struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; 67 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
68 struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); 68 struct samsung_pinctrl_drv_data *d = bank->drvdata;
69 unsigned long reg_pend = d->ctrl->geint_pend + edata->eint_offset; 69 unsigned long reg_pend = d->ctrl->geint_pend + bank->eint_offset;
70 70
71 writel(1 << edata->pin, d->virt_base + reg_pend); 71 writel(1 << irqd->hwirq, d->virt_base + reg_pend);
72} 72}
73 73
74static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) 74static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
75{ 75{
76 struct samsung_pinctrl_drv_data *d = irqd->domain->host_data; 76 struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
77 struct samsung_pinctrl_drv_data *d = bank->drvdata;
77 struct samsung_pin_ctrl *ctrl = d->ctrl; 78 struct samsung_pin_ctrl *ctrl = d->ctrl;
78 struct exynos_geint_data *edata = irq_data_get_irq_handler_data(irqd); 79 unsigned int pin = irqd->hwirq;
79 struct samsung_pin_bank *bank = edata->bank; 80 unsigned int shift = EXYNOS_EINT_CON_LEN * pin;
80 unsigned int shift = EXYNOS_EINT_CON_LEN * edata->pin;
81 unsigned int con, trig_type; 81 unsigned int con, trig_type;
82 unsigned long reg_con = ctrl->geint_con + edata->eint_offset; 82 unsigned long reg_con = ctrl->geint_con + bank->eint_offset;
83 unsigned int mask; 83 unsigned int mask;
84 84
85 switch (type) { 85 switch (type) {
@@ -114,7 +114,7 @@ static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
114 writel(con, d->virt_base + reg_con); 114 writel(con, d->virt_base + reg_con);
115 115
116 reg_con = bank->pctl_offset; 116 reg_con = bank->pctl_offset;
117 shift = edata->pin * bank->func_width; 117 shift = pin * bank->func_width;
118 mask = (1 << bank->func_width) - 1; 118 mask = (1 << bank->func_width) - 1;
119 119
120 con = readl(d->virt_base + reg_con); 120 con = readl(d->virt_base + reg_con);
@@ -136,81 +136,23 @@ static struct irq_chip exynos_gpio_irq_chip = {
136 .irq_set_type = exynos_gpio_irq_set_type, 136 .irq_set_type = exynos_gpio_irq_set_type,
137}; 137};
138 138
139/*
140 * given a controller-local external gpio interrupt number, prepare the handler
141 * data for it.
142 */
143static struct exynos_geint_data *exynos_get_eint_data(irq_hw_number_t hw,
144 struct samsung_pinctrl_drv_data *d)
145{
146 struct samsung_pin_bank *bank = d->ctrl->pin_banks;
147 struct exynos_geint_data *eint_data;
148 unsigned int nr_banks = d->ctrl->nr_banks, idx;
149 unsigned int irq_base = 0;
150
151 if (hw >= d->ctrl->nr_gint) {
152 dev_err(d->dev, "unsupported ext-gpio interrupt\n");
153 return NULL;
154 }
155
156 for (idx = 0; idx < nr_banks; idx++, bank++) {
157 if (bank->eint_type != EINT_TYPE_GPIO)
158 continue;
159 if ((hw >= irq_base) && (hw < (irq_base + bank->nr_pins)))
160 break;
161 irq_base += bank->nr_pins;
162 }
163
164 if (idx == nr_banks) {
165 dev_err(d->dev, "pin bank not found for ext-gpio interrupt\n");
166 return NULL;
167 }
168
169 eint_data = devm_kzalloc(d->dev, sizeof(*eint_data), GFP_KERNEL);
170 if (!eint_data) {
171 dev_err(d->dev, "no memory for eint-gpio data\n");
172 return NULL;
173 }
174
175 eint_data->bank = bank;
176 eint_data->pin = hw - irq_base;
177 eint_data->eint_offset = bank->eint_offset;
178 return eint_data;
179}
180
181static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq, 139static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq,
182 irq_hw_number_t hw) 140 irq_hw_number_t hw)
183{ 141{
184 struct samsung_pinctrl_drv_data *d = h->host_data; 142 struct samsung_pin_bank *b = h->host_data;
185 struct exynos_geint_data *eint_data;
186
187 eint_data = exynos_get_eint_data(hw, d);
188 if (!eint_data)
189 return -EINVAL;
190 143
191 irq_set_handler_data(virq, eint_data); 144 irq_set_chip_data(virq, b);
192 irq_set_chip_data(virq, h->host_data);
193 irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip, 145 irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip,
194 handle_level_irq); 146 handle_level_irq);
195 set_irq_flags(virq, IRQF_VALID); 147 set_irq_flags(virq, IRQF_VALID);
196 return 0; 148 return 0;
197} 149}
198 150
199static void exynos_gpio_irq_unmap(struct irq_domain *h, unsigned int virq)
200{
201 struct samsung_pinctrl_drv_data *d = h->host_data;
202 struct exynos_geint_data *eint_data;
203
204 eint_data = irq_get_handler_data(virq);
205 devm_kfree(d->dev, eint_data);
206}
207
208/* 151/*
209 * irq domain callbacks for external gpio interrupt controller. 152 * irq domain callbacks for external gpio interrupt controller.
210 */ 153 */
211static const struct irq_domain_ops exynos_gpio_irqd_ops = { 154static const struct irq_domain_ops exynos_gpio_irqd_ops = {
212 .map = exynos_gpio_irq_map, 155 .map = exynos_gpio_irq_map,
213 .unmap = exynos_gpio_irq_unmap,
214 .xlate = irq_domain_xlate_twocell, 156 .xlate = irq_domain_xlate_twocell,
215}; 157};
216 158
@@ -229,7 +171,7 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
229 return IRQ_HANDLED; 171 return IRQ_HANDLED;
230 bank += (group - 1); 172 bank += (group - 1);
231 173
232 virq = irq_linear_revmap(d->gpio_irqd, bank->irq_base + pin); 174 virq = irq_linear_revmap(bank->irq_domain, pin);
233 if (!virq) 175 if (!virq)
234 return IRQ_NONE; 176 return IRQ_NONE;
235 generic_handle_irq(virq); 177 generic_handle_irq(virq);
@@ -242,8 +184,10 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
242 */ 184 */
243static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) 185static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
244{ 186{
187 struct samsung_pin_bank *bank;
245 struct device *dev = d->dev; 188 struct device *dev = d->dev;
246 unsigned int ret; 189 unsigned int ret;
190 unsigned int i;
247 191
248 if (!d->irq) { 192 if (!d->irq) {
249 dev_err(dev, "irq number not available\n"); 193 dev_err(dev, "irq number not available\n");
@@ -257,11 +201,16 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
257 return -ENXIO; 201 return -ENXIO;
258 } 202 }
259 203
260 d->gpio_irqd = irq_domain_add_linear(dev->of_node, d->ctrl->nr_gint, 204 bank = d->ctrl->pin_banks;
261 &exynos_gpio_irqd_ops, d); 205 for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
262 if (!d->gpio_irqd) { 206 if (bank->eint_type != EINT_TYPE_GPIO)
263 dev_err(dev, "gpio irq domain allocation failed\n"); 207 continue;
264 return -ENXIO; 208 bank->irq_domain = irq_domain_add_linear(bank->of_node,
209 bank->nr_pins, &exynos_gpio_irqd_ops, bank);
210 if (!bank->irq_domain) {
211 dev_err(dev, "gpio irq domain add failed\n");
212 return -ENXIO;
213 }
265 } 214 }
266 215
267 return 0; 216 return 0;
diff --git a/drivers/pinctrl/pinctrl-exynos.h b/drivers/pinctrl/pinctrl-exynos.h
index 5d8e380fbadf..f05efa074658 100644
--- a/drivers/pinctrl/pinctrl-exynos.h
+++ b/drivers/pinctrl/pinctrl-exynos.h
@@ -74,18 +74,6 @@
74 } 74 }
75 75
76/** 76/**
77 * struct exynos_geint_data: gpio eint specific data for irq_chip callbacks.
78 * @bank: pin bank from which this gpio interrupt originates.
79 * @pin: pin number within the bank.
80 * @eint_offset: offset to be added to the con/pend/mask register bank base.
81 */
82struct exynos_geint_data {
83 struct samsung_pin_bank *bank;
84 u32 pin;
85 u32 eint_offset;
86};
87
88/**
89 * struct exynos_weint_data: irq specific data for all the wakeup interrupts 77 * struct exynos_weint_data: irq specific data for all the wakeup interrupts
90 * generated by the external wakeup interrupt controller. 78 * generated by the external wakeup interrupt controller.
91 * @domain: irq domain representing the external wakeup interrupts 79 * @domain: irq domain representing the external wakeup interrupts
diff --git a/drivers/pinctrl/pinctrl-samsung.c b/drivers/pinctrl/pinctrl-samsung.c
index 53493c3c35ff..e1ef5d28094d 100644
--- a/drivers/pinctrl/pinctrl-samsung.c
+++ b/drivers/pinctrl/pinctrl-samsung.c
@@ -813,10 +813,6 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
813 bank->drvdata = d; 813 bank->drvdata = d;
814 bank->pin_base = ctrl->nr_pins; 814 bank->pin_base = ctrl->nr_pins;
815 ctrl->nr_pins += bank->nr_pins; 815 ctrl->nr_pins += bank->nr_pins;
816 if (bank->eint_type == EINT_TYPE_GPIO) {
817 bank->irq_base = ctrl->nr_gint;
818 ctrl->nr_gint += bank->nr_pins;
819 }
820 } 816 }
821 817
822 for_each_child_of_node(node, np) { 818 for_each_child_of_node(node, np) {
diff --git a/drivers/pinctrl/pinctrl-samsung.h b/drivers/pinctrl/pinctrl-samsung.h
index d77d9bcc5d7d..e56be22302cd 100644
--- a/drivers/pinctrl/pinctrl-samsung.h
+++ b/drivers/pinctrl/pinctrl-samsung.h
@@ -109,10 +109,10 @@ struct samsung_pinctrl_drv_data;
109 * @conpdn_width: width of the sleep mode function selector bin field. 109 * @conpdn_width: width of the sleep mode function selector bin field.
110 * @pudpdn_width: width of the sleep mode pull up/down selector bit field. 110 * @pudpdn_width: width of the sleep mode pull up/down selector bit field.
111 * @eint_type: type of the external interrupt supported by the bank. 111 * @eint_type: type of the external interrupt supported by the bank.
112 * @irq_base: starting controller local irq number of the bank.
113 * @name: name to be prefixed for each pin in this pin bank. 112 * @name: name to be prefixed for each pin in this pin bank.
114 * @of_node: OF node of the bank. 113 * @of_node: OF node of the bank.
115 * @drvdata: link to controller driver data 114 * @drvdata: link to controller driver data
115 * @irq_domain: IRQ domain of the bank.
116 */ 116 */
117struct samsung_pin_bank { 117struct samsung_pin_bank {
118 u32 pctl_offset; 118 u32 pctl_offset;
@@ -125,10 +125,10 @@ struct samsung_pin_bank {
125 u8 pudpdn_width; 125 u8 pudpdn_width;
126 enum eint_type eint_type; 126 enum eint_type eint_type;
127 u32 eint_offset; 127 u32 eint_offset;
128 u32 irq_base;
129 char *name; 128 char *name;
130 struct device_node *of_node; 129 struct device_node *of_node;
131 struct samsung_pinctrl_drv_data *drvdata; 130 struct samsung_pinctrl_drv_data *drvdata;
131 struct irq_domain *irq_domain;
132}; 132};
133 133
134/** 134/**
@@ -137,7 +137,6 @@ struct samsung_pin_bank {
137 * @nr_banks: number of pin banks. 137 * @nr_banks: number of pin banks.
138 * @base: starting system wide pin number. 138 * @base: starting system wide pin number.
139 * @nr_pins: number of pins supported by the controller. 139 * @nr_pins: number of pins supported by the controller.
140 * @nr_gint: number of external gpio interrupts supported.
141 * @nr_wint: number of external wakeup interrupts supported. 140 * @nr_wint: number of external wakeup interrupts supported.
142 * @geint_con: offset of the ext-gpio controller registers. 141 * @geint_con: offset of the ext-gpio controller registers.
143 * @geint_mask: offset of the ext-gpio interrupt mask registers. 142 * @geint_mask: offset of the ext-gpio interrupt mask registers.
@@ -158,7 +157,6 @@ struct samsung_pin_ctrl {
158 157
159 u32 base; 158 u32 base;
160 u32 nr_pins; 159 u32 nr_pins;
161 u32 nr_gint;
162 u32 nr_wint; 160 u32 nr_wint;
163 161
164 u32 geint_con; 162 u32 geint_con;
@@ -205,7 +203,6 @@ struct samsung_pinctrl_drv_data {
205 const struct samsung_pmx_func *pmx_functions; 203 const struct samsung_pmx_func *pmx_functions;
206 unsigned int nr_functions; 204 unsigned int nr_functions;
207 205
208 struct irq_domain *gpio_irqd;
209 struct irq_domain *wkup_irqd; 206 struct irq_domain *wkup_irqd;
210 207
211 struct gpio_chip *gc; 208 struct gpio_chip *gc;