diff options
Diffstat (limited to 'drivers/mfd/ezx-pcap.c')
-rw-r--r-- | drivers/mfd/ezx-pcap.c | 105 |
1 files changed, 74 insertions, 31 deletions
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index c1de4afa89a6..016be4938e4c 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/irq.h> | 17 | #include <linux/irq.h> |
18 | #include <linux/mfd/ezx-pcap.h> | 18 | #include <linux/mfd/ezx-pcap.h> |
19 | #include <linux/spi/spi.h> | 19 | #include <linux/spi/spi.h> |
20 | #include <linux/gpio.h> | ||
20 | 21 | ||
21 | #define PCAP_ADC_MAXQ 8 | 22 | #define PCAP_ADC_MAXQ 8 |
22 | struct pcap_adc_request { | 23 | struct pcap_adc_request { |
@@ -106,11 +107,35 @@ int ezx_pcap_read(struct pcap_chip *pcap, u8 reg_num, u32 *value) | |||
106 | } | 107 | } |
107 | EXPORT_SYMBOL_GPL(ezx_pcap_read); | 108 | EXPORT_SYMBOL_GPL(ezx_pcap_read); |
108 | 109 | ||
110 | int ezx_pcap_set_bits(struct pcap_chip *pcap, u8 reg_num, u32 mask, u32 val) | ||
111 | { | ||
112 | int ret; | ||
113 | u32 tmp = PCAP_REGISTER_READ_OP_BIT | | ||
114 | (reg_num << PCAP_REGISTER_ADDRESS_SHIFT); | ||
115 | |||
116 | mutex_lock(&pcap->io_mutex); | ||
117 | ret = ezx_pcap_putget(pcap, &tmp); | ||
118 | if (ret) | ||
119 | goto out_unlock; | ||
120 | |||
121 | tmp &= (PCAP_REGISTER_VALUE_MASK & ~mask); | ||
122 | tmp |= (val & mask) | PCAP_REGISTER_WRITE_OP_BIT | | ||
123 | (reg_num << PCAP_REGISTER_ADDRESS_SHIFT); | ||
124 | |||
125 | ret = ezx_pcap_putget(pcap, &tmp); | ||
126 | out_unlock: | ||
127 | mutex_unlock(&pcap->io_mutex); | ||
128 | |||
129 | return ret; | ||
130 | } | ||
131 | EXPORT_SYMBOL_GPL(ezx_pcap_set_bits); | ||
132 | |||
109 | /* IRQ */ | 133 | /* IRQ */ |
110 | static inline unsigned int irq2pcap(struct pcap_chip *pcap, int irq) | 134 | int irq_to_pcap(struct pcap_chip *pcap, int irq) |
111 | { | 135 | { |
112 | return 1 << (irq - pcap->irq_base); | 136 | return irq - pcap->irq_base; |
113 | } | 137 | } |
138 | EXPORT_SYMBOL_GPL(irq_to_pcap); | ||
114 | 139 | ||
115 | int pcap_to_irq(struct pcap_chip *pcap, int irq) | 140 | int pcap_to_irq(struct pcap_chip *pcap, int irq) |
116 | { | 141 | { |
@@ -122,7 +147,7 @@ static void pcap_mask_irq(unsigned int irq) | |||
122 | { | 147 | { |
123 | struct pcap_chip *pcap = get_irq_chip_data(irq); | 148 | struct pcap_chip *pcap = get_irq_chip_data(irq); |
124 | 149 | ||
125 | pcap->msr |= irq2pcap(pcap, irq); | 150 | pcap->msr |= 1 << irq_to_pcap(pcap, irq); |
126 | queue_work(pcap->workqueue, &pcap->msr_work); | 151 | queue_work(pcap->workqueue, &pcap->msr_work); |
127 | } | 152 | } |
128 | 153 | ||
@@ -130,7 +155,7 @@ static void pcap_unmask_irq(unsigned int irq) | |||
130 | { | 155 | { |
131 | struct pcap_chip *pcap = get_irq_chip_data(irq); | 156 | struct pcap_chip *pcap = get_irq_chip_data(irq); |
132 | 157 | ||
133 | pcap->msr &= ~irq2pcap(pcap, irq); | 158 | pcap->msr &= ~(1 << irq_to_pcap(pcap, irq)); |
134 | queue_work(pcap->workqueue, &pcap->msr_work); | 159 | queue_work(pcap->workqueue, &pcap->msr_work); |
135 | } | 160 | } |
136 | 161 | ||
@@ -154,34 +179,38 @@ static void pcap_isr_work(struct work_struct *work) | |||
154 | u32 msr, isr, int_sel, service; | 179 | u32 msr, isr, int_sel, service; |
155 | int irq; | 180 | int irq; |
156 | 181 | ||
157 | ezx_pcap_read(pcap, PCAP_REG_MSR, &msr); | 182 | do { |
158 | ezx_pcap_read(pcap, PCAP_REG_ISR, &isr); | 183 | ezx_pcap_read(pcap, PCAP_REG_MSR, &msr); |
184 | ezx_pcap_read(pcap, PCAP_REG_ISR, &isr); | ||
159 | 185 | ||
160 | /* We cant service/ack irqs that are assigned to port 2 */ | 186 | /* We cant service/ack irqs that are assigned to port 2 */ |
161 | if (!(pdata->config & PCAP_SECOND_PORT)) { | 187 | if (!(pdata->config & PCAP_SECOND_PORT)) { |
162 | ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel); | 188 | ezx_pcap_read(pcap, PCAP_REG_INT_SEL, &int_sel); |
163 | isr &= ~int_sel; | 189 | isr &= ~int_sel; |
164 | } | 190 | } |
165 | ezx_pcap_write(pcap, PCAP_REG_ISR, isr); | ||
166 | 191 | ||
167 | local_irq_disable(); | 192 | ezx_pcap_write(pcap, PCAP_REG_MSR, isr | msr); |
168 | service = isr & ~msr; | 193 | ezx_pcap_write(pcap, PCAP_REG_ISR, isr); |
169 | 194 | ||
170 | for (irq = pcap->irq_base; service; service >>= 1, irq++) { | 195 | local_irq_disable(); |
171 | if (service & 1) { | 196 | service = isr & ~msr; |
172 | struct irq_desc *desc = irq_to_desc(irq); | 197 | for (irq = pcap->irq_base; service; service >>= 1, irq++) { |
198 | if (service & 1) { | ||
199 | struct irq_desc *desc = irq_to_desc(irq); | ||
173 | 200 | ||
174 | if (WARN(!desc, KERN_WARNING | 201 | if (WARN(!desc, KERN_WARNING |
175 | "Invalid PCAP IRQ %d\n", irq)) | 202 | "Invalid PCAP IRQ %d\n", irq)) |
176 | break; | 203 | break; |
177 | 204 | ||
178 | if (desc->status & IRQ_DISABLED) | 205 | if (desc->status & IRQ_DISABLED) |
179 | note_interrupt(irq, desc, IRQ_NONE); | 206 | note_interrupt(irq, desc, IRQ_NONE); |
180 | else | 207 | else |
181 | desc->handle_irq(irq, desc); | 208 | desc->handle_irq(irq, desc); |
209 | } | ||
182 | } | 210 | } |
183 | } | 211 | local_irq_enable(); |
184 | local_irq_enable(); | 212 | ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr); |
213 | } while (gpio_get_value(irq_to_gpio(pcap->spi->irq))); | ||
185 | } | 214 | } |
186 | 215 | ||
187 | static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) | 216 | static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) |
@@ -194,6 +223,19 @@ static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) | |||
194 | } | 223 | } |
195 | 224 | ||
196 | /* ADC */ | 225 | /* ADC */ |
226 | void pcap_set_ts_bits(struct pcap_chip *pcap, u32 bits) | ||
227 | { | ||
228 | u32 tmp; | ||
229 | |||
230 | mutex_lock(&pcap->adc_mutex); | ||
231 | ezx_pcap_read(pcap, PCAP_REG_ADC, &tmp); | ||
232 | tmp &= ~(PCAP_ADC_TS_M_MASK | PCAP_ADC_TS_REF_LOWPWR); | ||
233 | tmp |= bits & (PCAP_ADC_TS_M_MASK | PCAP_ADC_TS_REF_LOWPWR); | ||
234 | ezx_pcap_write(pcap, PCAP_REG_ADC, tmp); | ||
235 | mutex_unlock(&pcap->adc_mutex); | ||
236 | } | ||
237 | EXPORT_SYMBOL_GPL(pcap_set_ts_bits); | ||
238 | |||
197 | static void pcap_disable_adc(struct pcap_chip *pcap) | 239 | static void pcap_disable_adc(struct pcap_chip *pcap) |
198 | { | 240 | { |
199 | u32 tmp; | 241 | u32 tmp; |
@@ -216,15 +258,16 @@ static void pcap_adc_trigger(struct pcap_chip *pcap) | |||
216 | mutex_unlock(&pcap->adc_mutex); | 258 | mutex_unlock(&pcap->adc_mutex); |
217 | return; | 259 | return; |
218 | } | 260 | } |
219 | mutex_unlock(&pcap->adc_mutex); | 261 | /* start conversion on requested bank, save TS_M bits */ |
220 | 262 | ezx_pcap_read(pcap, PCAP_REG_ADC, &tmp); | |
221 | /* start conversion on requested bank */ | 263 | tmp &= (PCAP_ADC_TS_M_MASK | PCAP_ADC_TS_REF_LOWPWR); |
222 | tmp = pcap->adc_queue[head]->flags | PCAP_ADC_ADEN; | 264 | tmp |= pcap->adc_queue[head]->flags | PCAP_ADC_ADEN; |
223 | 265 | ||
224 | if (pcap->adc_queue[head]->bank == PCAP_ADC_BANK_1) | 266 | if (pcap->adc_queue[head]->bank == PCAP_ADC_BANK_1) |
225 | tmp |= PCAP_ADC_AD_SEL1; | 267 | tmp |= PCAP_ADC_AD_SEL1; |
226 | 268 | ||
227 | ezx_pcap_write(pcap, PCAP_REG_ADC, tmp); | 269 | ezx_pcap_write(pcap, PCAP_REG_ADC, tmp); |
270 | mutex_unlock(&pcap->adc_mutex); | ||
228 | ezx_pcap_write(pcap, PCAP_REG_ADR, PCAP_ADR_ASC); | 271 | ezx_pcap_write(pcap, PCAP_REG_ADR, PCAP_ADR_ASC); |
229 | } | 272 | } |
230 | 273 | ||
@@ -499,7 +542,7 @@ static void __exit ezx_pcap_exit(void) | |||
499 | spi_unregister_driver(&ezxpcap_driver); | 542 | spi_unregister_driver(&ezxpcap_driver); |
500 | } | 543 | } |
501 | 544 | ||
502 | module_init(ezx_pcap_init); | 545 | subsys_initcall(ezx_pcap_init); |
503 | module_exit(ezx_pcap_exit); | 546 | module_exit(ezx_pcap_exit); |
504 | 547 | ||
505 | MODULE_LICENSE("GPL"); | 548 | MODULE_LICENSE("GPL"); |