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); |
