diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2011-02-05 05:46:32 -0500 |
---|---|---|
committer | Matthew Garrett <mjg@redhat.com> | 2011-02-07 16:52:28 -0500 |
commit | d4b7de612d193e1c8fdeee9902e5a582e746dfe9 (patch) | |
tree | 0248a01267c1e827a5175cabe80c4acda6afee24 | |
parent | cb8e5e6a60cab5a90afd45d49655458c6e1db78c (diff) |
platform-drivers: x86: pmic: Use irq_chip buslock mechanism
The set_type function of the pmic irq chip is a horrible hack. It
schedules work because it cannot access the scu chip from the set_type
function. That breaks the assumption, that the type is set after
set_type has returned.
irq_chips provide buslock functions to avoid the above. Convert the
driver to use the proper model.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Feng Tang <feng.tang@intel.com>
Cc: Matthew Garrett <mjg@redhat.com>
Cc: Alan Cox <alan@linux.intel.com>
Cc: Alek Du <alek.du@intel.com>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
-rw-r--r-- | drivers/platform/x86/intel_pmic_gpio.c | 80 |
1 files changed, 32 insertions, 48 deletions
diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c index 9134d9d07569..df244c83681d 100644 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ b/drivers/platform/x86/intel_pmic_gpio.c | |||
@@ -60,23 +60,18 @@ enum pmic_gpio_register { | |||
60 | #define GPOSW_DOU 0x08 | 60 | #define GPOSW_DOU 0x08 |
61 | #define GPOSW_RDRV 0x30 | 61 | #define GPOSW_RDRV 0x30 |
62 | 62 | ||
63 | #define GPIO_UPDATE_TYPE 0x80000000 | ||
63 | 64 | ||
64 | #define NUM_GPIO 24 | 65 | #define NUM_GPIO 24 |
65 | 66 | ||
66 | struct pmic_gpio_irq { | ||
67 | spinlock_t lock; | ||
68 | u32 trigger[NUM_GPIO]; | ||
69 | u32 dirty; | ||
70 | struct work_struct work; | ||
71 | }; | ||
72 | |||
73 | |||
74 | struct pmic_gpio { | 67 | struct pmic_gpio { |
68 | struct mutex buslock; | ||
75 | struct gpio_chip chip; | 69 | struct gpio_chip chip; |
76 | struct pmic_gpio_irq irqtypes; | ||
77 | void *gpiointr; | 70 | void *gpiointr; |
78 | int irq; | 71 | int irq; |
79 | unsigned irq_base; | 72 | unsigned irq_base; |
73 | unsigned int update_type; | ||
74 | u32 trigger_type; | ||
80 | }; | 75 | }; |
81 | 76 | ||
82 | static void pmic_program_irqtype(int gpio, int type) | 77 | static void pmic_program_irqtype(int gpio, int type) |
@@ -92,37 +87,6 @@ static void pmic_program_irqtype(int gpio, int type) | |||
92 | intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10); | 87 | intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10); |
93 | }; | 88 | }; |
94 | 89 | ||
95 | static void pmic_irqtype_work(struct work_struct *work) | ||
96 | { | ||
97 | struct pmic_gpio_irq *t = | ||
98 | container_of(work, struct pmic_gpio_irq, work); | ||
99 | unsigned long flags; | ||
100 | int i; | ||
101 | u16 type; | ||
102 | |||
103 | spin_lock_irqsave(&t->lock, flags); | ||
104 | /* As we drop the lock, we may need multiple scans if we race the | ||
105 | pmic_irq_type function */ | ||
106 | while (t->dirty) { | ||
107 | /* | ||
108 | * For each pin that has the dirty bit set send an IPC | ||
109 | * message to configure the hardware via the PMIC | ||
110 | */ | ||
111 | for (i = 0; i < NUM_GPIO; i++) { | ||
112 | if (!(t->dirty & (1 << i))) | ||
113 | continue; | ||
114 | t->dirty &= ~(1 << i); | ||
115 | /* We can't trust the array entry or dirty | ||
116 | once the lock is dropped */ | ||
117 | type = t->trigger[i]; | ||
118 | spin_unlock_irqrestore(&t->lock, flags); | ||
119 | pmic_program_irqtype(i, type); | ||
120 | spin_lock_irqsave(&t->lock, flags); | ||
121 | } | ||
122 | } | ||
123 | spin_unlock_irqrestore(&t->lock, flags); | ||
124 | } | ||
125 | |||
126 | static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | 90 | static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) |
127 | { | 91 | { |
128 | if (offset > 8) { | 92 | if (offset > 8) { |
@@ -190,20 +154,21 @@ static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |||
190 | 1 << (offset - 16)); | 154 | 1 << (offset - 16)); |
191 | } | 155 | } |
192 | 156 | ||
157 | /* | ||
158 | * This is called from genirq with pg->buslock locked and | ||
159 | * irq_desc->lock held. We can not access the scu bus here, so we | ||
160 | * store the change and update in the bus_sync_unlock() function below | ||
161 | */ | ||
193 | static int pmic_irq_type(struct irq_data *data, unsigned type) | 162 | static int pmic_irq_type(struct irq_data *data, unsigned type) |
194 | { | 163 | { |
195 | struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); | 164 | struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); |
196 | u32 gpio = data->irq - pg->irq_base; | 165 | u32 gpio = data->irq - pg->irq_base; |
197 | unsigned long flags; | ||
198 | 166 | ||
199 | if (gpio >= pg->chip.ngpio) | 167 | if (gpio >= pg->chip.ngpio) |
200 | return -EINVAL; | 168 | return -EINVAL; |
201 | 169 | ||
202 | spin_lock_irqsave(&pg->irqtypes.lock, flags); | 170 | pg->trigger_type = type; |
203 | pg->irqtypes.trigger[gpio] = type; | 171 | pg->update_type = gpio | GPIO_UPDATE_TYPE; |
204 | pg->irqtypes.dirty |= (1 << gpio); | ||
205 | spin_unlock_irqrestore(&pg->irqtypes.lock, flags); | ||
206 | schedule_work(&pg->irqtypes.work); | ||
207 | return 0; | 172 | return 0; |
208 | } | 173 | } |
209 | 174 | ||
@@ -214,6 +179,26 @@ static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | |||
214 | return pg->irq_base + offset; | 179 | return pg->irq_base + offset; |
215 | } | 180 | } |
216 | 181 | ||
182 | static void pmic_bus_lock(struct irq_data *data) | ||
183 | { | ||
184 | struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); | ||
185 | |||
186 | mutex_lock(&pg->buslock); | ||
187 | } | ||
188 | |||
189 | static void pmic_bus_sync_unlock(struct irq_data *data) | ||
190 | { | ||
191 | struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); | ||
192 | |||
193 | if (pg->update_type) { | ||
194 | unsigned int gpio = pg->update_type & ~GPIO_UPDATE_TYPE; | ||
195 | |||
196 | pmic_program_irqtype(gpio, pg->trigger_type); | ||
197 | pg->update_type = 0; | ||
198 | } | ||
199 | mutex_unlock(&pg->buslock); | ||
200 | } | ||
201 | |||
217 | /* the gpiointr register is read-clear, so just do nothing. */ | 202 | /* the gpiointr register is read-clear, so just do nothing. */ |
218 | static void pmic_irq_unmask(struct irq_data *data) { } | 203 | static void pmic_irq_unmask(struct irq_data *data) { } |
219 | 204 | ||
@@ -287,8 +272,7 @@ static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev) | |||
287 | pg->chip.can_sleep = 1; | 272 | pg->chip.can_sleep = 1; |
288 | pg->chip.dev = dev; | 273 | pg->chip.dev = dev; |
289 | 274 | ||
290 | INIT_WORK(&pg->irqtypes.work, pmic_irqtype_work); | 275 | mutex_init(&pg->buslock); |
291 | spin_lock_init(&pg->irqtypes.lock); | ||
292 | 276 | ||
293 | pg->chip.dev = dev; | 277 | pg->chip.dev = dev; |
294 | retval = gpiochip_add(&pg->chip); | 278 | retval = gpiochip_add(&pg->chip); |