Blame view
drivers/spmi/spmi-pmic-arb.c
36.6 KB
97fb5e8d9 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
d0c6ae41d spmi: pmic_arb: a... |
2 |
/* |
53d296b59 spmi: pmic-arb: R... |
3 |
* Copyright (c) 2012-2015, 2017, The Linux Foundation. All rights reserved. |
39ae93e3a spmi: Add MSM PMI... |
4 |
*/ |
987a9f128 spmi: pmic-arb: S... |
5 |
#include <linux/bitmap.h> |
39ae93e3a spmi: Add MSM PMI... |
6 7 8 9 |
#include <linux/delay.h> #include <linux/err.h> #include <linux/interrupt.h> #include <linux/io.h> |
67b563f1f spmi: pmic_arb: a... |
10 11 12 |
#include <linux/irqchip/chained_irq.h> #include <linux/irqdomain.h> #include <linux/irq.h> |
39ae93e3a spmi: Add MSM PMI... |
13 14 15 16 17 18 19 20 21 |
#include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spmi.h> /* PMIC Arbiter configuration registers */ #define PMIC_ARB_VERSION 0x0000 |
d0c6ae41d spmi: pmic_arb: a... |
22 |
#define PMIC_ARB_VERSION_V2_MIN 0x20010000 |
319f68843 spmi: pmic_arb: a... |
23 |
#define PMIC_ARB_VERSION_V3_MIN 0x30000000 |
40f318f0e spmi: pmic-arb: a... |
24 |
#define PMIC_ARB_VERSION_V5_MIN 0x50000000 |
39ae93e3a spmi: Add MSM PMI... |
25 |
#define PMIC_ARB_INT_EN 0x0004 |
d0c6ae41d spmi: pmic_arb: a... |
26 27 28 29 30 31 32 33 |
/* PMIC Arbiter channel registers offsets */ #define PMIC_ARB_CMD 0x00 #define PMIC_ARB_CONFIG 0x04 #define PMIC_ARB_STATUS 0x08 #define PMIC_ARB_WDATA0 0x10 #define PMIC_ARB_WDATA1 0x14 #define PMIC_ARB_RDATA0 0x18 #define PMIC_ARB_RDATA1 0x1C |
39ae93e3a spmi: Add MSM PMI... |
34 35 36 37 38 39 40 41 |
/* Mapping Table */ #define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N))) #define SPMI_MAPPING_BIT_INDEX(X) (((X) >> 18) & 0xF) #define SPMI_MAPPING_BIT_IS_0_FLAG(X) (((X) >> 17) & 0x1) #define SPMI_MAPPING_BIT_IS_0_RESULT(X) (((X) >> 9) & 0xFF) #define SPMI_MAPPING_BIT_IS_1_FLAG(X) (((X) >> 8) & 0x1) #define SPMI_MAPPING_BIT_IS_1_RESULT(X) (((X) >> 0) & 0xFF) |
39ae93e3a spmi: Add MSM PMI... |
42 |
#define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ |
987a9f128 spmi: pmic-arb: S... |
43 |
#define PMIC_ARB_MAX_PPID BIT(12) /* PPID is 12bit */ |
02abec361 spmi: pmic-arb: r... |
44 |
#define PMIC_ARB_APID_VALID BIT(15) |
40f318f0e spmi: pmic-arb: a... |
45 46 |
#define PMIC_ARB_CHAN_IS_IRQ_OWNER(reg) ((reg) & BIT(24)) #define INVALID_EE 0xFF |
39ae93e3a spmi: Add MSM PMI... |
47 48 49 50 51 52 53 |
/* Ownership Table */ #define SPMI_OWNERSHIP_TABLE_REG(N) (0x0700 + (4 * (N))) #define SPMI_OWNERSHIP_PERIPH2OWNER(X) ((X) & 0x7) /* Channel Status fields */ enum pmic_arb_chnl_status { |
111a10bf3 spmi: pmic-arb: r... |
54 55 56 57 |
PMIC_ARB_STATUS_DONE = BIT(0), PMIC_ARB_STATUS_FAILURE = BIT(1), PMIC_ARB_STATUS_DENIED = BIT(2), PMIC_ARB_STATUS_DROPPED = BIT(3), |
39ae93e3a spmi: Add MSM PMI... |
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
}; /* Command register fields */ #define PMIC_ARB_CMD_MAX_BYTE_COUNT 8 /* Command Opcodes */ enum pmic_arb_cmd_op_code { PMIC_ARB_OP_EXT_WRITEL = 0, PMIC_ARB_OP_EXT_READL = 1, PMIC_ARB_OP_EXT_WRITE = 2, PMIC_ARB_OP_RESET = 3, PMIC_ARB_OP_SLEEP = 4, PMIC_ARB_OP_SHUTDOWN = 5, PMIC_ARB_OP_WAKEUP = 6, PMIC_ARB_OP_AUTHENTICATE = 7, PMIC_ARB_OP_MSTR_READ = 8, PMIC_ARB_OP_MSTR_WRITE = 9, PMIC_ARB_OP_EXT_READ = 13, PMIC_ARB_OP_WRITE = 14, PMIC_ARB_OP_READ = 15, PMIC_ARB_OP_ZERO_WRITE = 16, }; |
40f318f0e spmi: pmic-arb: a... |
80 81 82 83 84 85 86 87 |
/* * PMIC arbiter version 5 uses different register offsets for read/write vs * observer channels. */ enum pmic_arb_channel { PMIC_ARB_CHANNEL_RW, PMIC_ARB_CHANNEL_OBS, }; |
39ae93e3a spmi: Add MSM PMI... |
88 |
/* Maximum number of support PMIC peripherals */ |
987a9f128 spmi: pmic-arb: S... |
89 |
#define PMIC_ARB_MAX_PERIPHS 512 |
39ae93e3a spmi: Add MSM PMI... |
90 91 92 93 94 95 96 97 |
#define PMIC_ARB_TIMEOUT_US 100 #define PMIC_ARB_MAX_TRANS_BYTES (8) #define PMIC_ARB_APID_MASK 0xFF #define PMIC_ARB_PPID_MASK 0xFFF /* interrupt enable bit */ #define SPMI_PIC_ACC_ENABLE_BIT BIT(0) |
02abec361 spmi: pmic-arb: r... |
98 |
#define spec_to_hwirq(slave_id, periph_id, irq_id, apid) \ |
319f68843 spmi: pmic_arb: a... |
99 100 101 102 |
((((slave_id) & 0xF) << 28) | \ (((periph_id) & 0xFF) << 20) | \ (((irq_id) & 0x7) << 16) | \ (((apid) & 0x1FF) << 0)) |
02abec361 spmi: pmic-arb: r... |
103 104 105 106 |
#define hwirq_to_sid(hwirq) (((hwirq) >> 28) & 0xF) #define hwirq_to_per(hwirq) (((hwirq) >> 20) & 0xFF) #define hwirq_to_irq(hwirq) (((hwirq) >> 16) & 0x7) #define hwirq_to_apid(hwirq) (((hwirq) >> 0) & 0x1FF) |
319f68843 spmi: pmic_arb: a... |
107 |
|
d0c6ae41d spmi: pmic_arb: a... |
108 |
struct pmic_arb_ver_ops; |
6bc546e71 spmi: pmic-arb: c... |
109 110 |
struct apid_data { u16 ppid; |
40f318f0e spmi: pmic-arb: a... |
111 112 |
u8 write_ee; u8 irq_ee; |
6bc546e71 spmi: pmic-arb: c... |
113 |
}; |
39ae93e3a spmi: Add MSM PMI... |
114 |
/** |
111a10bf3 spmi: pmic-arb: r... |
115 |
* spmi_pmic_arb - SPMI PMIC Arbiter object |
39ae93e3a spmi: Add MSM PMI... |
116 |
* |
d0c6ae41d spmi: pmic_arb: a... |
117 118 |
* @rd_base: on v1 "core", on v2 "observer" register base off DT. * @wr_base: on v1 "core", on v2 "chnls" register base off DT. |
39ae93e3a spmi: Add MSM PMI... |
119 120 121 |
* @intr: address of the SPMI interrupt control registers. * @cnfg: address of the PMIC Arbiter configuration registers. * @lock: lock to synchronize accesses. |
d0c6ae41d spmi: pmic_arb: a... |
122 |
* @channel: execution environment channel to use for accesses. |
67b563f1f spmi: pmic_arb: a... |
123 124 125 126 127 128 129 |
* @irq: PMIC ARB interrupt. * @ee: the current Execution Environment * @min_apid: minimum APID (used for bounding IRQ search) * @max_apid: maximum APID * @mapping_table: in-memory copy of PPID -> APID mapping table. * @domain: irq domain object for PMIC IRQ domain * @spmic: SPMI controller object |
d0c6ae41d spmi: pmic_arb: a... |
130 |
* @ver_ops: version dependent operations. |
02abec361 spmi: pmic-arb: r... |
131 |
* @ppid_to_apid in-memory copy of PPID -> APID mapping table. |
39ae93e3a spmi: Add MSM PMI... |
132 |
*/ |
111a10bf3 spmi: pmic-arb: r... |
133 |
struct spmi_pmic_arb { |
d0c6ae41d spmi: pmic_arb: a... |
134 135 |
void __iomem *rd_base; void __iomem *wr_base; |
39ae93e3a spmi: Add MSM PMI... |
136 137 |
void __iomem *intr; void __iomem *cnfg; |
987a9f128 spmi: pmic-arb: S... |
138 139 |
void __iomem *core; resource_size_t core_size; |
39ae93e3a spmi: Add MSM PMI... |
140 141 |
raw_spinlock_t lock; u8 channel; |
67b563f1f spmi: pmic_arb: a... |
142 143 |
int irq; u8 ee; |
987a9f128 spmi: pmic-arb: S... |
144 145 146 147 |
u16 min_apid; u16 max_apid; u32 *mapping_table; DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS); |
67b563f1f spmi: pmic_arb: a... |
148 149 |
struct irq_domain *domain; struct spmi_controller *spmic; |
d0c6ae41d spmi: pmic_arb: a... |
150 |
const struct pmic_arb_ver_ops *ver_ops; |
1ef1ce4e9 spmi: pmic-arb: f... |
151 152 |
u16 *ppid_to_apid; u16 last_apid; |
6bc546e71 spmi: pmic-arb: c... |
153 |
struct apid_data apid_data[PMIC_ARB_MAX_PERIPHS]; |
d0c6ae41d spmi: pmic_arb: a... |
154 155 156 157 158 |
}; /** * pmic_arb_ver: version dependent functionality. * |
319f68843 spmi: pmic_arb: a... |
159 160 |
* @ver_str: version string. * @ppid_to_apid: finds the apid for a given ppid. |
d0c6ae41d spmi: pmic_arb: a... |
161 162 163 164 165 |
* @non_data_cmd: on v1 issues an spmi non-data command. * on v2 no HW support, returns -EOPNOTSUPP. * @offset: on v1 offset of per-ee channel. * on v2 offset of per-ee and per-ppid channel. * @fmt_cmd: formats a GENI/SPMI command. |
e95d073c8 spmi: pmic-arb: r... |
166 167 168 169 170 171 172 173 |
* @owner_acc_status: on v1 address of PMIC_ARB_SPMI_PIC_OWNERm_ACC_STATUSn * on v2 address of SPMI_PIC_OWNERm_ACC_STATUSn. * @acc_enable: on v1 address of PMIC_ARB_SPMI_PIC_ACC_ENABLEn * on v2 address of SPMI_PIC_ACC_ENABLEn. * @irq_status: on v1 address of PMIC_ARB_SPMI_PIC_IRQ_STATUSn * on v2 address of SPMI_PIC_IRQ_STATUSn. * @irq_clear: on v1 address of PMIC_ARB_SPMI_PIC_IRQ_CLEARn * on v2 address of SPMI_PIC_IRQ_CLEARn. |
40f318f0e spmi: pmic-arb: a... |
174 |
* @apid_map_offset: offset of PMIC_ARB_REG_CHNLn |
d0c6ae41d spmi: pmic_arb: a... |
175 176 |
*/ struct pmic_arb_ver_ops { |
319f68843 spmi: pmic_arb: a... |
177 |
const char *ver_str; |
ff615ed91 spmi: pmic-arb: r... |
178 |
int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u16 ppid); |
d0c6ae41d spmi: pmic_arb: a... |
179 |
/* spmi commands (read_cmd, write_cmd, cmd) functionality */ |
40f318f0e spmi: pmic-arb: a... |
180 181 |
int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, enum pmic_arb_channel ch_type); |
d0c6ae41d spmi: pmic_arb: a... |
182 183 184 |
u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); /* Interrupts controller functionality (offset of PIC registers) */ |
e95d073c8 spmi: pmic-arb: r... |
185 186 187 188 189 |
void __iomem *(*owner_acc_status)(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n); void __iomem *(*acc_enable)(struct spmi_pmic_arb *pmic_arb, u16 n); void __iomem *(*irq_status)(struct spmi_pmic_arb *pmic_arb, u16 n); void __iomem *(*irq_clear)(struct spmi_pmic_arb *pmic_arb, u16 n); |
40f318f0e spmi: pmic-arb: a... |
190 |
u32 (*apid_map_offset)(u16 n); |
39ae93e3a spmi: Add MSM PMI... |
191 |
}; |
02abec361 spmi: pmic-arb: r... |
192 |
static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb, |
39ae93e3a spmi: Add MSM PMI... |
193 194 |
u32 offset, u32 val) { |
02abec361 spmi: pmic-arb: r... |
195 |
writel_relaxed(val, pmic_arb->wr_base + offset); |
d0c6ae41d spmi: pmic_arb: a... |
196 |
} |
02abec361 spmi: pmic-arb: r... |
197 |
static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pmic_arb, |
d0c6ae41d spmi: pmic_arb: a... |
198 199 |
u32 offset, u32 val) { |
02abec361 spmi: pmic-arb: r... |
200 |
writel_relaxed(val, pmic_arb->rd_base + offset); |
39ae93e3a spmi: Add MSM PMI... |
201 202 203 |
} /** |
02abec361 spmi: pmic-arb: r... |
204 |
* pmic_arb_read_data: reads pmic-arb's register and copy 1..4 bytes to buf |
39ae93e3a spmi: Add MSM PMI... |
205 206 207 208 |
* @bc: byte count -1. range: 0..3 * @reg: register's address * @buf: output parameter, length must be bc + 1 */ |
02abec361 spmi: pmic-arb: r... |
209 210 |
static void pmic_arb_read_data(struct spmi_pmic_arb *pmic_arb, u8 *buf, u32 reg, u8 bc) |
39ae93e3a spmi: Add MSM PMI... |
211 |
{ |
02abec361 spmi: pmic-arb: r... |
212 |
u32 data = __raw_readl(pmic_arb->rd_base + reg); |
111a10bf3 spmi: pmic-arb: r... |
213 |
|
39ae93e3a spmi: Add MSM PMI... |
214 215 216 217 |
memcpy(buf, &data, (bc & 3) + 1); } /** |
02abec361 spmi: pmic-arb: r... |
218 |
* pmic_arb_write_data: write 1..4 bytes from buf to pmic-arb's register |
39ae93e3a spmi: Add MSM PMI... |
219 220 221 222 |
* @bc: byte-count -1. range: 0..3. * @reg: register's address. * @buf: buffer to write. length must be bc + 1. */ |
02abec361 spmi: pmic-arb: r... |
223 224 |
static void pmic_arb_write_data(struct spmi_pmic_arb *pmic_arb, const u8 *buf, u32 reg, u8 bc) |
39ae93e3a spmi: Add MSM PMI... |
225 226 |
{ u32 data = 0; |
111a10bf3 spmi: pmic-arb: r... |
227 |
|
39ae93e3a spmi: Add MSM PMI... |
228 |
memcpy(&data, buf, (bc & 3) + 1); |
9f7a9a448 spmi: pmic-arb: r... |
229 |
__raw_writel(data, pmic_arb->wr_base + reg); |
39ae93e3a spmi: Add MSM PMI... |
230 |
} |
d0c6ae41d spmi: pmic_arb: a... |
231 |
static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, |
40f318f0e spmi: pmic-arb: a... |
232 233 |
void __iomem *base, u8 sid, u16 addr, enum pmic_arb_channel ch_type) |
39ae93e3a spmi: Add MSM PMI... |
234 |
{ |
02abec361 spmi: pmic-arb: r... |
235 |
struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); |
39ae93e3a spmi: Add MSM PMI... |
236 237 |
u32 status = 0; u32 timeout = PMIC_ARB_TIMEOUT_US; |
987a9f128 spmi: pmic-arb: S... |
238 239 |
u32 offset; int rc; |
40f318f0e spmi: pmic-arb: a... |
240 |
rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, ch_type); |
ff615ed91 spmi: pmic-arb: r... |
241 |
if (rc < 0) |
987a9f128 spmi: pmic-arb: S... |
242 |
return rc; |
ff615ed91 spmi: pmic-arb: r... |
243 |
offset = rc; |
987a9f128 spmi: pmic-arb: S... |
244 |
offset += PMIC_ARB_STATUS; |
39ae93e3a spmi: Add MSM PMI... |
245 246 |
while (timeout--) { |
d0c6ae41d spmi: pmic_arb: a... |
247 |
status = readl_relaxed(base + offset); |
39ae93e3a spmi: Add MSM PMI... |
248 249 250 |
if (status & PMIC_ARB_STATUS_DONE) { if (status & PMIC_ARB_STATUS_DENIED) { |
02abec361 spmi: pmic-arb: r... |
251 252 |
dev_err(&ctrl->dev, "%s: transaction denied (0x%x) ", |
39ae93e3a spmi: Add MSM PMI... |
253 254 255 256 257 |
__func__, status); return -EPERM; } if (status & PMIC_ARB_STATUS_FAILURE) { |
02abec361 spmi: pmic-arb: r... |
258 259 |
dev_err(&ctrl->dev, "%s: transaction failed (0x%x) ", |
39ae93e3a spmi: Add MSM PMI... |
260 261 262 263 264 |
__func__, status); return -EIO; } if (status & PMIC_ARB_STATUS_DROPPED) { |
02abec361 spmi: pmic-arb: r... |
265 266 |
dev_err(&ctrl->dev, "%s: transaction dropped (0x%x) ", |
39ae93e3a spmi: Add MSM PMI... |
267 268 269 270 271 272 273 274 |
__func__, status); return -EIO; } return 0; } udelay(1); } |
02abec361 spmi: pmic-arb: r... |
275 276 |
dev_err(&ctrl->dev, "%s: timeout, status 0x%x ", |
39ae93e3a spmi: Add MSM PMI... |
277 278 279 |
__func__, status); return -ETIMEDOUT; } |
d0c6ae41d spmi: pmic_arb: a... |
280 281 |
static int pmic_arb_non_data_cmd_v1(struct spmi_controller *ctrl, u8 opc, u8 sid) |
39ae93e3a spmi: Add MSM PMI... |
282 |
{ |
02abec361 spmi: pmic-arb: r... |
283 |
struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); |
39ae93e3a spmi: Add MSM PMI... |
284 285 286 |
unsigned long flags; u32 cmd; int rc; |
987a9f128 spmi: pmic-arb: S... |
287 |
u32 offset; |
40f318f0e spmi: pmic-arb: a... |
288 |
rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, PMIC_ARB_CHANNEL_RW); |
ff615ed91 spmi: pmic-arb: r... |
289 |
if (rc < 0) |
987a9f128 spmi: pmic-arb: S... |
290 |
return rc; |
39ae93e3a spmi: Add MSM PMI... |
291 |
|
ff615ed91 spmi: pmic-arb: r... |
292 |
offset = rc; |
39ae93e3a spmi: Add MSM PMI... |
293 |
cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20); |
02abec361 spmi: pmic-arb: r... |
294 295 |
raw_spin_lock_irqsave(&pmic_arb->lock, flags); pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd); |
40f318f0e spmi: pmic-arb: a... |
296 297 |
rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, 0, PMIC_ARB_CHANNEL_RW); |
02abec361 spmi: pmic-arb: r... |
298 |
raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); |
39ae93e3a spmi: Add MSM PMI... |
299 300 301 |
return rc; } |
d0c6ae41d spmi: pmic_arb: a... |
302 303 304 305 306 307 308 309 310 |
static int pmic_arb_non_data_cmd_v2(struct spmi_controller *ctrl, u8 opc, u8 sid) { return -EOPNOTSUPP; } /* Non-data command */ static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid) { |
02abec361 spmi: pmic-arb: r... |
311 |
struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); |
d0c6ae41d spmi: pmic_arb: a... |
312 313 314 315 316 317 318 |
dev_dbg(&ctrl->dev, "cmd op:0x%x sid:%d ", opc, sid); /* Check for valid non-data command */ if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP) return -EINVAL; |
02abec361 spmi: pmic-arb: r... |
319 |
return pmic_arb->ver_ops->non_data_cmd(ctrl, opc, sid); |
d0c6ae41d spmi: pmic_arb: a... |
320 |
} |
39ae93e3a spmi: Add MSM PMI... |
321 322 323 |
static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, u16 addr, u8 *buf, size_t len) { |
02abec361 spmi: pmic-arb: r... |
324 |
struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); |
39ae93e3a spmi: Add MSM PMI... |
325 326 327 328 |
unsigned long flags; u8 bc = len - 1; u32 cmd; int rc; |
987a9f128 spmi: pmic-arb: S... |
329 |
u32 offset; |
40f318f0e spmi: pmic-arb: a... |
330 331 |
rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, PMIC_ARB_CHANNEL_OBS); |
ff615ed91 spmi: pmic-arb: r... |
332 |
if (rc < 0) |
987a9f128 spmi: pmic-arb: S... |
333 |
return rc; |
39ae93e3a spmi: Add MSM PMI... |
334 |
|
ff615ed91 spmi: pmic-arb: r... |
335 |
offset = rc; |
39ae93e3a spmi: Add MSM PMI... |
336 |
if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { |
02abec361 spmi: pmic-arb: r... |
337 |
dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", |
39ae93e3a spmi: Add MSM PMI... |
338 339 340 341 342 343 344 345 346 347 348 349 350 |
PMIC_ARB_MAX_TRANS_BYTES, len); return -EINVAL; } /* Check the opcode */ if (opc >= 0x60 && opc <= 0x7F) opc = PMIC_ARB_OP_READ; else if (opc >= 0x20 && opc <= 0x2F) opc = PMIC_ARB_OP_EXT_READ; else if (opc >= 0x38 && opc <= 0x3F) opc = PMIC_ARB_OP_EXT_READL; else return -EINVAL; |
02abec361 spmi: pmic-arb: r... |
351 |
cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc); |
39ae93e3a spmi: Add MSM PMI... |
352 |
|
02abec361 spmi: pmic-arb: r... |
353 354 |
raw_spin_lock_irqsave(&pmic_arb->lock, flags); pmic_arb_set_rd_cmd(pmic_arb, offset + PMIC_ARB_CMD, cmd); |
40f318f0e spmi: pmic-arb: a... |
355 356 |
rc = pmic_arb_wait_for_done(ctrl, pmic_arb->rd_base, sid, addr, PMIC_ARB_CHANNEL_OBS); |
39ae93e3a spmi: Add MSM PMI... |
357 358 |
if (rc) goto done; |
02abec361 spmi: pmic-arb: r... |
359 |
pmic_arb_read_data(pmic_arb, buf, offset + PMIC_ARB_RDATA0, |
39ae93e3a spmi: Add MSM PMI... |
360 361 362 |
min_t(u8, bc, 3)); if (bc > 3) |
02abec361 spmi: pmic-arb: r... |
363 364 |
pmic_arb_read_data(pmic_arb, buf + 4, offset + PMIC_ARB_RDATA1, bc - 4); |
39ae93e3a spmi: Add MSM PMI... |
365 366 |
done: |
02abec361 spmi: pmic-arb: r... |
367 |
raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); |
39ae93e3a spmi: Add MSM PMI... |
368 369 370 371 |
return rc; } static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, |
40f318f0e spmi: pmic-arb: a... |
372 |
u16 addr, const u8 *buf, size_t len) |
39ae93e3a spmi: Add MSM PMI... |
373 |
{ |
02abec361 spmi: pmic-arb: r... |
374 |
struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); |
39ae93e3a spmi: Add MSM PMI... |
375 376 377 378 |
unsigned long flags; u8 bc = len - 1; u32 cmd; int rc; |
987a9f128 spmi: pmic-arb: S... |
379 |
u32 offset; |
40f318f0e spmi: pmic-arb: a... |
380 381 |
rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, PMIC_ARB_CHANNEL_RW); |
ff615ed91 spmi: pmic-arb: r... |
382 |
if (rc < 0) |
987a9f128 spmi: pmic-arb: S... |
383 |
return rc; |
39ae93e3a spmi: Add MSM PMI... |
384 |
|
ff615ed91 spmi: pmic-arb: r... |
385 |
offset = rc; |
39ae93e3a spmi: Add MSM PMI... |
386 |
if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { |
02abec361 spmi: pmic-arb: r... |
387 |
dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", |
39ae93e3a spmi: Add MSM PMI... |
388 389 390 391 392 393 394 |
PMIC_ARB_MAX_TRANS_BYTES, len); return -EINVAL; } /* Check the opcode */ if (opc >= 0x40 && opc <= 0x5F) opc = PMIC_ARB_OP_WRITE; |
53d296b59 spmi: pmic-arb: R... |
395 |
else if (opc <= 0x0F) |
39ae93e3a spmi: Add MSM PMI... |
396 397 398 |
opc = PMIC_ARB_OP_EXT_WRITE; else if (opc >= 0x30 && opc <= 0x37) opc = PMIC_ARB_OP_EXT_WRITEL; |
9b76968db spmi: pmic-arb: u... |
399 |
else if (opc >= 0x80) |
39ae93e3a spmi: Add MSM PMI... |
400 401 402 |
opc = PMIC_ARB_OP_ZERO_WRITE; else return -EINVAL; |
02abec361 spmi: pmic-arb: r... |
403 |
cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc); |
39ae93e3a spmi: Add MSM PMI... |
404 405 |
/* Write data to FIFOs */ |
02abec361 spmi: pmic-arb: r... |
406 407 408 |
raw_spin_lock_irqsave(&pmic_arb->lock, flags); pmic_arb_write_data(pmic_arb, buf, offset + PMIC_ARB_WDATA0, min_t(u8, bc, 3)); |
39ae93e3a spmi: Add MSM PMI... |
409 |
if (bc > 3) |
02abec361 spmi: pmic-arb: r... |
410 411 |
pmic_arb_write_data(pmic_arb, buf + 4, offset + PMIC_ARB_WDATA1, bc - 4); |
39ae93e3a spmi: Add MSM PMI... |
412 413 |
/* Start the transaction */ |
02abec361 spmi: pmic-arb: r... |
414 |
pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd); |
40f318f0e spmi: pmic-arb: a... |
415 416 |
rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, addr, PMIC_ARB_CHANNEL_RW); |
02abec361 spmi: pmic-arb: r... |
417 |
raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); |
39ae93e3a spmi: Add MSM PMI... |
418 419 420 |
return rc; } |
67b563f1f spmi: pmic_arb: a... |
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
enum qpnpint_regs { QPNPINT_REG_RT_STS = 0x10, QPNPINT_REG_SET_TYPE = 0x11, QPNPINT_REG_POLARITY_HIGH = 0x12, QPNPINT_REG_POLARITY_LOW = 0x13, QPNPINT_REG_LATCHED_CLR = 0x14, QPNPINT_REG_EN_SET = 0x15, QPNPINT_REG_EN_CLR = 0x16, QPNPINT_REG_LATCHED_STS = 0x18, }; struct spmi_pmic_arb_qpnpint_type { u8 type; /* 1 -> edge */ u8 polarity_high; u8 polarity_low; } __packed; /* Simplified accessor functions for irqchip callbacks */ static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf, size_t len) { |
02abec361 spmi: pmic-arb: r... |
442 443 444 |
struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); u8 sid = hwirq_to_sid(d->hwirq); u8 per = hwirq_to_per(d->hwirq); |
67b563f1f spmi: pmic_arb: a... |
445 |
|
02abec361 spmi: pmic-arb: r... |
446 |
if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid, |
67b563f1f spmi: pmic_arb: a... |
447 |
(per << 8) + reg, buf, len)) |
02abec361 spmi: pmic-arb: r... |
448 449 |
dev_err_ratelimited(&pmic_arb->spmic->dev, "failed irqchip transaction on %x ", |
67b563f1f spmi: pmic_arb: a... |
450 451 452 453 454 |
d->irq); } static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len) { |
02abec361 spmi: pmic-arb: r... |
455 456 457 |
struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); u8 sid = hwirq_to_sid(d->hwirq); u8 per = hwirq_to_per(d->hwirq); |
67b563f1f spmi: pmic_arb: a... |
458 |
|
02abec361 spmi: pmic-arb: r... |
459 |
if (pmic_arb_read_cmd(pmic_arb->spmic, SPMI_CMD_EXT_READL, sid, |
67b563f1f spmi: pmic_arb: a... |
460 |
(per << 8) + reg, buf, len)) |
02abec361 spmi: pmic-arb: r... |
461 462 |
dev_err_ratelimited(&pmic_arb->spmic->dev, "failed irqchip transaction on %x ", |
67b563f1f spmi: pmic_arb: a... |
463 464 |
d->irq); } |
02abec361 spmi: pmic-arb: r... |
465 |
static void cleanup_irq(struct spmi_pmic_arb *pmic_arb, u16 apid, int id) |
6bc546e71 spmi: pmic-arb: c... |
466 |
{ |
02abec361 spmi: pmic-arb: r... |
467 |
u16 ppid = pmic_arb->apid_data[apid].ppid; |
6bc546e71 spmi: pmic-arb: c... |
468 469 470 |
u8 sid = ppid >> 8; u8 per = ppid & 0xFF; u8 irq_mask = BIT(id); |
e95d073c8 spmi: pmic-arb: r... |
471 |
writel_relaxed(irq_mask, pmic_arb->ver_ops->irq_clear(pmic_arb, apid)); |
6bc546e71 spmi: pmic-arb: c... |
472 |
|
02abec361 spmi: pmic-arb: r... |
473 |
if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid, |
6bc546e71 spmi: pmic-arb: c... |
474 |
(per << 8) + QPNPINT_REG_LATCHED_CLR, &irq_mask, 1)) |
02abec361 spmi: pmic-arb: r... |
475 476 |
dev_err_ratelimited(&pmic_arb->spmic->dev, "failed to ack irq_mask = 0x%x for ppid = %x ", |
6bc546e71 spmi: pmic-arb: c... |
477 |
irq_mask, ppid); |
02abec361 spmi: pmic-arb: r... |
478 |
if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid, |
6bc546e71 spmi: pmic-arb: c... |
479 |
(per << 8) + QPNPINT_REG_EN_CLR, &irq_mask, 1)) |
02abec361 spmi: pmic-arb: r... |
480 481 |
dev_err_ratelimited(&pmic_arb->spmic->dev, "failed to ack irq_mask = 0x%x for ppid = %x ", |
6bc546e71 spmi: pmic-arb: c... |
482 483 |
irq_mask, ppid); } |
02abec361 spmi: pmic-arb: r... |
484 |
static void periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid) |
67b563f1f spmi: pmic_arb: a... |
485 486 487 488 |
{ unsigned int irq; u32 status; int id; |
02abec361 spmi: pmic-arb: r... |
489 490 |
u8 sid = (pmic_arb->apid_data[apid].ppid >> 8) & 0xF; u8 per = pmic_arb->apid_data[apid].ppid & 0xFF; |
67b563f1f spmi: pmic_arb: a... |
491 |
|
e95d073c8 spmi: pmic-arb: r... |
492 |
status = readl_relaxed(pmic_arb->ver_ops->irq_status(pmic_arb, apid)); |
67b563f1f spmi: pmic_arb: a... |
493 494 |
while (status) { id = ffs(status) - 1; |
111a10bf3 spmi: pmic-arb: r... |
495 |
status &= ~BIT(id); |
02abec361 spmi: pmic-arb: r... |
496 497 |
irq = irq_find_mapping(pmic_arb->domain, spec_to_hwirq(sid, per, id, apid)); |
6bc546e71 spmi: pmic-arb: c... |
498 |
if (irq == 0) { |
02abec361 spmi: pmic-arb: r... |
499 |
cleanup_irq(pmic_arb, apid, id); |
6bc546e71 spmi: pmic-arb: c... |
500 501 |
continue; } |
67b563f1f spmi: pmic_arb: a... |
502 503 504 |
generic_handle_irq(irq); } } |
bd0b9ac40 genirq: Remove ir... |
505 |
static void pmic_arb_chained_irq(struct irq_desc *desc) |
67b563f1f spmi: pmic_arb: a... |
506 |
{ |
02abec361 spmi: pmic-arb: r... |
507 |
struct spmi_pmic_arb *pmic_arb = irq_desc_get_handler_data(desc); |
e95d073c8 spmi: pmic-arb: r... |
508 |
const struct pmic_arb_ver_ops *ver_ops = pmic_arb->ver_ops; |
7fe88f3c0 spmi/pmic: Use ir... |
509 |
struct irq_chip *chip = irq_desc_get_chip(desc); |
02abec361 spmi: pmic-arb: r... |
510 511 |
int first = pmic_arb->min_apid >> 5; int last = pmic_arb->max_apid >> 5; |
e95d073c8 spmi: pmic-arb: r... |
512 |
u8 ee = pmic_arb->ee; |
472eaf8be spmi: pmic-arb: c... |
513 514 |
u32 status, enable; int i, id, apid; |
67b563f1f spmi: pmic_arb: a... |
515 516 517 518 |
chained_irq_enter(chip, desc); for (i = first; i <= last; ++i) { |
e95d073c8 spmi: pmic-arb: r... |
519 520 |
status = readl_relaxed( ver_ops->owner_acc_status(pmic_arb, ee, i)); |
67b563f1f spmi: pmic_arb: a... |
521 522 |
while (status) { id = ffs(status) - 1; |
111a10bf3 spmi: pmic-arb: r... |
523 |
status &= ~BIT(id); |
472eaf8be spmi: pmic-arb: c... |
524 |
apid = id + i * 32; |
e95d073c8 spmi: pmic-arb: r... |
525 526 |
enable = readl_relaxed( ver_ops->acc_enable(pmic_arb, apid)); |
472eaf8be spmi: pmic-arb: c... |
527 |
if (enable & SPMI_PIC_ACC_ENABLE_BIT) |
02abec361 spmi: pmic-arb: r... |
528 |
periph_interrupt(pmic_arb, apid); |
67b563f1f spmi: pmic_arb: a... |
529 530 531 532 533 534 535 536 |
} } chained_irq_exit(chip, desc); } static void qpnpint_irq_ack(struct irq_data *d) { |
02abec361 spmi: pmic-arb: r... |
537 538 539 |
struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); u8 irq = hwirq_to_irq(d->hwirq); u16 apid = hwirq_to_apid(d->hwirq); |
67b563f1f spmi: pmic_arb: a... |
540 |
u8 data; |
e95d073c8 spmi: pmic-arb: r... |
541 |
writel_relaxed(BIT(irq), pmic_arb->ver_ops->irq_clear(pmic_arb, apid)); |
67b563f1f spmi: pmic_arb: a... |
542 |
|
111a10bf3 spmi: pmic-arb: r... |
543 |
data = BIT(irq); |
67b563f1f spmi: pmic_arb: a... |
544 545 546 547 548 |
qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1); } static void qpnpint_irq_mask(struct irq_data *d) { |
02abec361 spmi: pmic-arb: r... |
549 |
u8 irq = hwirq_to_irq(d->hwirq); |
6bc546e71 spmi: pmic-arb: c... |
550 |
u8 data = BIT(irq); |
67b563f1f spmi: pmic_arb: a... |
551 |
|
67b563f1f spmi: pmic_arb: a... |
552 553 554 555 556 |
qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1); } static void qpnpint_irq_unmask(struct irq_data *d) { |
02abec361 spmi: pmic-arb: r... |
557 |
struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); |
e95d073c8 spmi: pmic-arb: r... |
558 |
const struct pmic_arb_ver_ops *ver_ops = pmic_arb->ver_ops; |
02abec361 spmi: pmic-arb: r... |
559 560 |
u8 irq = hwirq_to_irq(d->hwirq); u16 apid = hwirq_to_apid(d->hwirq); |
cee0fad77 spmi: pmic-arb: c... |
561 |
u8 buf[2]; |
67b563f1f spmi: pmic_arb: a... |
562 |
|
6bc546e71 spmi: pmic-arb: c... |
563 |
writel_relaxed(SPMI_PIC_ACC_ENABLE_BIT, |
e95d073c8 spmi: pmic-arb: r... |
564 |
ver_ops->acc_enable(pmic_arb, apid)); |
67b563f1f spmi: pmic_arb: a... |
565 |
|
cee0fad77 spmi: pmic-arb: c... |
566 567 568 569 570 571 572 573 574 575 576 |
qpnpint_spmi_read(d, QPNPINT_REG_EN_SET, &buf[0], 1); if (!(buf[0] & BIT(irq))) { /* * Since the interrupt is currently disabled, write to both the * LATCHED_CLR and EN_SET registers so that a spurious interrupt * cannot be triggered when the interrupt is enabled */ buf[0] = BIT(irq); buf[1] = BIT(irq); qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &buf, 2); } |
67b563f1f spmi: pmic_arb: a... |
577 |
} |
67b563f1f spmi: pmic_arb: a... |
578 579 580 |
static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) { struct spmi_pmic_arb_qpnpint_type type; |
325255bc9 spmi: pmic-arb: o... |
581 |
irq_flow_handler_t flow_handler; |
02abec361 spmi: pmic-arb: r... |
582 |
u8 irq = hwirq_to_irq(d->hwirq); |
67b563f1f spmi: pmic_arb: a... |
583 584 585 586 |
qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { |
325255bc9 spmi: pmic-arb: o... |
587 |
type.type |= BIT(irq); |
67b563f1f spmi: pmic_arb: a... |
588 |
if (flow_type & IRQF_TRIGGER_RISING) |
325255bc9 spmi: pmic-arb: o... |
589 |
type.polarity_high |= BIT(irq); |
67b563f1f spmi: pmic_arb: a... |
590 |
if (flow_type & IRQF_TRIGGER_FALLING) |
325255bc9 spmi: pmic-arb: o... |
591 592 593 |
type.polarity_low |= BIT(irq); flow_handler = handle_edge_irq; |
67b563f1f spmi: pmic_arb: a... |
594 595 596 597 |
} else { if ((flow_type & (IRQF_TRIGGER_HIGH)) && (flow_type & (IRQF_TRIGGER_LOW))) return -EINVAL; |
325255bc9 spmi: pmic-arb: o... |
598 |
type.type &= ~BIT(irq); /* level trig */ |
67b563f1f spmi: pmic_arb: a... |
599 |
if (flow_type & IRQF_TRIGGER_HIGH) |
325255bc9 spmi: pmic-arb: o... |
600 |
type.polarity_high |= BIT(irq); |
67b563f1f spmi: pmic_arb: a... |
601 |
else |
325255bc9 spmi: pmic-arb: o... |
602 603 604 |
type.polarity_low |= BIT(irq); flow_handler = handle_level_irq; |
67b563f1f spmi: pmic_arb: a... |
605 606 607 |
} qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); |
325255bc9 spmi: pmic-arb: o... |
608 |
irq_set_handler_locked(d, flow_handler); |
5f9b2ea3d spmi: pmic_arb: u... |
609 |
|
67b563f1f spmi: pmic_arb: a... |
610 611 |
return 0; } |
cdeef07a8 spmi: pmic-arb: u... |
612 613 614 615 616 617 |
static int qpnpint_irq_set_wake(struct irq_data *d, unsigned int on) { struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); return irq_set_irq_wake(pmic_arb->irq, on); } |
60be42306 spmi: pmic-arb: a... |
618 619 620 621 |
static int qpnpint_get_irqchip_state(struct irq_data *d, enum irqchip_irq_state which, bool *state) { |
02abec361 spmi: pmic-arb: r... |
622 |
u8 irq = hwirq_to_irq(d->hwirq); |
60be42306 spmi: pmic-arb: a... |
623 624 625 626 627 628 629 630 631 632 |
u8 status = 0; if (which != IRQCHIP_STATE_LINE_LEVEL) return -EINVAL; qpnpint_spmi_read(d, QPNPINT_REG_RT_STS, &status, 1); *state = !!(status & BIT(irq)); return 0; } |
12a9eeaeb spmi: pmic-arb: c... |
633 634 |
static int qpnpint_irq_domain_activate(struct irq_domain *domain, struct irq_data *d, bool reserve) |
2fb4f2581 spmi: pmic-arb: M... |
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 |
{ struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); u16 periph = hwirq_to_per(d->hwirq); u16 apid = hwirq_to_apid(d->hwirq); u16 sid = hwirq_to_sid(d->hwirq); u16 irq = hwirq_to_irq(d->hwirq); if (pmic_arb->apid_data[apid].irq_ee != pmic_arb->ee) { dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u ", sid, periph, irq, pmic_arb->ee, pmic_arb->apid_data[apid].irq_ee); return -ENODEV; } return 0; } |
67b563f1f spmi: pmic_arb: a... |
652 653 |
static struct irq_chip pmic_arb_irqchip = { .name = "pmic_arb", |
67b563f1f spmi: pmic_arb: a... |
654 655 656 657 |
.irq_ack = qpnpint_irq_ack, .irq_mask = qpnpint_irq_mask, .irq_unmask = qpnpint_irq_unmask, .irq_set_type = qpnpint_irq_set_type, |
cdeef07a8 spmi: pmic-arb: u... |
658 |
.irq_set_wake = qpnpint_irq_set_wake, |
60be42306 spmi: pmic-arb: a... |
659 |
.irq_get_irqchip_state = qpnpint_get_irqchip_state, |
cdeef07a8 spmi: pmic-arb: u... |
660 |
.flags = IRQCHIP_MASK_ON_SUSPEND, |
67b563f1f spmi: pmic_arb: a... |
661 |
}; |
12a9eeaeb spmi: pmic-arb: c... |
662 663 664 665 |
static int qpnpint_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *out_hwirq, unsigned int *out_type) |
67b563f1f spmi: pmic_arb: a... |
666 |
{ |
02abec361 spmi: pmic-arb: r... |
667 |
struct spmi_pmic_arb *pmic_arb = d->host_data; |
12a9eeaeb spmi: pmic-arb: c... |
668 |
u32 *intspec = fwspec->param; |
ff615ed91 spmi: pmic-arb: r... |
669 |
u16 apid, ppid; |
7f1d4e58d spmi: pmic-arb: o... |
670 |
int rc; |
67b563f1f spmi: pmic_arb: a... |
671 |
|
02abec361 spmi: pmic-arb: r... |
672 673 |
dev_dbg(&pmic_arb->spmic->dev, "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x ", |
67b563f1f spmi: pmic_arb: a... |
674 |
intspec[0], intspec[1], intspec[2]); |
12a9eeaeb spmi: pmic-arb: c... |
675 |
if (irq_domain_get_of_node(d) != pmic_arb->spmic->dev.of_node) |
67b563f1f spmi: pmic_arb: a... |
676 |
return -EINVAL; |
12a9eeaeb spmi: pmic-arb: c... |
677 |
if (fwspec->param_count != 4) |
67b563f1f spmi: pmic_arb: a... |
678 679 680 |
return -EINVAL; if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7) return -EINVAL; |
ff615ed91 spmi: pmic-arb: r... |
681 682 |
ppid = intspec[0] << 8 | intspec[1]; rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, ppid); |
7f1d4e58d spmi: pmic-arb: o... |
683 |
if (rc < 0) { |
40f318f0e spmi: pmic-arb: a... |
684 685 |
dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u rc = %d ", |
7f1d4e58d spmi: pmic-arb: o... |
686 687 688 |
intspec[0], intspec[1], intspec[2], rc); return rc; } |
67b563f1f spmi: pmic_arb: a... |
689 |
|
ff615ed91 spmi: pmic-arb: r... |
690 |
apid = rc; |
67b563f1f spmi: pmic_arb: a... |
691 |
/* Keep track of {max,min}_apid for bounding search during interrupt */ |
02abec361 spmi: pmic-arb: r... |
692 693 694 695 |
if (apid > pmic_arb->max_apid) pmic_arb->max_apid = apid; if (apid < pmic_arb->min_apid) pmic_arb->min_apid = apid; |
67b563f1f spmi: pmic_arb: a... |
696 |
|
02abec361 spmi: pmic-arb: r... |
697 |
*out_hwirq = spec_to_hwirq(intspec[0], intspec[1], intspec[2], apid); |
67b563f1f spmi: pmic_arb: a... |
698 |
*out_type = intspec[3] & IRQ_TYPE_SENSE_MASK; |
02abec361 spmi: pmic-arb: r... |
699 700 |
dev_dbg(&pmic_arb->spmic->dev, "out_hwirq = %lu ", *out_hwirq); |
67b563f1f spmi: pmic_arb: a... |
701 702 703 |
return 0; } |
2d5a2f913 spmi: pmic-arb: S... |
704 |
static struct lock_class_key qpnpint_irq_lock_class, qpnpint_irq_request_class; |
12a9eeaeb spmi: pmic-arb: c... |
705 |
|
25655c753 spmi: pmic-arb: r... |
706 707 708 |
static void qpnpint_irq_domain_map(struct spmi_pmic_arb *pmic_arb, struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq, unsigned int type) |
67b563f1f spmi: pmic_arb: a... |
709 |
{ |
12a9eeaeb spmi: pmic-arb: c... |
710 711 712 713 714 715 716 717 |
irq_flow_handler_t handler; dev_dbg(&pmic_arb->spmic->dev, "virq = %u, hwirq = %lu, type = %u ", virq, hwirq, type); if (type & IRQ_TYPE_EDGE_BOTH) handler = handle_edge_irq; |
135ef21ab spmi: pmic-arb: v... |
718 |
else |
25655c753 spmi: pmic-arb: r... |
719 |
handler = handle_level_irq; |
12a9eeaeb spmi: pmic-arb: c... |
720 |
|
2d5a2f913 spmi: pmic-arb: S... |
721 722 723 |
irq_set_lockdep_class(virq, &qpnpint_irq_lock_class, &qpnpint_irq_request_class); |
12a9eeaeb spmi: pmic-arb: c... |
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 |
irq_domain_set_info(domain, virq, hwirq, &pmic_arb_irqchip, pmic_arb, handler, NULL, NULL); } static int qpnpint_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *data) { struct spmi_pmic_arb *pmic_arb = domain->host_data; struct irq_fwspec *fwspec = data; irq_hw_number_t hwirq; unsigned int type; int ret, i; ret = qpnpint_irq_domain_translate(domain, fwspec, &hwirq, &type); if (ret) return ret; |
67b563f1f spmi: pmic_arb: a... |
741 |
|
25655c753 spmi: pmic-arb: r... |
742 743 744 |
for (i = 0; i < nr_irqs; i++) qpnpint_irq_domain_map(pmic_arb, domain, virq + i, hwirq + i, type); |
67b563f1f spmi: pmic_arb: a... |
745 |
|
67b563f1f spmi: pmic_arb: a... |
746 747 |
return 0; } |
ff615ed91 spmi: pmic-arb: r... |
748 |
static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pmic_arb, u16 ppid) |
7f1d4e58d spmi: pmic-arb: o... |
749 |
{ |
02abec361 spmi: pmic-arb: r... |
750 |
u32 *mapping_table = pmic_arb->mapping_table; |
7f1d4e58d spmi: pmic-arb: o... |
751 752 |
int index = 0, i; u16 apid_valid; |
ff615ed91 spmi: pmic-arb: r... |
753 |
u16 apid; |
7f1d4e58d spmi: pmic-arb: o... |
754 |
u32 data; |
02abec361 spmi: pmic-arb: r... |
755 756 |
apid_valid = pmic_arb->ppid_to_apid[ppid]; if (apid_valid & PMIC_ARB_APID_VALID) { |
ff615ed91 spmi: pmic-arb: r... |
757 758 |
apid = apid_valid & ~PMIC_ARB_APID_VALID; return apid; |
7f1d4e58d spmi: pmic-arb: o... |
759 760 761 |
} for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) { |
02abec361 spmi: pmic-arb: r... |
762 763 |
if (!test_and_set_bit(index, pmic_arb->mapping_table_valid)) mapping_table[index] = readl_relaxed(pmic_arb->cnfg + |
7f1d4e58d spmi: pmic-arb: o... |
764 765 766 767 768 769 770 771 |
SPMI_MAPPING_TABLE_REG(index)); data = mapping_table[index]; if (ppid & BIT(SPMI_MAPPING_BIT_INDEX(data))) { if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) { index = SPMI_MAPPING_BIT_IS_1_RESULT(data); } else { |
ff615ed91 spmi: pmic-arb: r... |
772 |
apid = SPMI_MAPPING_BIT_IS_1_RESULT(data); |
02abec361 spmi: pmic-arb: r... |
773 |
pmic_arb->ppid_to_apid[ppid] |
ff615ed91 spmi: pmic-arb: r... |
774 775 776 |
= apid | PMIC_ARB_APID_VALID; pmic_arb->apid_data[apid].ppid = ppid; return apid; |
7f1d4e58d spmi: pmic-arb: o... |
777 778 779 780 781 |
} } else { if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) { index = SPMI_MAPPING_BIT_IS_0_RESULT(data); } else { |
ff615ed91 spmi: pmic-arb: r... |
782 |
apid = SPMI_MAPPING_BIT_IS_0_RESULT(data); |
02abec361 spmi: pmic-arb: r... |
783 |
pmic_arb->ppid_to_apid[ppid] |
ff615ed91 spmi: pmic-arb: r... |
784 785 786 |
= apid | PMIC_ARB_APID_VALID; pmic_arb->apid_data[apid].ppid = ppid; return apid; |
7f1d4e58d spmi: pmic-arb: o... |
787 788 789 790 791 792 |
} } } return -ENODEV; } |
d0c6ae41d spmi: pmic_arb: a... |
793 |
/* v1 offset per ee */ |
40f318f0e spmi: pmic-arb: a... |
794 795 |
static int pmic_arb_offset_v1(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, enum pmic_arb_channel ch_type) |
d0c6ae41d spmi: pmic_arb: a... |
796 |
{ |
ff615ed91 spmi: pmic-arb: r... |
797 |
return 0x800 + 0x80 * pmic_arb->channel; |
987a9f128 spmi: pmic-arb: S... |
798 |
} |
02abec361 spmi: pmic-arb: r... |
799 |
static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid) |
987a9f128 spmi: pmic-arb: S... |
800 |
{ |
f2f315647 spmi: pmic-arb: c... |
801 |
struct apid_data *apidd = &pmic_arb->apid_data[pmic_arb->last_apid]; |
987a9f128 spmi: pmic-arb: S... |
802 |
u32 regval, offset; |
f2f315647 spmi: pmic-arb: c... |
803 |
u16 id, apid; |
987a9f128 spmi: pmic-arb: S... |
804 |
|
f2f315647 spmi: pmic-arb: c... |
805 |
for (apid = pmic_arb->last_apid; ; apid++, apidd++) { |
40f318f0e spmi: pmic-arb: a... |
806 |
offset = pmic_arb->ver_ops->apid_map_offset(apid); |
02abec361 spmi: pmic-arb: r... |
807 |
if (offset >= pmic_arb->core_size) |
987a9f128 spmi: pmic-arb: S... |
808 |
break; |
02abec361 spmi: pmic-arb: r... |
809 |
regval = readl_relaxed(pmic_arb->cnfg + |
b319b5922 spmi: pmic-arb: r... |
810 |
SPMI_OWNERSHIP_TABLE_REG(apid)); |
40f318f0e spmi: pmic-arb: a... |
811 812 |
apidd->irq_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval); apidd->write_ee = apidd->irq_ee; |
b319b5922 spmi: pmic-arb: r... |
813 |
|
02abec361 spmi: pmic-arb: r... |
814 |
regval = readl_relaxed(pmic_arb->core + offset); |
987a9f128 spmi: pmic-arb: S... |
815 816 817 818 |
if (!regval) continue; id = (regval >> 8) & PMIC_ARB_PPID_MASK; |
02abec361 spmi: pmic-arb: r... |
819 |
pmic_arb->ppid_to_apid[id] = apid | PMIC_ARB_APID_VALID; |
f2f315647 spmi: pmic-arb: c... |
820 |
apidd->ppid = id; |
987a9f128 spmi: pmic-arb: S... |
821 |
if (id == ppid) { |
02abec361 spmi: pmic-arb: r... |
822 |
apid |= PMIC_ARB_APID_VALID; |
987a9f128 spmi: pmic-arb: S... |
823 824 825 |
break; } } |
02abec361 spmi: pmic-arb: r... |
826 |
pmic_arb->last_apid = apid & ~PMIC_ARB_APID_VALID; |
987a9f128 spmi: pmic-arb: S... |
827 |
|
1ef1ce4e9 spmi: pmic-arb: f... |
828 |
return apid; |
d0c6ae41d spmi: pmic_arb: a... |
829 |
} |
ff615ed91 spmi: pmic-arb: r... |
830 |
static int pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pmic_arb, u16 ppid) |
57102ad79 spmi: pmic_arb: b... |
831 |
{ |
7f1d4e58d spmi: pmic-arb: o... |
832 |
u16 apid_valid; |
57102ad79 spmi: pmic_arb: b... |
833 |
|
02abec361 spmi: pmic-arb: r... |
834 835 836 837 |
apid_valid = pmic_arb->ppid_to_apid[ppid]; if (!(apid_valid & PMIC_ARB_APID_VALID)) apid_valid = pmic_arb_find_apid(pmic_arb, ppid); if (!(apid_valid & PMIC_ARB_APID_VALID)) |
57102ad79 spmi: pmic_arb: b... |
838 |
return -ENODEV; |
ff615ed91 spmi: pmic-arb: r... |
839 |
return apid_valid & ~PMIC_ARB_APID_VALID; |
7f1d4e58d spmi: pmic-arb: o... |
840 |
} |
40f318f0e spmi: pmic-arb: a... |
841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 |
static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb) { struct apid_data *apidd = pmic_arb->apid_data; struct apid_data *prev_apidd; u16 i, apid, ppid; bool valid, is_irq_ee; u32 regval, offset; /* * In order to allow multiple EEs to write to a single PPID in arbiter * version 5, there is more than one APID mapped to each PPID. * The owner field for each of these mappings specifies the EE which is * allowed to write to the APID. The owner of the last (highest) APID * for a given PPID will receive interrupts from the PPID. */ for (i = 0; ; i++, apidd++) { offset = pmic_arb->ver_ops->apid_map_offset(i); if (offset >= pmic_arb->core_size) break; regval = readl_relaxed(pmic_arb->core + offset); if (!regval) continue; ppid = (regval >> 8) & PMIC_ARB_PPID_MASK; is_irq_ee = PMIC_ARB_CHAN_IS_IRQ_OWNER(regval); regval = readl_relaxed(pmic_arb->cnfg + SPMI_OWNERSHIP_TABLE_REG(i)); apidd->write_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval); apidd->irq_ee = is_irq_ee ? apidd->write_ee : INVALID_EE; valid = pmic_arb->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID; apid = pmic_arb->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID; prev_apidd = &pmic_arb->apid_data[apid]; if (valid && is_irq_ee && prev_apidd->write_ee == pmic_arb->ee) { /* * Duplicate PPID mapping after the one for this EE; * override the irq owner */ prev_apidd->irq_ee = apidd->irq_ee; } else if (!valid || is_irq_ee) { /* First PPID mapping or duplicate for another EE */ pmic_arb->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID; } apidd->ppid = ppid; pmic_arb->last_apid = i; } /* Dump the mapping table for debug purposes. */ dev_dbg(&pmic_arb->spmic->dev, "PPID APID Write-EE IRQ-EE "); for (ppid = 0; ppid < PMIC_ARB_MAX_PPID; ppid++) { apid = pmic_arb->ppid_to_apid[ppid]; if (apid & PMIC_ARB_APID_VALID) { apid &= ~PMIC_ARB_APID_VALID; apidd = &pmic_arb->apid_data[apid]; dev_dbg(&pmic_arb->spmic->dev, "%#03X %3u %2u %2u ", ppid, apid, apidd->write_ee, apidd->irq_ee); } } return 0; } static int pmic_arb_ppid_to_apid_v5(struct spmi_pmic_arb *pmic_arb, u16 ppid) { if (!(pmic_arb->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID)) return -ENODEV; return pmic_arb->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID; } |
1ef1ce4e9 spmi: pmic-arb: f... |
917 |
/* v2 offset per ppid and per ee */ |
40f318f0e spmi: pmic-arb: a... |
918 919 |
static int pmic_arb_offset_v2(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, enum pmic_arb_channel ch_type) |
d0c6ae41d spmi: pmic_arb: a... |
920 |
{ |
319f68843 spmi: pmic_arb: a... |
921 |
u16 apid; |
ff615ed91 spmi: pmic-arb: r... |
922 |
u16 ppid; |
7f1d4e58d spmi: pmic-arb: o... |
923 |
int rc; |
987a9f128 spmi: pmic-arb: S... |
924 |
|
ff615ed91 spmi: pmic-arb: r... |
925 926 |
ppid = sid << 8 | ((addr >> 8) & 0xFF); rc = pmic_arb_ppid_to_apid_v2(pmic_arb, ppid); |
7f1d4e58d spmi: pmic-arb: o... |
927 928 |
if (rc < 0) return rc; |
d0c6ae41d spmi: pmic_arb: a... |
929 |
|
ff615ed91 spmi: pmic-arb: r... |
930 931 |
apid = rc; return 0x1000 * pmic_arb->ee + 0x8000 * apid; |
d0c6ae41d spmi: pmic_arb: a... |
932 |
} |
40f318f0e spmi: pmic-arb: a... |
933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 |
/* * v5 offset per ee and per apid for observer channels and per apid for * read/write channels. */ static int pmic_arb_offset_v5(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, enum pmic_arb_channel ch_type) { u16 apid; int rc; u32 offset = 0; u16 ppid = (sid << 8) | (addr >> 8); rc = pmic_arb_ppid_to_apid_v5(pmic_arb, ppid); if (rc < 0) return rc; apid = rc; switch (ch_type) { case PMIC_ARB_CHANNEL_OBS: offset = 0x10000 * pmic_arb->ee + 0x80 * apid; break; case PMIC_ARB_CHANNEL_RW: offset = 0x10000 * apid; break; } return offset; } |
d0c6ae41d spmi: pmic_arb: a... |
961 962 963 964 965 966 967 968 969 |
static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc) { return (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7); } static u32 pmic_arb_fmt_cmd_v2(u8 opc, u8 sid, u16 addr, u8 bc) { return (opc << 27) | ((addr & 0xff) << 4) | (bc & 0x7); } |
e95d073c8 spmi: pmic-arb: r... |
970 971 |
static void __iomem * pmic_arb_owner_acc_status_v1(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n) |
d0c6ae41d spmi: pmic_arb: a... |
972 |
{ |
e95d073c8 spmi: pmic-arb: r... |
973 |
return pmic_arb->intr + 0x20 * m + 0x4 * n; |
d0c6ae41d spmi: pmic_arb: a... |
974 |
} |
e95d073c8 spmi: pmic-arb: r... |
975 976 |
static void __iomem * pmic_arb_owner_acc_status_v2(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n) |
d0c6ae41d spmi: pmic_arb: a... |
977 |
{ |
e95d073c8 spmi: pmic-arb: r... |
978 |
return pmic_arb->intr + 0x100000 + 0x1000 * m + 0x4 * n; |
d0c6ae41d spmi: pmic_arb: a... |
979 |
} |
e95d073c8 spmi: pmic-arb: r... |
980 981 |
static void __iomem * pmic_arb_owner_acc_status_v3(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n) |
319f68843 spmi: pmic_arb: a... |
982 |
{ |
e95d073c8 spmi: pmic-arb: r... |
983 |
return pmic_arb->intr + 0x200000 + 0x1000 * m + 0x4 * n; |
319f68843 spmi: pmic_arb: a... |
984 |
} |
e95d073c8 spmi: pmic-arb: r... |
985 |
static void __iomem * |
40f318f0e spmi: pmic-arb: a... |
986 987 988 989 990 991 |
pmic_arb_owner_acc_status_v5(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n) { return pmic_arb->intr + 0x10000 * m + 0x4 * n; } static void __iomem * |
e95d073c8 spmi: pmic-arb: r... |
992 |
pmic_arb_acc_enable_v1(struct spmi_pmic_arb *pmic_arb, u16 n) |
d0c6ae41d spmi: pmic_arb: a... |
993 |
{ |
e95d073c8 spmi: pmic-arb: r... |
994 |
return pmic_arb->intr + 0x200 + 0x4 * n; |
d0c6ae41d spmi: pmic_arb: a... |
995 |
} |
e95d073c8 spmi: pmic-arb: r... |
996 997 |
static void __iomem * pmic_arb_acc_enable_v2(struct spmi_pmic_arb *pmic_arb, u16 n) |
d0c6ae41d spmi: pmic_arb: a... |
998 |
{ |
e95d073c8 spmi: pmic-arb: r... |
999 |
return pmic_arb->intr + 0x1000 * n; |
d0c6ae41d spmi: pmic_arb: a... |
1000 |
} |
e95d073c8 spmi: pmic-arb: r... |
1001 |
static void __iomem * |
40f318f0e spmi: pmic-arb: a... |
1002 1003 1004 1005 1006 1007 |
pmic_arb_acc_enable_v5(struct spmi_pmic_arb *pmic_arb, u16 n) { return pmic_arb->wr_base + 0x100 + 0x10000 * n; } static void __iomem * |
e95d073c8 spmi: pmic-arb: r... |
1008 |
pmic_arb_irq_status_v1(struct spmi_pmic_arb *pmic_arb, u16 n) |
d0c6ae41d spmi: pmic_arb: a... |
1009 |
{ |
e95d073c8 spmi: pmic-arb: r... |
1010 |
return pmic_arb->intr + 0x600 + 0x4 * n; |
d0c6ae41d spmi: pmic_arb: a... |
1011 |
} |
e95d073c8 spmi: pmic-arb: r... |
1012 1013 |
static void __iomem * pmic_arb_irq_status_v2(struct spmi_pmic_arb *pmic_arb, u16 n) |
d0c6ae41d spmi: pmic_arb: a... |
1014 |
{ |
e95d073c8 spmi: pmic-arb: r... |
1015 |
return pmic_arb->intr + 0x4 + 0x1000 * n; |
d0c6ae41d spmi: pmic_arb: a... |
1016 |
} |
e95d073c8 spmi: pmic-arb: r... |
1017 |
static void __iomem * |
40f318f0e spmi: pmic-arb: a... |
1018 1019 1020 1021 1022 1023 |
pmic_arb_irq_status_v5(struct spmi_pmic_arb *pmic_arb, u16 n) { return pmic_arb->wr_base + 0x104 + 0x10000 * n; } static void __iomem * |
e95d073c8 spmi: pmic-arb: r... |
1024 |
pmic_arb_irq_clear_v1(struct spmi_pmic_arb *pmic_arb, u16 n) |
d0c6ae41d spmi: pmic_arb: a... |
1025 |
{ |
e95d073c8 spmi: pmic-arb: r... |
1026 |
return pmic_arb->intr + 0xA00 + 0x4 * n; |
d0c6ae41d spmi: pmic_arb: a... |
1027 |
} |
e95d073c8 spmi: pmic-arb: r... |
1028 1029 |
static void __iomem * pmic_arb_irq_clear_v2(struct spmi_pmic_arb *pmic_arb, u16 n) |
d0c6ae41d spmi: pmic_arb: a... |
1030 |
{ |
e95d073c8 spmi: pmic-arb: r... |
1031 |
return pmic_arb->intr + 0x8 + 0x1000 * n; |
d0c6ae41d spmi: pmic_arb: a... |
1032 |
} |
40f318f0e spmi: pmic-arb: a... |
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 |
static void __iomem * pmic_arb_irq_clear_v5(struct spmi_pmic_arb *pmic_arb, u16 n) { return pmic_arb->wr_base + 0x108 + 0x10000 * n; } static u32 pmic_arb_apid_map_offset_v2(u16 n) { return 0x800 + 0x4 * n; } static u32 pmic_arb_apid_map_offset_v5(u16 n) { return 0x900 + 0x4 * n; } |
d0c6ae41d spmi: pmic_arb: a... |
1048 |
static const struct pmic_arb_ver_ops pmic_arb_v1 = { |
319f68843 spmi: pmic_arb: a... |
1049 |
.ver_str = "v1", |
7f1d4e58d spmi: pmic-arb: o... |
1050 |
.ppid_to_apid = pmic_arb_ppid_to_apid_v1, |
d0c6ae41d spmi: pmic_arb: a... |
1051 1052 1053 1054 1055 1056 1057 |
.non_data_cmd = pmic_arb_non_data_cmd_v1, .offset = pmic_arb_offset_v1, .fmt_cmd = pmic_arb_fmt_cmd_v1, .owner_acc_status = pmic_arb_owner_acc_status_v1, .acc_enable = pmic_arb_acc_enable_v1, .irq_status = pmic_arb_irq_status_v1, .irq_clear = pmic_arb_irq_clear_v1, |
40f318f0e spmi: pmic-arb: a... |
1058 |
.apid_map_offset = pmic_arb_apid_map_offset_v2, |
d0c6ae41d spmi: pmic_arb: a... |
1059 1060 1061 |
}; static const struct pmic_arb_ver_ops pmic_arb_v2 = { |
319f68843 spmi: pmic_arb: a... |
1062 |
.ver_str = "v2", |
7f1d4e58d spmi: pmic-arb: o... |
1063 |
.ppid_to_apid = pmic_arb_ppid_to_apid_v2, |
d0c6ae41d spmi: pmic_arb: a... |
1064 1065 1066 1067 1068 1069 1070 |
.non_data_cmd = pmic_arb_non_data_cmd_v2, .offset = pmic_arb_offset_v2, .fmt_cmd = pmic_arb_fmt_cmd_v2, .owner_acc_status = pmic_arb_owner_acc_status_v2, .acc_enable = pmic_arb_acc_enable_v2, .irq_status = pmic_arb_irq_status_v2, .irq_clear = pmic_arb_irq_clear_v2, |
40f318f0e spmi: pmic-arb: a... |
1071 |
.apid_map_offset = pmic_arb_apid_map_offset_v2, |
d0c6ae41d spmi: pmic_arb: a... |
1072 |
}; |
319f68843 spmi: pmic_arb: a... |
1073 1074 1075 |
static const struct pmic_arb_ver_ops pmic_arb_v3 = { .ver_str = "v3", .ppid_to_apid = pmic_arb_ppid_to_apid_v2, |
319f68843 spmi: pmic_arb: a... |
1076 1077 1078 1079 1080 1081 1082 |
.non_data_cmd = pmic_arb_non_data_cmd_v2, .offset = pmic_arb_offset_v2, .fmt_cmd = pmic_arb_fmt_cmd_v2, .owner_acc_status = pmic_arb_owner_acc_status_v3, .acc_enable = pmic_arb_acc_enable_v2, .irq_status = pmic_arb_irq_status_v2, .irq_clear = pmic_arb_irq_clear_v2, |
40f318f0e spmi: pmic-arb: a... |
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 |
.apid_map_offset = pmic_arb_apid_map_offset_v2, }; static const struct pmic_arb_ver_ops pmic_arb_v5 = { .ver_str = "v5", .ppid_to_apid = pmic_arb_ppid_to_apid_v5, .non_data_cmd = pmic_arb_non_data_cmd_v2, .offset = pmic_arb_offset_v5, .fmt_cmd = pmic_arb_fmt_cmd_v2, .owner_acc_status = pmic_arb_owner_acc_status_v5, .acc_enable = pmic_arb_acc_enable_v5, .irq_status = pmic_arb_irq_status_v5, .irq_clear = pmic_arb_irq_clear_v5, .apid_map_offset = pmic_arb_apid_map_offset_v5, |
319f68843 spmi: pmic_arb: a... |
1097 |
}; |
67b563f1f spmi: pmic_arb: a... |
1098 |
static const struct irq_domain_ops pmic_arb_irq_domain_ops = { |
12a9eeaeb spmi: pmic-arb: c... |
1099 1100 1101 1102 |
.activate = qpnpint_irq_domain_activate, .alloc = qpnpint_irq_domain_alloc, .free = irq_domain_free_irqs_common, .translate = qpnpint_irq_domain_translate, |
67b563f1f spmi: pmic_arb: a... |
1103 |
}; |
39ae93e3a spmi: Add MSM PMI... |
1104 1105 |
static int spmi_pmic_arb_probe(struct platform_device *pdev) { |
02abec361 spmi: pmic-arb: r... |
1106 |
struct spmi_pmic_arb *pmic_arb; |
39ae93e3a spmi: Add MSM PMI... |
1107 1108 |
struct spmi_controller *ctrl; struct resource *res; |
d0c6ae41d spmi: pmic_arb: a... |
1109 |
void __iomem *core; |
4788e613a spmi: pmic-arb: f... |
1110 |
u32 *mapping_table; |
d0c6ae41d spmi: pmic_arb: a... |
1111 |
u32 channel, ee, hw_ver; |
987a9f128 spmi: pmic-arb: S... |
1112 |
int err; |
39ae93e3a spmi: Add MSM PMI... |
1113 |
|
02abec361 spmi: pmic-arb: r... |
1114 |
ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pmic_arb)); |
39ae93e3a spmi: Add MSM PMI... |
1115 1116 |
if (!ctrl) return -ENOMEM; |
02abec361 spmi: pmic-arb: r... |
1117 1118 |
pmic_arb = spmi_controller_get_drvdata(ctrl); pmic_arb->spmic = ctrl; |
39ae93e3a spmi: Add MSM PMI... |
1119 1120 |
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); |
d0c6ae41d spmi: pmic_arb: a... |
1121 1122 1123 |
core = devm_ioremap_resource(&ctrl->dev, res); if (IS_ERR(core)) { err = PTR_ERR(core); |
39ae93e3a spmi: Add MSM PMI... |
1124 1125 |
goto err_put_ctrl; } |
000e1a43d spmi: pmic-arb: f... |
1126 |
pmic_arb->core_size = resource_size(res); |
02abec361 spmi: pmic-arb: r... |
1127 1128 1129 1130 |
pmic_arb->ppid_to_apid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PPID, sizeof(*pmic_arb->ppid_to_apid), GFP_KERNEL); if (!pmic_arb->ppid_to_apid) { |
eba9718ed spmi: pmic-arb: A... |
1131 1132 1133 |
err = -ENOMEM; goto err_put_ctrl; } |
d0c6ae41d spmi: pmic_arb: a... |
1134 |
hw_ver = readl_relaxed(core + PMIC_ARB_VERSION); |
d0c6ae41d spmi: pmic_arb: a... |
1135 |
|
319f68843 spmi: pmic_arb: a... |
1136 |
if (hw_ver < PMIC_ARB_VERSION_V2_MIN) { |
02abec361 spmi: pmic-arb: r... |
1137 1138 1139 |
pmic_arb->ver_ops = &pmic_arb_v1; pmic_arb->wr_base = core; pmic_arb->rd_base = core; |
d0c6ae41d spmi: pmic_arb: a... |
1140 |
} else { |
02abec361 spmi: pmic-arb: r... |
1141 |
pmic_arb->core = core; |
319f68843 spmi: pmic_arb: a... |
1142 1143 |
if (hw_ver < PMIC_ARB_VERSION_V3_MIN) |
02abec361 spmi: pmic-arb: r... |
1144 |
pmic_arb->ver_ops = &pmic_arb_v2; |
40f318f0e spmi: pmic-arb: a... |
1145 |
else if (hw_ver < PMIC_ARB_VERSION_V5_MIN) |
02abec361 spmi: pmic-arb: r... |
1146 |
pmic_arb->ver_ops = &pmic_arb_v3; |
40f318f0e spmi: pmic-arb: a... |
1147 1148 |
else pmic_arb->ver_ops = &pmic_arb_v5; |
d0c6ae41d spmi: pmic_arb: a... |
1149 1150 1151 |
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "obsrvr"); |
02abec361 spmi: pmic-arb: r... |
1152 1153 1154 |
pmic_arb->rd_base = devm_ioremap_resource(&ctrl->dev, res); if (IS_ERR(pmic_arb->rd_base)) { err = PTR_ERR(pmic_arb->rd_base); |
d0c6ae41d spmi: pmic_arb: a... |
1155 1156 1157 1158 1159 |
goto err_put_ctrl; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "chnls"); |
02abec361 spmi: pmic-arb: r... |
1160 1161 1162 |
pmic_arb->wr_base = devm_ioremap_resource(&ctrl->dev, res); if (IS_ERR(pmic_arb->wr_base)) { err = PTR_ERR(pmic_arb->wr_base); |
d0c6ae41d spmi: pmic_arb: a... |
1163 1164 |
goto err_put_ctrl; } |
d0c6ae41d spmi: pmic_arb: a... |
1165 |
} |
319f68843 spmi: pmic_arb: a... |
1166 1167 |
dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x) ", |
02abec361 spmi: pmic-arb: r... |
1168 |
pmic_arb->ver_ops->ver_str, hw_ver); |
319f68843 spmi: pmic_arb: a... |
1169 |
|
39ae93e3a spmi: Add MSM PMI... |
1170 |
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr"); |
02abec361 spmi: pmic-arb: r... |
1171 1172 1173 |
pmic_arb->intr = devm_ioremap_resource(&ctrl->dev, res); if (IS_ERR(pmic_arb->intr)) { err = PTR_ERR(pmic_arb->intr); |
39ae93e3a spmi: Add MSM PMI... |
1174 1175 1176 1177 |
goto err_put_ctrl; } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg"); |
02abec361 spmi: pmic-arb: r... |
1178 1179 1180 |
pmic_arb->cnfg = devm_ioremap_resource(&ctrl->dev, res); if (IS_ERR(pmic_arb->cnfg)) { err = PTR_ERR(pmic_arb->cnfg); |
39ae93e3a spmi: Add MSM PMI... |
1181 1182 |
goto err_put_ctrl; } |
02abec361 spmi: pmic-arb: r... |
1183 1184 1185 |
pmic_arb->irq = platform_get_irq_byname(pdev, "periph_irq"); if (pmic_arb->irq < 0) { err = pmic_arb->irq; |
67b563f1f spmi: pmic_arb: a... |
1186 1187 |
goto err_put_ctrl; } |
39ae93e3a spmi: Add MSM PMI... |
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 |
err = of_property_read_u32(pdev->dev.of_node, "qcom,channel", &channel); if (err) { dev_err(&pdev->dev, "channel unspecified. "); goto err_put_ctrl; } if (channel > 5) { dev_err(&pdev->dev, "invalid channel (%u) specified. ", channel); |
e98cc182a spmi: pmic-arb: R... |
1199 |
err = -EINVAL; |
39ae93e3a spmi: Add MSM PMI... |
1200 1201 |
goto err_put_ctrl; } |
02abec361 spmi: pmic-arb: r... |
1202 |
pmic_arb->channel = channel; |
39ae93e3a spmi: Add MSM PMI... |
1203 |
|
67b563f1f spmi: pmic_arb: a... |
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 |
err = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &ee); if (err) { dev_err(&pdev->dev, "EE unspecified. "); goto err_put_ctrl; } if (ee > 5) { dev_err(&pdev->dev, "invalid EE (%u) specified ", ee); err = -EINVAL; goto err_put_ctrl; } |
02abec361 spmi: pmic-arb: r... |
1217 |
pmic_arb->ee = ee; |
4788e613a spmi: pmic-arb: f... |
1218 1219 1220 |
mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS, sizeof(*mapping_table), GFP_KERNEL); if (!mapping_table) { |
987a9f128 spmi: pmic-arb: S... |
1221 1222 1223 |
err = -ENOMEM; goto err_put_ctrl; } |
67b563f1f spmi: pmic_arb: a... |
1224 |
|
4788e613a spmi: pmic-arb: f... |
1225 |
pmic_arb->mapping_table = mapping_table; |
67b563f1f spmi: pmic_arb: a... |
1226 1227 |
/* Initialize max_apid/min_apid to the opposite bounds, during * the irq domain translation, we are sure to update these */ |
02abec361 spmi: pmic-arb: r... |
1228 1229 |
pmic_arb->max_apid = 0; pmic_arb->min_apid = PMIC_ARB_MAX_PERIPHS - 1; |
67b563f1f spmi: pmic_arb: a... |
1230 |
|
39ae93e3a spmi: Add MSM PMI... |
1231 |
platform_set_drvdata(pdev, ctrl); |
02abec361 spmi: pmic-arb: r... |
1232 |
raw_spin_lock_init(&pmic_arb->lock); |
39ae93e3a spmi: Add MSM PMI... |
1233 1234 1235 1236 |
ctrl->cmd = pmic_arb_cmd; ctrl->read_cmd = pmic_arb_read_cmd; ctrl->write_cmd = pmic_arb_write_cmd; |
40f318f0e spmi: pmic-arb: a... |
1237 1238 1239 1240 1241 1242 1243 1244 1245 |
if (hw_ver >= PMIC_ARB_VERSION_V5_MIN) { err = pmic_arb_read_apid_map_v5(pmic_arb); if (err) { dev_err(&pdev->dev, "could not read APID->PPID mapping table, rc= %d ", err); goto err_put_ctrl; } } |
67b563f1f spmi: pmic_arb: a... |
1246 1247 |
dev_dbg(&pdev->dev, "adding irq domain "); |
02abec361 spmi: pmic-arb: r... |
1248 1249 1250 |
pmic_arb->domain = irq_domain_add_tree(pdev->dev.of_node, &pmic_arb_irq_domain_ops, pmic_arb); if (!pmic_arb->domain) { |
67b563f1f spmi: pmic_arb: a... |
1251 1252 1253 1254 1255 |
dev_err(&pdev->dev, "unable to create irq_domain "); err = -ENOMEM; goto err_put_ctrl; } |
02abec361 spmi: pmic-arb: r... |
1256 1257 |
irq_set_chained_handler_and_data(pmic_arb->irq, pmic_arb_chained_irq, pmic_arb); |
39ae93e3a spmi: Add MSM PMI... |
1258 1259 |
err = spmi_controller_add(ctrl); if (err) |
67b563f1f spmi: pmic_arb: a... |
1260 |
goto err_domain_remove; |
39ae93e3a spmi: Add MSM PMI... |
1261 |
|
39ae93e3a spmi: Add MSM PMI... |
1262 |
return 0; |
67b563f1f spmi: pmic_arb: a... |
1263 |
err_domain_remove: |
02abec361 spmi: pmic-arb: r... |
1264 1265 |
irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL); irq_domain_remove(pmic_arb->domain); |
39ae93e3a spmi: Add MSM PMI... |
1266 1267 1268 1269 1270 1271 1272 1273 |
err_put_ctrl: spmi_controller_put(ctrl); return err; } static int spmi_pmic_arb_remove(struct platform_device *pdev) { struct spmi_controller *ctrl = platform_get_drvdata(pdev); |
02abec361 spmi: pmic-arb: r... |
1274 |
struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); |
39ae93e3a spmi: Add MSM PMI... |
1275 |
spmi_controller_remove(ctrl); |
02abec361 spmi: pmic-arb: r... |
1276 1277 |
irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL); irq_domain_remove(pmic_arb->domain); |
39ae93e3a spmi: Add MSM PMI... |
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 |
spmi_controller_put(ctrl); return 0; } static const struct of_device_id spmi_pmic_arb_match_table[] = { { .compatible = "qcom,spmi-pmic-arb", }, {}, }; MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table); static struct platform_driver spmi_pmic_arb_driver = { .probe = spmi_pmic_arb_probe, .remove = spmi_pmic_arb_remove, .driver = { .name = "spmi_pmic_arb", |
39ae93e3a spmi: Add MSM PMI... |
1293 1294 1295 1296 1297 1298 1299 |
.of_match_table = spmi_pmic_arb_match_table, }, }; module_platform_driver(spmi_pmic_arb_driver); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:spmi_pmic_arb"); |