aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spmi
diff options
context:
space:
mode:
authorKenneth Heitke <kheitke@codeaurora.org>2014-02-12 14:44:24 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-02-15 14:55:28 -0500
commit39ae93e3a31d0c9ca99e35b754a9f3c6f1db2bee (patch)
tree88e35be655e440dbc3122ffdf67b1f62d3a4fc61 /drivers/spmi
parent8006c944b043d0cfa07cd8d8cccd686e30fe766d (diff)
spmi: Add MSM PMIC Arbiter SPMI controller
Qualcomm's PMIC Arbiter SPMI controller functions as a bus master and is used to communication with one or more PMIC (slave) devices on the SPMI bus. The PMIC Arbiter is actually a hardware wrapper around the SPMI controller that provides concurrent and autonomous PMIC access to various entities that need to communicate with the PMIC. The SPMI controller hardware handles all of the SPMI bus activity (bus arbitration, sequence start condition, transmission of frames, etc). This software driver uses the PMIC Arbiter register interface to initiate command sequences on the SPMI bus. The status register is read to determine when the command sequence has completed and whether or not it completed successfully. Signed-off-by: Kenneth Heitke <kheitke@codeaurora.org> Signed-off-by: Josh Cartwright <joshc@codeaurora.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/spmi')
-rw-r--r--drivers/spmi/Kconfig17
-rw-r--r--drivers/spmi/Makefile2
-rw-r--r--drivers/spmi/spmi-pmic-arb.c405
3 files changed, 424 insertions, 0 deletions
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index 1dbfee022e90..80b79013fd1e 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -7,3 +7,20 @@ menuconfig SPMI
7 SPMI (System Power Management Interface) is a two-wire 7 SPMI (System Power Management Interface) is a two-wire
8 serial interface between baseband and application processors 8 serial interface between baseband and application processors
9 and Power Management Integrated Circuits (PMIC). 9 and Power Management Integrated Circuits (PMIC).
10
11if SPMI
12
13config SPMI_MSM_PMIC_ARB
14 tristate "Qualcomm MSM SPMI Controller (PMIC Arbiter)"
15 depends on ARM
16 depends on ARCH_MSM || COMPILE_TEST
17 default ARCH_MSM
18 help
19 If you say yes to this option, support will be included for the
20 built-in SPMI PMIC Arbiter interface on Qualcomm MSM family
21 processors.
22
23 This is required for communicating with Qualcomm PMICs and
24 other devices that have the SPMI interface.
25
26endif
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index 1de1acd6a587..fc75104a5aab 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -2,3 +2,5 @@
2# Makefile for kernel SPMI framework. 2# Makefile for kernel SPMI framework.
3# 3#
4obj-$(CONFIG_SPMI) += spmi.o 4obj-$(CONFIG_SPMI) += spmi.o
5
6obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
new file mode 100644
index 000000000000..2dd27e8d140d
--- /dev/null
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -0,0 +1,405 @@
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>
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/platform_device.h>
20#include <linux/slab.h>
21#include <linux/spmi.h>
22
23/* PMIC Arbiter configuration registers */
24#define PMIC_ARB_VERSION 0x0000
25#define PMIC_ARB_INT_EN 0x0004
26
27/* PMIC Arbiter channel registers */
28#define PMIC_ARB_CMD(N) (0x0800 + (0x80 * (N)))
29#define PMIC_ARB_CONFIG(N) (0x0804 + (0x80 * (N)))
30#define PMIC_ARB_STATUS(N) (0x0808 + (0x80 * (N)))
31#define PMIC_ARB_WDATA0(N) (0x0810 + (0x80 * (N)))
32#define PMIC_ARB_WDATA1(N) (0x0814 + (0x80 * (N)))
33#define PMIC_ARB_RDATA0(N) (0x0818 + (0x80 * (N)))
34#define PMIC_ARB_RDATA1(N) (0x081C + (0x80 * (N)))
35
36/* Interrupt Controller */
37#define SPMI_PIC_OWNER_ACC_STATUS(M, N) (0x0000 + ((32 * (M)) + (4 * (N))))
38#define SPMI_PIC_ACC_ENABLE(N) (0x0200 + (4 * (N)))
39#define SPMI_PIC_IRQ_STATUS(N) (0x0600 + (4 * (N)))
40#define SPMI_PIC_IRQ_CLEAR(N) (0x0A00 + (4 * (N)))
41
42/* Mapping Table */
43#define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N)))
44#define SPMI_MAPPING_BIT_INDEX(X) (((X) >> 18) & 0xF)
45#define SPMI_MAPPING_BIT_IS_0_FLAG(X) (((X) >> 17) & 0x1)
46#define SPMI_MAPPING_BIT_IS_0_RESULT(X) (((X) >> 9) & 0xFF)
47#define SPMI_MAPPING_BIT_IS_1_FLAG(X) (((X) >> 8) & 0x1)
48#define SPMI_MAPPING_BIT_IS_1_RESULT(X) (((X) >> 0) & 0xFF)
49
50#define SPMI_MAPPING_TABLE_LEN 255
51#define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */
52
53/* Ownership Table */
54#define SPMI_OWNERSHIP_TABLE_REG(N) (0x0700 + (4 * (N)))
55#define SPMI_OWNERSHIP_PERIPH2OWNER(X) ((X) & 0x7)
56
57/* Channel Status fields */
58enum pmic_arb_chnl_status {
59 PMIC_ARB_STATUS_DONE = (1 << 0),
60 PMIC_ARB_STATUS_FAILURE = (1 << 1),
61 PMIC_ARB_STATUS_DENIED = (1 << 2),
62 PMIC_ARB_STATUS_DROPPED = (1 << 3),
63};
64
65/* Command register fields */
66#define PMIC_ARB_CMD_MAX_BYTE_COUNT 8
67
68/* Command Opcodes */
69enum pmic_arb_cmd_op_code {
70 PMIC_ARB_OP_EXT_WRITEL = 0,
71 PMIC_ARB_OP_EXT_READL = 1,
72 PMIC_ARB_OP_EXT_WRITE = 2,
73 PMIC_ARB_OP_RESET = 3,
74 PMIC_ARB_OP_SLEEP = 4,
75 PMIC_ARB_OP_SHUTDOWN = 5,
76 PMIC_ARB_OP_WAKEUP = 6,
77 PMIC_ARB_OP_AUTHENTICATE = 7,
78 PMIC_ARB_OP_MSTR_READ = 8,
79 PMIC_ARB_OP_MSTR_WRITE = 9,
80 PMIC_ARB_OP_EXT_READ = 13,
81 PMIC_ARB_OP_WRITE = 14,
82 PMIC_ARB_OP_READ = 15,
83 PMIC_ARB_OP_ZERO_WRITE = 16,
84};
85
86/* Maximum number of support PMIC peripherals */
87#define PMIC_ARB_MAX_PERIPHS 256
88#define PMIC_ARB_PERIPH_ID_VALID (1 << 15)
89#define PMIC_ARB_TIMEOUT_US 100
90#define PMIC_ARB_MAX_TRANS_BYTES (8)
91
92#define PMIC_ARB_APID_MASK 0xFF
93#define PMIC_ARB_PPID_MASK 0xFFF
94
95/* interrupt enable bit */
96#define SPMI_PIC_ACC_ENABLE_BIT BIT(0)
97
98/**
99 * spmi_pmic_arb_dev - SPMI PMIC Arbiter object
100 *
101 * @base: address of the PMIC Arbiter core registers.
102 * @intr: address of the SPMI interrupt control registers.
103 * @cnfg: address of the PMIC Arbiter configuration registers.
104 * @lock: lock to synchronize accesses.
105 * @channel: which channel to use for accesses.
106 */
107struct spmi_pmic_arb_dev {
108 void __iomem *base;
109 void __iomem *intr;
110 void __iomem *cnfg;
111 raw_spinlock_t lock;
112 u8 channel;
113};
114
115static inline u32 pmic_arb_base_read(struct spmi_pmic_arb_dev *dev, u32 offset)
116{
117 return readl_relaxed(dev->base + offset);
118}
119
120static inline void pmic_arb_base_write(struct spmi_pmic_arb_dev *dev,
121 u32 offset, u32 val)
122{
123 writel_relaxed(val, dev->base + offset);
124}
125
126/**
127 * pa_read_data: reads pmic-arb's register and copy 1..4 bytes to buf
128 * @bc: byte count -1. range: 0..3
129 * @reg: register's address
130 * @buf: output parameter, length must be bc + 1
131 */
132static void pa_read_data(struct spmi_pmic_arb_dev *dev, u8 *buf, u32 reg, u8 bc)
133{
134 u32 data = pmic_arb_base_read(dev, reg);
135 memcpy(buf, &data, (bc & 3) + 1);
136}
137
138/**
139 * pa_write_data: write 1..4 bytes from buf to pmic-arb's register
140 * @bc: byte-count -1. range: 0..3.
141 * @reg: register's address.
142 * @buf: buffer to write. length must be bc + 1.
143 */
144static void
145pa_write_data(struct spmi_pmic_arb_dev *dev, const u8 *buf, u32 reg, u8 bc)
146{
147 u32 data = 0;
148 memcpy(&data, buf, (bc & 3) + 1);
149 pmic_arb_base_write(dev, reg, data);
150}
151
152static int pmic_arb_wait_for_done(struct spmi_controller *ctrl)
153{
154 struct spmi_pmic_arb_dev *dev = spmi_controller_get_drvdata(ctrl);
155 u32 status = 0;
156 u32 timeout = PMIC_ARB_TIMEOUT_US;
157 u32 offset = PMIC_ARB_STATUS(dev->channel);
158
159 while (timeout--) {
160 status = pmic_arb_base_read(dev, offset);
161
162 if (status & PMIC_ARB_STATUS_DONE) {
163 if (status & PMIC_ARB_STATUS_DENIED) {
164 dev_err(&ctrl->dev,
165 "%s: transaction denied (0x%x)\n",
166 __func__, status);
167 return -EPERM;
168 }
169
170 if (status & PMIC_ARB_STATUS_FAILURE) {
171 dev_err(&ctrl->dev,
172 "%s: transaction failed (0x%x)\n",
173 __func__, status);
174 return -EIO;
175 }
176
177 if (status & PMIC_ARB_STATUS_DROPPED) {
178 dev_err(&ctrl->dev,
179 "%s: transaction dropped (0x%x)\n",
180 __func__, status);
181 return -EIO;
182 }
183
184 return 0;
185 }
186 udelay(1);
187 }
188
189 dev_err(&ctrl->dev,
190 "%s: timeout, status 0x%x\n",
191 __func__, status);
192 return -ETIMEDOUT;
193}
194
195/* Non-data command */
196static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
197{
198 struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
199 unsigned long flags;
200 u32 cmd;
201 int rc;
202
203 /* Check for valid non-data command */
204 if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP)
205 return -EINVAL;
206
207 cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20);
208
209 raw_spin_lock_irqsave(&pmic_arb->lock, flags);
210 pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
211 rc = pmic_arb_wait_for_done(ctrl);
212 raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
213
214 return rc;
215}
216
217static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
218 u16 addr, u8 *buf, size_t len)
219{
220 struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
221 unsigned long flags;
222 u8 bc = len - 1;
223 u32 cmd;
224 int rc;
225
226 if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
227 dev_err(&ctrl->dev,
228 "pmic-arb supports 1..%d bytes per trans, but %d requested",
229 PMIC_ARB_MAX_TRANS_BYTES, len);
230 return -EINVAL;
231 }
232
233 /* Check the opcode */
234 if (opc >= 0x60 && opc <= 0x7F)
235 opc = PMIC_ARB_OP_READ;
236 else if (opc >= 0x20 && opc <= 0x2F)
237 opc = PMIC_ARB_OP_EXT_READ;
238 else if (opc >= 0x38 && opc <= 0x3F)
239 opc = PMIC_ARB_OP_EXT_READL;
240 else
241 return -EINVAL;
242
243 cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
244
245 raw_spin_lock_irqsave(&pmic_arb->lock, flags);
246 pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
247 rc = pmic_arb_wait_for_done(ctrl);
248 if (rc)
249 goto done;
250
251 pa_read_data(pmic_arb, buf, PMIC_ARB_RDATA0(pmic_arb->channel),
252 min_t(u8, bc, 3));
253
254 if (bc > 3)
255 pa_read_data(pmic_arb, buf + 4,
256 PMIC_ARB_RDATA1(pmic_arb->channel), bc - 4);
257
258done:
259 raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
260 return rc;
261}
262
263static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
264 u16 addr, const u8 *buf, size_t len)
265{
266 struct spmi_pmic_arb_dev *pmic_arb = spmi_controller_get_drvdata(ctrl);
267 unsigned long flags;
268 u8 bc = len - 1;
269 u32 cmd;
270 int rc;
271
272 if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
273 dev_err(&ctrl->dev,
274 "pmic-arb supports 1..%d bytes per trans, but:%d requested",
275 PMIC_ARB_MAX_TRANS_BYTES, len);
276 return -EINVAL;
277 }
278
279 /* Check the opcode */
280 if (opc >= 0x40 && opc <= 0x5F)
281 opc = PMIC_ARB_OP_WRITE;
282 else if (opc >= 0x00 && opc <= 0x0F)
283 opc = PMIC_ARB_OP_EXT_WRITE;
284 else if (opc >= 0x30 && opc <= 0x37)
285 opc = PMIC_ARB_OP_EXT_WRITEL;
286 else if (opc >= 0x80 && opc <= 0xFF)
287 opc = PMIC_ARB_OP_ZERO_WRITE;
288 else
289 return -EINVAL;
290
291 cmd = (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
292
293 /* Write data to FIFOs */
294 raw_spin_lock_irqsave(&pmic_arb->lock, flags);
295 pa_write_data(pmic_arb, buf, PMIC_ARB_WDATA0(pmic_arb->channel)
296 , min_t(u8, bc, 3));
297 if (bc > 3)
298 pa_write_data(pmic_arb, buf + 4,
299 PMIC_ARB_WDATA1(pmic_arb->channel), bc - 4);
300
301 /* Start the transaction */
302 pmic_arb_base_write(pmic_arb, PMIC_ARB_CMD(pmic_arb->channel), cmd);
303 rc = pmic_arb_wait_for_done(ctrl);
304 raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
305
306 return rc;
307}
308
309static int spmi_pmic_arb_probe(struct platform_device *pdev)
310{
311 struct spmi_pmic_arb_dev *pa;
312 struct spmi_controller *ctrl;
313 struct resource *res;
314 u32 channel;
315 int err, i;
316
317 ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa));
318 if (!ctrl)
319 return -ENOMEM;
320
321 pa = spmi_controller_get_drvdata(ctrl);
322
323 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
324 pa->base = devm_ioremap_resource(&ctrl->dev, res);
325 if (IS_ERR(pa->base)) {
326 err = PTR_ERR(pa->base);
327 goto err_put_ctrl;
328 }
329
330 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
331 pa->intr = devm_ioremap_resource(&ctrl->dev, res);
332 if (IS_ERR(pa->intr)) {
333 err = PTR_ERR(pa->intr);
334 goto err_put_ctrl;
335 }
336
337 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg");
338 pa->cnfg = devm_ioremap_resource(&ctrl->dev, res);
339 if (IS_ERR(pa->cnfg)) {
340 err = PTR_ERR(pa->cnfg);
341 goto err_put_ctrl;
342 }
343
344 err = of_property_read_u32(pdev->dev.of_node, "qcom,channel", &channel);
345 if (err) {
346 dev_err(&pdev->dev, "channel unspecified.\n");
347 goto err_put_ctrl;
348 }
349
350 if (channel > 5) {
351 dev_err(&pdev->dev, "invalid channel (%u) specified.\n",
352 channel);
353 goto err_put_ctrl;
354 }
355
356 pa->channel = channel;
357
358 platform_set_drvdata(pdev, ctrl);
359 raw_spin_lock_init(&pa->lock);
360
361 ctrl->cmd = pmic_arb_cmd;
362 ctrl->read_cmd = pmic_arb_read_cmd;
363 ctrl->write_cmd = pmic_arb_write_cmd;
364
365 err = spmi_controller_add(ctrl);
366 if (err)
367 goto err_put_ctrl;
368
369 dev_dbg(&ctrl->dev, "PMIC Arb Version 0x%x\n",
370 pmic_arb_base_read(pa, PMIC_ARB_VERSION));
371
372 return 0;
373
374err_put_ctrl:
375 spmi_controller_put(ctrl);
376 return err;
377}
378
379static int spmi_pmic_arb_remove(struct platform_device *pdev)
380{
381 struct spmi_controller *ctrl = platform_get_drvdata(pdev);
382 spmi_controller_remove(ctrl);
383 spmi_controller_put(ctrl);
384 return 0;
385}
386
387static const struct of_device_id spmi_pmic_arb_match_table[] = {
388 { .compatible = "qcom,spmi-pmic-arb", },
389 {},
390};
391MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table);
392
393static struct platform_driver spmi_pmic_arb_driver = {
394 .probe = spmi_pmic_arb_probe,
395 .remove = spmi_pmic_arb_remove,
396 .driver = {
397 .name = "spmi_pmic_arb",
398 .owner = THIS_MODULE,
399 .of_match_table = spmi_pmic_arb_match_table,
400 },
401};
402module_platform_driver(spmi_pmic_arb_driver);
403
404MODULE_LICENSE("GPL v2");
405MODULE_ALIAS("platform:spmi_pmic_arb");