.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Driver for Motorola PCAP2 as present in EZX phones |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2006 Harald Welte <laforge@openezx.org> |
---|
5 | 6 | * Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify |
---|
8 | | - * it under the terms of the GNU General Public License version 2 as |
---|
9 | | - * published by the Free Software Foundation. |
---|
10 | | - * |
---|
11 | 7 | */ |
---|
12 | 8 | |
---|
13 | 9 | #include <linux/module.h> |
---|
.. | .. |
---|
39 | 35 | |
---|
40 | 36 | /* IO */ |
---|
41 | 37 | u32 buf; |
---|
42 | | - struct mutex io_mutex; |
---|
| 38 | + spinlock_t io_lock; |
---|
43 | 39 | |
---|
44 | 40 | /* IRQ */ |
---|
45 | 41 | unsigned int irq_base; |
---|
.. | .. |
---|
52 | 48 | struct pcap_adc_request *adc_queue[PCAP_ADC_MAXQ]; |
---|
53 | 49 | u8 adc_head; |
---|
54 | 50 | u8 adc_tail; |
---|
55 | | - struct mutex adc_mutex; |
---|
| 51 | + spinlock_t adc_lock; |
---|
56 | 52 | }; |
---|
57 | 53 | |
---|
58 | 54 | /* IO */ |
---|
.. | .. |
---|
80 | 76 | |
---|
81 | 77 | int ezx_pcap_write(struct pcap_chip *pcap, u8 reg_num, u32 value) |
---|
82 | 78 | { |
---|
| 79 | + unsigned long flags; |
---|
83 | 80 | int ret; |
---|
84 | 81 | |
---|
85 | | - mutex_lock(&pcap->io_mutex); |
---|
| 82 | + spin_lock_irqsave(&pcap->io_lock, flags); |
---|
86 | 83 | value &= PCAP_REGISTER_VALUE_MASK; |
---|
87 | 84 | value |= PCAP_REGISTER_WRITE_OP_BIT |
---|
88 | 85 | | (reg_num << PCAP_REGISTER_ADDRESS_SHIFT); |
---|
89 | 86 | ret = ezx_pcap_putget(pcap, &value); |
---|
90 | | - mutex_unlock(&pcap->io_mutex); |
---|
| 87 | + spin_unlock_irqrestore(&pcap->io_lock, flags); |
---|
91 | 88 | |
---|
92 | 89 | return ret; |
---|
93 | 90 | } |
---|
.. | .. |
---|
95 | 92 | |
---|
96 | 93 | int ezx_pcap_read(struct pcap_chip *pcap, u8 reg_num, u32 *value) |
---|
97 | 94 | { |
---|
| 95 | + unsigned long flags; |
---|
98 | 96 | int ret; |
---|
99 | 97 | |
---|
100 | | - mutex_lock(&pcap->io_mutex); |
---|
| 98 | + spin_lock_irqsave(&pcap->io_lock, flags); |
---|
101 | 99 | *value = PCAP_REGISTER_READ_OP_BIT |
---|
102 | 100 | | (reg_num << PCAP_REGISTER_ADDRESS_SHIFT); |
---|
103 | 101 | |
---|
104 | 102 | ret = ezx_pcap_putget(pcap, value); |
---|
105 | | - mutex_unlock(&pcap->io_mutex); |
---|
| 103 | + spin_unlock_irqrestore(&pcap->io_lock, flags); |
---|
106 | 104 | |
---|
107 | 105 | return ret; |
---|
108 | 106 | } |
---|
.. | .. |
---|
110 | 108 | |
---|
111 | 109 | int ezx_pcap_set_bits(struct pcap_chip *pcap, u8 reg_num, u32 mask, u32 val) |
---|
112 | 110 | { |
---|
| 111 | + unsigned long flags; |
---|
113 | 112 | int ret; |
---|
114 | 113 | u32 tmp = PCAP_REGISTER_READ_OP_BIT | |
---|
115 | 114 | (reg_num << PCAP_REGISTER_ADDRESS_SHIFT); |
---|
116 | 115 | |
---|
117 | | - mutex_lock(&pcap->io_mutex); |
---|
| 116 | + spin_lock_irqsave(&pcap->io_lock, flags); |
---|
118 | 117 | ret = ezx_pcap_putget(pcap, &tmp); |
---|
119 | 118 | if (ret) |
---|
120 | 119 | goto out_unlock; |
---|
.. | .. |
---|
125 | 124 | |
---|
126 | 125 | ret = ezx_pcap_putget(pcap, &tmp); |
---|
127 | 126 | out_unlock: |
---|
128 | | - mutex_unlock(&pcap->io_mutex); |
---|
| 127 | + spin_unlock_irqrestore(&pcap->io_lock, flags); |
---|
129 | 128 | |
---|
130 | 129 | return ret; |
---|
131 | 130 | } |
---|
.. | .. |
---|
216 | 215 | /* ADC */ |
---|
217 | 216 | void pcap_set_ts_bits(struct pcap_chip *pcap, u32 bits) |
---|
218 | 217 | { |
---|
| 218 | + unsigned long flags; |
---|
219 | 219 | u32 tmp; |
---|
220 | 220 | |
---|
221 | | - mutex_lock(&pcap->adc_mutex); |
---|
| 221 | + spin_lock_irqsave(&pcap->adc_lock, flags); |
---|
222 | 222 | ezx_pcap_read(pcap, PCAP_REG_ADC, &tmp); |
---|
223 | 223 | tmp &= ~(PCAP_ADC_TS_M_MASK | PCAP_ADC_TS_REF_LOWPWR); |
---|
224 | 224 | tmp |= bits & (PCAP_ADC_TS_M_MASK | PCAP_ADC_TS_REF_LOWPWR); |
---|
225 | 225 | ezx_pcap_write(pcap, PCAP_REG_ADC, tmp); |
---|
226 | | - mutex_unlock(&pcap->adc_mutex); |
---|
| 226 | + spin_unlock_irqrestore(&pcap->adc_lock, flags); |
---|
227 | 227 | } |
---|
228 | 228 | EXPORT_SYMBOL_GPL(pcap_set_ts_bits); |
---|
229 | 229 | |
---|
.. | .. |
---|
238 | 238 | |
---|
239 | 239 | static void pcap_adc_trigger(struct pcap_chip *pcap) |
---|
240 | 240 | { |
---|
| 241 | + unsigned long flags; |
---|
241 | 242 | u32 tmp; |
---|
242 | 243 | u8 head; |
---|
243 | 244 | |
---|
244 | | - mutex_lock(&pcap->adc_mutex); |
---|
| 245 | + spin_lock_irqsave(&pcap->adc_lock, flags); |
---|
245 | 246 | head = pcap->adc_head; |
---|
246 | 247 | if (!pcap->adc_queue[head]) { |
---|
247 | 248 | /* queue is empty, save power */ |
---|
248 | 249 | pcap_disable_adc(pcap); |
---|
249 | | - mutex_unlock(&pcap->adc_mutex); |
---|
| 250 | + spin_unlock_irqrestore(&pcap->adc_lock, flags); |
---|
250 | 251 | return; |
---|
251 | 252 | } |
---|
252 | 253 | /* start conversion on requested bank, save TS_M bits */ |
---|
.. | .. |
---|
258 | 259 | tmp |= PCAP_ADC_AD_SEL1; |
---|
259 | 260 | |
---|
260 | 261 | ezx_pcap_write(pcap, PCAP_REG_ADC, tmp); |
---|
261 | | - mutex_unlock(&pcap->adc_mutex); |
---|
| 262 | + spin_unlock_irqrestore(&pcap->adc_lock, flags); |
---|
262 | 263 | ezx_pcap_write(pcap, PCAP_REG_ADR, PCAP_ADR_ASC); |
---|
263 | 264 | } |
---|
264 | 265 | |
---|
.. | .. |
---|
269 | 270 | u16 res[2]; |
---|
270 | 271 | u32 tmp; |
---|
271 | 272 | |
---|
272 | | - mutex_lock(&pcap->adc_mutex); |
---|
| 273 | + spin_lock(&pcap->adc_lock); |
---|
273 | 274 | req = pcap->adc_queue[pcap->adc_head]; |
---|
274 | 275 | |
---|
275 | 276 | if (WARN(!req, "adc irq without pending request\n")) { |
---|
276 | | - mutex_unlock(&pcap->adc_mutex); |
---|
| 277 | + spin_unlock(&pcap->adc_lock); |
---|
277 | 278 | return IRQ_HANDLED; |
---|
278 | 279 | } |
---|
279 | 280 | |
---|
.. | .. |
---|
289 | 290 | |
---|
290 | 291 | pcap->adc_queue[pcap->adc_head] = NULL; |
---|
291 | 292 | pcap->adc_head = (pcap->adc_head + 1) & (PCAP_ADC_MAXQ - 1); |
---|
292 | | - mutex_unlock(&pcap->adc_mutex); |
---|
| 293 | + spin_unlock(&pcap->adc_lock); |
---|
293 | 294 | |
---|
294 | 295 | /* pass the results and release memory */ |
---|
295 | 296 | req->callback(req->data, res); |
---|
.. | .. |
---|
305 | 306 | void *callback, void *data) |
---|
306 | 307 | { |
---|
307 | 308 | struct pcap_adc_request *req; |
---|
| 309 | + unsigned long irq_flags; |
---|
308 | 310 | |
---|
309 | 311 | /* This will be freed after we have a result */ |
---|
310 | 312 | req = kmalloc(sizeof(struct pcap_adc_request), GFP_KERNEL); |
---|
.. | .. |
---|
318 | 320 | req->callback = callback; |
---|
319 | 321 | req->data = data; |
---|
320 | 322 | |
---|
321 | | - mutex_lock(&pcap->adc_mutex); |
---|
| 323 | + spin_lock_irqsave(&pcap->adc_lock, irq_flags); |
---|
322 | 324 | if (pcap->adc_queue[pcap->adc_tail]) { |
---|
323 | | - mutex_unlock(&pcap->adc_mutex); |
---|
| 325 | + spin_unlock_irqrestore(&pcap->adc_lock, irq_flags); |
---|
324 | 326 | kfree(req); |
---|
325 | 327 | return -EBUSY; |
---|
326 | 328 | } |
---|
327 | 329 | pcap->adc_queue[pcap->adc_tail] = req; |
---|
328 | 330 | pcap->adc_tail = (pcap->adc_tail + 1) & (PCAP_ADC_MAXQ - 1); |
---|
329 | | - mutex_unlock(&pcap->adc_mutex); |
---|
| 331 | + spin_unlock_irqrestore(&pcap->adc_lock, irq_flags); |
---|
330 | 332 | |
---|
331 | 333 | /* start conversion */ |
---|
332 | 334 | pcap_adc_trigger(pcap); |
---|
.. | .. |
---|
393 | 395 | static int ezx_pcap_remove(struct spi_device *spi) |
---|
394 | 396 | { |
---|
395 | 397 | struct pcap_chip *pcap = spi_get_drvdata(spi); |
---|
| 398 | + unsigned long flags; |
---|
396 | 399 | int i; |
---|
397 | 400 | |
---|
398 | 401 | /* remove all registered subdevs */ |
---|
399 | 402 | device_for_each_child(&spi->dev, NULL, pcap_remove_subdev); |
---|
400 | 403 | |
---|
401 | 404 | /* cleanup ADC */ |
---|
402 | | - mutex_lock(&pcap->adc_mutex); |
---|
| 405 | + spin_lock_irqsave(&pcap->adc_lock, flags); |
---|
403 | 406 | for (i = 0; i < PCAP_ADC_MAXQ; i++) |
---|
404 | 407 | kfree(pcap->adc_queue[i]); |
---|
405 | | - mutex_unlock(&pcap->adc_mutex); |
---|
| 408 | + spin_unlock_irqrestore(&pcap->adc_lock, flags); |
---|
406 | 409 | |
---|
407 | 410 | /* cleanup irqchip */ |
---|
408 | 411 | for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) |
---|
.. | .. |
---|
430 | 433 | goto ret; |
---|
431 | 434 | } |
---|
432 | 435 | |
---|
433 | | - mutex_init(&pcap->io_mutex); |
---|
434 | | - mutex_init(&pcap->adc_mutex); |
---|
| 436 | + spin_lock_init(&pcap->io_lock); |
---|
| 437 | + spin_lock_init(&pcap->adc_lock); |
---|
435 | 438 | INIT_WORK(&pcap->isr_work, pcap_isr_work); |
---|
436 | 439 | INIT_WORK(&pcap->msr_work, pcap_msr_work); |
---|
437 | 440 | spi_set_drvdata(spi, pcap); |
---|