Commit | Line | Data |
---|---|---|
39ae93e3 KH |
1 | /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. |
2 | * | |
3 | * This program is free software; you can redistribute it and/or modify | |
4 | * it under the terms of the GNU General Public License version 2 and | |
5 | * only version 2 as published by the Free Software Foundation. | |
6 | * | |
7 | * This program is distributed in the hope that it will be useful, | |
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | * GNU General Public License for more details. | |
11 | */ | |
12 | #include <linux/delay.h> | |
13 | #include <linux/err.h> | |
14 | #include <linux/interrupt.h> | |
15 | #include <linux/io.h> | |
67b563f1 JC |
16 | #include <linux/irqchip/chained_irq.h> |
17 | #include <linux/irqdomain.h> | |
18 | #include <linux/irq.h> | |
39ae93e3 KH |
19 | #include <linux/kernel.h> |
20 | #include <linux/module.h> | |
21 | #include <linux/of.h> | |
22 | #include <linux/platform_device.h> | |
23 | #include <linux/slab.h> | |
24 | #include <linux/spmi.h> | |
25 | ||
26 | /* PMIC Arbiter configuration registers */ | |
27 | #define PMIC_ARB_VERSION 0x0000 | |
28 | #define PMIC_ARB_INT_EN 0x0004 | |
29 | ||
30 | /* PMIC Arbiter channel registers */ | |
31 | #define PMIC_ARB_CMD(N) (0x0800 + (0x80 * (N))) | |
32 | #define PMIC_ARB_CONFIG(N) (0x0804 + (0x80 * (N))) | |
33 | #define PMIC_ARB_STATUS(N) (0x0808 + (0x80 * (N))) | |
34 | #define PMIC_ARB_WDATA0(N) (0x0810 + (0x80 * (N))) | |
35 | #define PMIC_ARB_WDATA1(N) (0x0814 + (0x80 * (N))) | |
36 | #define PMIC_ARB_RDATA0(N) (0x0818 + (0x80 * (N))) | |
37 | #define PMIC_ARB_RDATA1(N) (0x081C + (0x80 * (N))) | |
38 | ||
39 | /* Interrupt Controller */ | |
40 | #define SPMI_PIC_OWNER_ACC_STATUS(M, N) (0x0000 + ((32 * (M)) + (4 * (N)))) | |
41 | #define SPMI_PIC_ACC_ENABLE(N) (0x0200 + (4 * (N))) | |
42 | #define SPMI_PIC_IRQ_STATUS(N) (0x0600 + (4 * (N))) | |
43 | #define SPMI_PIC_IRQ_CLEAR(N) (0x0A00 + (4 * (N))) | |
44 | ||
45 | /* Mapping Table */ | |
46 | #define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N))) | |
47 | #define SPMI_MAPPING_BIT_INDEX(X) (((X) >> 18) & 0xF) | |
48 | #define SPMI_MAPPING_BIT_IS_0_FLAG(X) (((X) >> 17) & 0x1) | |
49 | #define SPMI_MAPPING_BIT_IS_0_RESULT(X) (((X) >> 9) & 0xFF) | |
50 | #define SPMI_MAPPING_BIT_IS_1_FLAG(X) (((X) >> 8) & 0x1) | |
51 | #define SPMI_MAPPING_BIT_IS_1_RESULT(X) (((X) >> 0) & 0xFF) | |
52 | ||
53 | #define SPMI_MAPPING_TABLE_LEN 255 | |
54 | #define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ | |
55 | ||
56 | /* Ownership Table */ | |
57 | #define SPMI_OWNERSHIP_TABLE_REG(N) (0x0700 + (4 * (N))) | |
58 | #define SPMI_OWNERSHIP_PERIPH2OWNER(X) ((X) & 0x7) | |
59 | ||
60 | /* Channel Status fields */ | |
61 | enum pmic_arb_chnl_status { | |
62 | PMIC_ARB_STATUS_DONE = (1 << 0), | |
63 | PMIC_ARB_STATUS_FAILURE = (1 << 1), | |
64 | PMIC_ARB_STATUS_DENIED = (1 << 2), | |
65 | PMIC_ARB_STATUS_DROPPED = (1 << 3), | |
66 | }; | |
67 | ||
68 | /* Command register fields */ | |
69 | #define PMIC_ARB_CMD_MAX_BYTE_COUNT 8 | |
70 | ||
71 | /* Command Opcodes */ | |
72 | enum pmic_arb_cmd_op_code { | |
73 | PMIC_ARB_OP_EXT_WRITEL = 0, | |
74 | PMIC_ARB_OP_EXT_READL = 1, | |
75 | PMIC_ARB_OP_EXT_WRITE = 2, | |
76 | PMIC_ARB_OP_RESET = 3, | |
77 | PMIC_ARB_OP_SLEEP = 4, | |
78 | PMIC_ARB_OP_SHUTDOWN = 5, | |
79 | PMIC_ARB_OP_WAKEUP = 6, | |
80 | PMIC_ARB_OP_AUTHENTICATE = 7, | |
81 | PMIC_ARB_OP_MSTR_READ = 8, | |
82 | PMIC_ARB_OP_MSTR_WRITE = 9, | |
83 | PMIC_ARB_OP_EXT_READ = 13, | |
84 | PMIC_ARB_OP_WRITE = 14, | |
85 | PMIC_ARB_OP_READ = 15, | |
86 | PMIC_ARB_OP_ZERO_WRITE = 16, | |
87 | }; | |
88 | ||
89 | /* Maximum number of support PMIC peripherals */ | |
90 | #define PMIC_ARB_MAX_PERIPHS 256 | |
91 | #define PMIC_ARB_PERIPH_ID_VALID (1 << 15) | |
92 | #define PMIC_ARB_TIMEOUT_US 100 | |
93 | #define PMIC_ARB_MAX_TRANS_BYTES (8) | |
94 | ||
95 | #define PMIC_ARB_APID_MASK 0xFF | |
96 | #define PMIC_ARB_PPID_MASK 0xFFF | |
97 | ||
98 | /* interrupt enable bit */ | |
99 | #define SPMI_PIC_ACC_ENABLE_BIT BIT(0) | |
100 | ||
101 | /** | |
102 | * spmi_pmic_arb_dev - SPMI PMIC Arbiter object | |
103 | * | |
104 | * @base: address of the PMIC Arbiter core registers. | |
105 | * @intr: address of the SPMI interrupt control registers. | |
106 | * @cnfg: address of the PMIC Arbiter configuration registers. | |
107 | * @lock: lock to synchronize accesses. | |
108 | * @channel: which channel to use for accesses. | |
67b563f1 JC |
109 | * @irq: PMIC ARB interrupt. |
110 | * @ee: the current Execution Environment | |
111 | * @min_apid: minimum APID (used for bounding IRQ search) | |
112 | * @max_apid: maximum APID | |
113 | * @mapping_table: in-memory copy of PPID -> APID mapping table. | |
114 | * @domain: irq domain object for PMIC IRQ domain | |
115 | * @spmic: SPMI controller object | |
116 | * @apid_to_ppid: cached mapping from APID to PPID | |
39ae93e3 KH |
117 | */ |
118 | struct spmi_pmic_arb_dev { | |
119 | void __iomem *base; | |
120 | void __iomem *intr; | |
121 | void __iomem *cnfg; | |
122 | raw_spinlock_t lock; | |
123 | u8 channel; | |
67b563f1 JC |
124 | int irq; |
125 | u8 ee; | |
126 | u8 min_apid; | |
127 | u8 max_apid; | |
128 | u32 mapping_table[SPMI_MAPPING_TABLE_LEN]; | |
129 | struct irq_domain *domain; | |
130 | struct spmi_controller *spmic; | |
131 | u16 apid_to_ppid[256]; | |
39ae93e3 KH |
132 | }; |
133 | ||
134 | static inline u32 pmic_arb_base_read(struct spmi_pmic_arb_dev *dev, u32 offset) | |
135 | { | |
136 | return readl_relaxed(dev->base + offset); | |
137 | } | |
138 | ||
139 | static inline void pmic_arb_base_write(struct spmi_pmic_arb_dev *dev, | |
140 | u32 offset, u32 val) | |
141 | { | |
142 | writel_relaxed(val, dev->base + offset); | |
143 | } | |
144 | ||
145 | /** | |
146 | * pa_read_data: reads pmic-arb's register and copy 1..4 bytes to buf | |
147 | * @bc: byte count -1. range: 0..3 | |
148 | * @reg: register's address | |
149 | * @buf: output parameter, length must be bc + 1 | |
150 | */ | |
151 | static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc) | |
152 | { | |
153 | u32 data = pmic_arb_base_read(dev, reg); | |
154 | memcpy(buf, &data, (bc & 3) + 1); | |
155 | } | |
156 | ||
157 | /** | |
158 | * pa_write_data: write 1..4 bytes from buf to pmic-arb's register | |
159 | * @bc: byte-count -1. range: 0..3. | |
160 | * @reg: register's address. | |
161 | * @buf: buffer to write. length must be bc + 1. | |
162 | */ | |
163 | static void | |
164 | pa_write_data(struct spmi_pmic_arb_dev *dev, const u8 *buf, u32 reg, u8 bc) | |
165 | { | |
166 | u32 data = 0; | |
167 | memcpy(&data, buf, (bc & 3) + 1); | |
168 | pmic_arb_base_write(dev, reg, data); | |
169 | } | |
170 | ||
171 | static int pmic_arb_wait_for_done(struct spmi_controller *ctrl) | |
172 | { | |
173 | struct spmi_pmic_arb_dev *dev = spmi_controller_get_drvdata(ctrl); | |
174 | u32 status = 0; | |
175 | u32 timeout = PMIC_ARB_TIMEOUT_US; | |
176 | u32 offset = PMIC_ARB_STATUS(dev->channel); | |
177 | ||
178 | while (timeout--) { | |
179 | status = pmic_arb_base_read(dev, offset); | |
180 | ||
181 | if (status & PMIC_ARB_STATUS_DONE) { | |
182 | if (status & PMIC_ARB_STATUS_DENIED) { | |
183 | dev_err(&ctrl->dev, | |
184 | "%s: transaction denied (0x%x)\n", | |
185 | __func__, status); | |
186 | return -EPERM; | |
187 | } | |
188 | ||
189 | if (status & PMIC_ARB_STATUS_FAILURE) { | |
190 | dev_err(&ctrl->dev, | |
191 | "%s: transaction failed (0x%x)\n", | |
192 | __func__, status); | |
193 | return -EIO; | |
194 | } | |
195 | ||
196 | if (status & PMIC_ARB_STATUS_DROPPED) { | |
197 | dev_err(&ctrl->dev, | |
198 | "%s: transaction dropped (0x%x)\n", | |
199 | __func__, status); | |
200 | return -EIO; | |
201 | } | |
202 | ||
203 | return 0; | |
204 | } | |
205 | udelay(1); | |
206 | } | |
207 | ||
208 | dev_err(&ctrl->dev, | |
209 | "%s: timeout, status 0x%x\n", | |
210 | __func__, status); | |
211 | return -ETIMEDOUT; | |
212 | } | |
213 | ||
214 | /* Non-data command */ | |
215 | static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid) | |
216 | { | |
217 | struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl); | |
218 | unsigned long flags; | |
219 | u32 cmd; | |
220 | int rc; | |
221 | ||
222 | /* Check for valid non-data command */ | |
223 | if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP) | |
224 | return -EINVAL; | |
225 | ||
226 | cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20); | |
227 | ||
228 | raw_spin_lock_irqsave(&pmic_arb->lock, flags); | |
229 | pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd); | |
230 | rc = pmic_arb_wait_for_done(ctrl); | |
231 | raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); | |
232 | ||
233 | return rc; | |
234 | } | |
235 | ||
236 | static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, | |
237 | u16 addr, u8 *buf, size_t len) | |
238 | { | |
239 | struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl); | |
240 | unsigned long flags; | |
241 | u8 bc = len - 1; | |
242 | u32 cmd; | |
243 | int rc; | |
244 | ||
245 | if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { | |
246 | dev_err(&ctrl->dev, | |
247 | "pmic-arb supports 1..%d bytes per trans, but %d requested", | |
248 | PMIC_ARB_MAX_TRANS_BYTES, len); | |
249 | return -EINVAL; | |
250 | } | |
251 | ||
252 | /* Check the opcode */ | |
253 | if (opc >= 0x60 && opc <= 0x7F) | |
254 | opc = PMIC_ARB_OP_READ; | |
255 | else if (opc >= 0x20 && opc <= 0x2F) | |
256 | opc = PMIC_ARB_OP_EXT_READ; | |
257 | else if (opc >= 0x38 && opc <= 0x3F) | |
258 | opc = PMIC_ARB_OP_EXT_READL; | |
259 | else | |
260 | return -EINVAL; | |
261 | ||
262 | cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7); | |
263 | ||
264 | raw_spin_lock_irqsave(&pmic_arb->lock, flags); | |
265 | pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd); | |
266 | rc = pmic_arb_wait_for_done(ctrl); | |
267 | if (rc) | |
268 | goto done; | |
269 | ||
270 | pa_read_data(pmic_arb, buf, PMIC_ARB_RDATA0(pmic_arb->channel), | |
271 | min_t(u8, bc, 3)); | |
272 | ||
273 | if (bc > 3) | |
274 | pa_read_data(pmic_arb, buf + 4, | |
275 | PMIC_ARB_RDATA1(pmic_arb->channel), bc - 4); | |
276 | ||
277 | done: | |
278 | raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); | |
279 | return rc; | |
280 | } | |
281 | ||
282 | static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, | |
283 | u16 addr, const u8 *buf, size_t len) | |
284 | { | |
285 | struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl); | |
286 | unsigned long flags; | |
287 | u8 bc = len - 1; | |
288 | u32 cmd; | |
289 | int rc; | |
290 | ||
291 | if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { | |
292 | dev_err(&ctrl->dev, | |
293 | "pmic-arb supports 1..%d bytes per trans, but:%d requested", | |
294 | PMIC_ARB_MAX_TRANS_BYTES, len); | |
295 | return -EINVAL; | |
296 | } | |
297 | ||
298 | /* Check the opcode */ | |
299 | if (opc >= 0x40 && opc <= 0x5F) | |
300 | opc = PMIC_ARB_OP_WRITE; | |
301 | else if (opc >= 0x00 && opc <= 0x0F) | |
302 | opc = PMIC_ARB_OP_EXT_WRITE; | |
303 | else if (opc >= 0x30 && opc <= 0x37) | |
304 | opc = PMIC_ARB_OP_EXT_WRITEL; | |
305 | else if (opc >= 0x80 && opc <= 0xFF) | |
306 | opc = PMIC_ARB_OP_ZERO_WRITE; | |
307 | else | |
308 | return -EINVAL; | |
309 | ||
310 | cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7); | |
311 | ||
312 | /* Write data to FIFOs */ | |
313 | raw_spin_lock_irqsave(&pmic_arb->lock, flags); | |
314 | pa_write_data(pmic_arb, buf, PMIC_ARB_WDATA0(pmic_arb->channel) | |
315 | , min_t(u8, bc, 3)); | |
316 | if (bc > 3) | |
317 | pa_write_data(pmic_arb, buf + 4, | |
318 | PMIC_ARB_WDATA1(pmic_arb->channel), bc - 4); | |
319 | ||
320 | /* Start the transaction */ | |
321 | pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd); | |
322 | rc = pmic_arb_wait_for_done(ctrl); | |
323 | raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); | |
324 | ||
325 | return rc; | |
326 | } | |
327 | ||
67b563f1 JC |
328 | enum qpnpint_regs { |
329 | QPNPINT_REG_RT_STS = 0x10, | |
330 | QPNPINT_REG_SET_TYPE = 0x11, | |
331 | QPNPINT_REG_POLARITY_HIGH = 0x12, | |
332 | QPNPINT_REG_POLARITY_LOW = 0x13, | |
333 | QPNPINT_REG_LATCHED_CLR = 0x14, | |
334 | QPNPINT_REG_EN_SET = 0x15, | |
335 | QPNPINT_REG_EN_CLR = 0x16, | |
336 | QPNPINT_REG_LATCHED_STS = 0x18, | |
337 | }; | |
338 | ||
339 | struct spmi_pmic_arb_qpnpint_type { | |
340 | u8 type; /* 1 -> edge */ | |
341 | u8 polarity_high; | |
342 | u8 polarity_low; | |
343 | } __packed; | |
344 | ||
345 | /* Simplified accessor functions for irqchip callbacks */ | |
346 | static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf, | |
347 | size_t len) | |
348 | { | |
349 | struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d); | |
350 | u8 sid = d->hwirq >> 24; | |
351 | u8 per = d->hwirq >> 16; | |
352 | ||
353 | if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid, | |
354 | (per << 8) + reg, buf, len)) | |
355 | dev_err_ratelimited(&pa->spmic->dev, | |
356 | "failed irqchip transaction on %x\n", | |
357 | d->irq); | |
358 | } | |
359 | ||
360 | static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len) | |
361 | { | |
362 | struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d); | |
363 | u8 sid = d->hwirq >> 24; | |
364 | u8 per = d->hwirq >> 16; | |
365 | ||
366 | if (pmic_arb_read_cmd(pa->spmic, SPMI_CMD_EXT_READL, sid, | |
367 | (per << 8) + reg, buf, len)) | |
368 | dev_err_ratelimited(&pa->spmic->dev, | |
369 | "failed irqchip transaction on %x\n", | |
370 | d->irq); | |
371 | } | |
372 | ||
373 | static void periph_interrupt(struct spmi_pmic_arb_dev *pa, u8 apid) | |
374 | { | |
375 | unsigned int irq; | |
376 | u32 status; | |
377 | int id; | |
378 | ||
379 | status = readl_relaxed(pa->intr + SPMI_PIC_IRQ_STATUS(apid)); | |
380 | while (status) { | |
381 | id = ffs(status) - 1; | |
382 | status &= ~(1 << id); | |
383 | irq = irq_find_mapping(pa->domain, | |
384 | pa->apid_to_ppid[apid] << 16 | |
385 | | id << 8 | |
386 | | apid); | |
387 | generic_handle_irq(irq); | |
388 | } | |
389 | } | |
390 | ||
391 | static void pmic_arb_chained_irq(unsigned int irq, struct irq_desc *desc) | |
392 | { | |
393 | struct spmi_pmic_arb_dev *pa = irq_get_handler_data(irq); | |
394 | struct irq_chip *chip = irq_get_chip(irq); | |
395 | void __iomem *intr = pa->intr; | |
396 | int first = pa->min_apid >> 5; | |
397 | int last = pa->max_apid >> 5; | |
398 | u32 status; | |
399 | int i, id; | |
400 | ||
401 | chained_irq_enter(chip, desc); | |
402 | ||
403 | for (i = first; i <= last; ++i) { | |
404 | status = readl_relaxed(intr + | |
405 | SPMI_PIC_OWNER_ACC_STATUS(pa->ee, i)); | |
406 | while (status) { | |
407 | id = ffs(status) - 1; | |
408 | status &= ~(1 << id); | |
409 | periph_interrupt(pa, id + i * 32); | |
410 | } | |
411 | } | |
412 | ||
413 | chained_irq_exit(chip, desc); | |
414 | } | |
415 | ||
416 | static void qpnpint_irq_ack(struct irq_data *d) | |
417 | { | |
418 | struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d); | |
419 | u8 irq = d->hwirq >> 8; | |
420 | u8 apid = d->hwirq; | |
421 | unsigned long flags; | |
422 | u8 data; | |
423 | ||
424 | raw_spin_lock_irqsave(&pa->lock, flags); | |
425 | writel_relaxed(1 << irq, pa->intr + SPMI_PIC_IRQ_CLEAR(apid)); | |
426 | raw_spin_unlock_irqrestore(&pa->lock, flags); | |
427 | ||
428 | data = 1 << irq; | |
429 | qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1); | |
430 | } | |
431 | ||
432 | static void qpnpint_irq_mask(struct irq_data *d) | |
433 | { | |
434 | struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d); | |
435 | u8 irq = d->hwirq >> 8; | |
436 | u8 apid = d->hwirq; | |
437 | unsigned long flags; | |
438 | u32 status; | |
439 | u8 data; | |
440 | ||
441 | raw_spin_lock_irqsave(&pa->lock, flags); | |
442 | status = readl_relaxed(pa->intr + SPMI_PIC_ACC_ENABLE(apid)); | |
443 | if (status & SPMI_PIC_ACC_ENABLE_BIT) { | |
444 | status = status & ~SPMI_PIC_ACC_ENABLE_BIT; | |
445 | writel_relaxed(status, pa->intr + SPMI_PIC_ACC_ENABLE(apid)); | |
446 | } | |
447 | raw_spin_unlock_irqrestore(&pa->lock, flags); | |
448 | ||
449 | data = 1 << irq; | |
450 | qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1); | |
451 | } | |
452 | ||
453 | static void qpnpint_irq_unmask(struct irq_data *d) | |
454 | { | |
455 | struct spmi_pmic_arb_dev *pa = irq_data_get_irq_chip_data(d); | |
456 | u8 irq = d->hwirq >> 8; | |
457 | u8 apid = d->hwirq; | |
458 | unsigned long flags; | |
459 | u32 status; | |
460 | u8 data; | |
461 | ||
462 | raw_spin_lock_irqsave(&pa->lock, flags); | |
463 | status = readl_relaxed(pa->intr + SPMI_PIC_ACC_ENABLE(apid)); | |
464 | if (!(status & SPMI_PIC_ACC_ENABLE_BIT)) { | |
465 | writel_relaxed(status | SPMI_PIC_ACC_ENABLE_BIT, | |
466 | pa->intr + SPMI_PIC_ACC_ENABLE(apid)); | |
467 | } | |
468 | raw_spin_unlock_irqrestore(&pa->lock, flags); | |
469 | ||
470 | data = 1 << irq; | |
471 | qpnpint_spmi_write(d, QPNPINT_REG_EN_SET, &data, 1); | |
472 | } | |
473 | ||
474 | static void qpnpint_irq_enable(struct irq_data *d) | |
475 | { | |
476 | u8 irq = d->hwirq >> 8; | |
477 | u8 data; | |
478 | ||
479 | qpnpint_irq_unmask(d); | |
480 | ||
481 | data = 1 << irq; | |
482 | qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1); | |
483 | } | |
484 | ||
485 | static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) | |
486 | { | |
487 | struct spmi_pmic_arb_qpnpint_type type; | |
488 | u8 irq = d->hwirq >> 8; | |
489 | ||
490 | qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); | |
491 | ||
492 | if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { | |
493 | type.type |= 1 << irq; | |
494 | if (flow_type & IRQF_TRIGGER_RISING) | |
495 | type.polarity_high |= 1 << irq; | |
496 | if (flow_type & IRQF_TRIGGER_FALLING) | |
497 | type.polarity_low |= 1 << irq; | |
498 | } else { | |
499 | if ((flow_type & (IRQF_TRIGGER_HIGH)) && | |
500 | (flow_type & (IRQF_TRIGGER_LOW))) | |
501 | return -EINVAL; | |
502 | ||
503 | type.type &= ~(1 << irq); /* level trig */ | |
504 | if (flow_type & IRQF_TRIGGER_HIGH) | |
505 | type.polarity_high |= 1 << irq; | |
506 | else | |
507 | type.polarity_low |= 1 << irq; | |
508 | } | |
509 | ||
510 | qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); | |
511 | return 0; | |
512 | } | |
513 | ||
514 | static struct irq_chip pmic_arb_irqchip = { | |
515 | .name = "pmic_arb", | |
516 | .irq_enable = qpnpint_irq_enable, | |
517 | .irq_ack = qpnpint_irq_ack, | |
518 | .irq_mask = qpnpint_irq_mask, | |
519 | .irq_unmask = qpnpint_irq_unmask, | |
520 | .irq_set_type = qpnpint_irq_set_type, | |
521 | .flags = IRQCHIP_MASK_ON_SUSPEND | |
522 | | IRQCHIP_SKIP_SET_WAKE, | |
523 | }; | |
524 | ||
525 | struct spmi_pmic_arb_irq_spec { | |
526 | unsigned slave:4; | |
527 | unsigned per:8; | |
528 | unsigned irq:3; | |
529 | }; | |
530 | ||
531 | static int search_mapping_table(struct spmi_pmic_arb_dev *pa, | |
532 | struct spmi_pmic_arb_irq_spec *spec, | |
533 | u8 *apid) | |
534 | { | |
535 | u16 ppid = spec->slave << 8 | spec->per; | |
536 | u32 *mapping_table = pa->mapping_table; | |
537 | int index = 0, i; | |
538 | u32 data; | |
539 | ||
540 | for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) { | |
541 | data = mapping_table[index]; | |
542 | ||
543 | if (ppid & (1 << SPMI_MAPPING_BIT_INDEX(data))) { | |
544 | if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) { | |
545 | index = SPMI_MAPPING_BIT_IS_1_RESULT(data); | |
546 | } else { | |
547 | *apid = SPMI_MAPPING_BIT_IS_1_RESULT(data); | |
548 | return 0; | |
549 | } | |
550 | } else { | |
551 | if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) { | |
552 | index = SPMI_MAPPING_BIT_IS_0_RESULT(data); | |
553 | } else { | |
554 | *apid = SPMI_MAPPING_BIT_IS_0_RESULT(data); | |
555 | return 0; | |
556 | } | |
557 | } | |
558 | } | |
559 | ||
560 | return -ENODEV; | |
561 | } | |
562 | ||
563 | static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, | |
564 | struct device_node *controller, | |
565 | const u32 *intspec, | |
566 | unsigned int intsize, | |
567 | unsigned long *out_hwirq, | |
568 | unsigned int *out_type) | |
569 | { | |
570 | struct spmi_pmic_arb_dev *pa = d->host_data; | |
571 | struct spmi_pmic_arb_irq_spec spec; | |
572 | int err; | |
573 | u8 apid; | |
574 | ||
575 | dev_dbg(&pa->spmic->dev, | |
576 | "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n", | |
577 | intspec[0], intspec[1], intspec[2]); | |
578 | ||
579 | if (d->of_node != controller) | |
580 | return -EINVAL; | |
581 | if (intsize != 4) | |
582 | return -EINVAL; | |
583 | if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7) | |
584 | return -EINVAL; | |
585 | ||
586 | spec.slave = intspec[0]; | |
587 | spec.per = intspec[1]; | |
588 | spec.irq = intspec[2]; | |
589 | ||
590 | err = search_mapping_table(pa, &spec, &apid); | |
591 | if (err) | |
592 | return err; | |
593 | ||
594 | pa->apid_to_ppid[apid] = spec.slave << 8 | spec.per; | |
595 | ||
596 | /* Keep track of {max,min}_apid for bounding search during interrupt */ | |
597 | if (apid > pa->max_apid) | |
598 | pa->max_apid = apid; | |
599 | if (apid < pa->min_apid) | |
600 | pa->min_apid = apid; | |
601 | ||
602 | *out_hwirq = spec.slave << 24 | |
603 | | spec.per << 16 | |
604 | | spec.irq << 8 | |
605 | | apid; | |
606 | *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK; | |
607 | ||
608 | dev_dbg(&pa->spmic->dev, "out_hwirq = %lu\n", *out_hwirq); | |
609 | ||
610 | return 0; | |
611 | } | |
612 | ||
613 | static int qpnpint_irq_domain_map(struct irq_domain *d, | |
614 | unsigned int virq, | |
615 | irq_hw_number_t hwirq) | |
616 | { | |
617 | struct spmi_pmic_arb_dev *pa = d->host_data; | |
618 | ||
619 | dev_dbg(&pa->spmic->dev, "virq = %u, hwirq = %lu\n", virq, hwirq); | |
620 | ||
621 | irq_set_chip_and_handler(virq, &pmic_arb_irqchip, handle_level_irq); | |
622 | irq_set_chip_data(virq, d->host_data); | |
623 | irq_set_noprobe(virq); | |
624 | return 0; | |
625 | } | |
626 | ||
627 | static const struct irq_domain_ops pmic_arb_irq_domain_ops = { | |
628 | .map = qpnpint_irq_domain_map, | |
629 | .xlate = qpnpint_irq_domain_dt_translate, | |
630 | }; | |
631 | ||
39ae93e3 KH |
632 | static int spmi_pmic_arb_probe(struct platform_device *pdev) |
633 | { | |
634 | struct spmi_pmic_arb_dev *pa; | |
635 | struct spmi_controller *ctrl; | |
636 | struct resource *res; | |
67b563f1 | 637 | u32 channel, ee; |
39ae93e3 KH |
638 | int err, i; |
639 | ||
640 | ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa)); | |
641 | if (!ctrl) | |
642 | return -ENOMEM; | |
643 | ||
644 | pa = spmi_controller_get_drvdata(ctrl); | |
67b563f1 | 645 | pa->spmic = ctrl; |
39ae93e3 KH |
646 | |
647 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); | |
648 | pa->base = devm_ioremap_resource(&ctrl->dev, res); | |
649 | if (IS_ERR(pa->base)) { | |
650 | err = PTR_ERR(pa->base); | |
651 | goto err_put_ctrl; | |
652 | } | |
653 | ||
654 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr"); | |
655 | pa->intr = devm_ioremap_resource(&ctrl->dev, res); | |
656 | if (IS_ERR(pa->intr)) { | |
657 | err = PTR_ERR(pa->intr); | |
658 | goto err_put_ctrl; | |
659 | } | |
660 | ||
661 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg"); | |
662 | pa->cnfg = devm_ioremap_resource(&ctrl->dev, res); | |
663 | if (IS_ERR(pa->cnfg)) { | |
664 | err = PTR_ERR(pa->cnfg); | |
665 | goto err_put_ctrl; | |
666 | } | |
667 | ||
67b563f1 JC |
668 | pa->irq = platform_get_irq_byname(pdev, "periph_irq"); |
669 | if (pa->irq < 0) { | |
670 | err = pa->irq; | |
671 | goto err_put_ctrl; | |
672 | } | |
673 | ||
39ae93e3 KH |
674 | err = of_property_read_u32(pdev->dev.of_node, "qcom,channel", &channel); |
675 | if (err) { | |
676 | dev_err(&pdev->dev, "channel unspecified.\n"); | |
677 | goto err_put_ctrl; | |
678 | } | |
679 | ||
680 | if (channel > 5) { | |
681 | dev_err(&pdev->dev, "invalid channel (%u) specified.\n", | |
682 | channel); | |
683 | goto err_put_ctrl; | |
684 | } | |
685 | ||
686 | pa->channel = channel; | |
687 | ||
67b563f1 JC |
688 | err = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &ee); |
689 | if (err) { | |
690 | dev_err(&pdev->dev, "EE unspecified.\n"); | |
691 | goto err_put_ctrl; | |
692 | } | |
693 | ||
694 | if (ee > 5) { | |
695 | dev_err(&pdev->dev, "invalid EE (%u) specified\n", ee); | |
696 | err = -EINVAL; | |
697 | goto err_put_ctrl; | |
698 | } | |
699 | ||
700 | pa->ee = ee; | |
701 | ||
702 | for (i = 0; i < ARRAY_SIZE(pa->mapping_table); ++i) | |
703 | pa->mapping_table[i] = readl_relaxed( | |
704 | pa->cnfg + SPMI_MAPPING_TABLE_REG(i)); | |
705 | ||
706 | /* Initialize max_apid/min_apid to the opposite bounds, during | |
707 | * the irq domain translation, we are sure to update these */ | |
708 | pa->max_apid = 0; | |
709 | pa->min_apid = PMIC_ARB_MAX_PERIPHS - 1; | |
710 | ||
39ae93e3 KH |
711 | platform_set_drvdata(pdev, ctrl); |
712 | raw_spin_lock_init(&pa->lock); | |
713 | ||
714 | ctrl->cmd = pmic_arb_cmd; | |
715 | ctrl->read_cmd = pmic_arb_read_cmd; | |
716 | ctrl->write_cmd = pmic_arb_write_cmd; | |
717 | ||
67b563f1 JC |
718 | dev_dbg(&pdev->dev, "adding irq domain\n"); |
719 | pa->domain = irq_domain_add_tree(pdev->dev.of_node, | |
720 | &pmic_arb_irq_domain_ops, pa); | |
721 | if (!pa->domain) { | |
722 | dev_err(&pdev->dev, "unable to create irq_domain\n"); | |
723 | err = -ENOMEM; | |
724 | goto err_put_ctrl; | |
725 | } | |
726 | ||
727 | irq_set_handler_data(pa->irq, pa); | |
728 | irq_set_chained_handler(pa->irq, pmic_arb_chained_irq); | |
729 | ||
39ae93e3 KH |
730 | err = spmi_controller_add(ctrl); |
731 | if (err) | |
67b563f1 | 732 | goto err_domain_remove; |
39ae93e3 KH |
733 | |
734 | dev_dbg(&ctrl->dev, "PMIC Arb Version 0x%x\n", | |
735 | pmic_arb_base_read(pa, PMIC_ARB_VERSION)); | |
736 | ||
737 | return 0; | |
738 | ||
67b563f1 JC |
739 | err_domain_remove: |
740 | irq_set_chained_handler(pa->irq, NULL); | |
741 | irq_set_handler_data(pa->irq, NULL); | |
742 | irq_domain_remove(pa->domain); | |
39ae93e3 KH |
743 | err_put_ctrl: |
744 | spmi_controller_put(ctrl); | |
745 | return err; | |
746 | } | |
747 | ||
748 | static int spmi_pmic_arb_remove(struct platform_device *pdev) | |
749 | { | |
750 | struct spmi_controller *ctrl = platform_get_drvdata(pdev); | |
67b563f1 | 751 | struct spmi_pmic_arb_dev *pa = spmi_controller_get_drvdata(ctrl); |
39ae93e3 | 752 | spmi_controller_remove(ctrl); |
67b563f1 JC |
753 | irq_set_chained_handler(pa->irq, NULL); |
754 | irq_set_handler_data(pa->irq, NULL); | |
755 | irq_domain_remove(pa->domain); | |
39ae93e3 KH |
756 | spmi_controller_put(ctrl); |
757 | return 0; | |
758 | } | |
759 | ||
760 | static const struct of_device_id spmi_pmic_arb_match_table[] = { | |
761 | { .compatible = "qcom,spmi-pmic-arb", }, | |
762 | {}, | |
763 | }; | |
764 | MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table); | |
765 | ||
766 | static struct platform_driver spmi_pmic_arb_driver = { | |
767 | .probe = spmi_pmic_arb_probe, | |
768 | .remove = spmi_pmic_arb_remove, | |
769 | .driver = { | |
770 | .name = "spmi_pmic_arb", | |
771 | .owner = THIS_MODULE, | |
772 | .of_match_table = spmi_pmic_arb_match_table, | |
773 | }, | |
774 | }; | |
775 | module_platform_driver(spmi_pmic_arb_driver); | |
776 | ||
777 | MODULE_LICENSE("GPL v2"); | |
778 | MODULE_ALIAS("platform:spmi_pmic_arb"); |