Blame view
drivers/mfd/ssbi.c
7.9 KB
ce44bf5b5 SSBI: Remove MSM_... |
1 |
/* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved. |
e44b0ceee add single-wire s... |
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
* Copyright (c) 2010, Google Inc. * * Original authors: Code Aurora Forum * * Author: Dima Zavin <dima@android.com> * - Largely rewritten from original to not be an i2c driver. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #define pr_fmt(fmt) "%s: " fmt, __func__ #include <linux/delay.h> #include <linux/err.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/slab.h> |
ce44bf5b5 SSBI: Remove MSM_... |
27 |
#include <linux/ssbi.h> |
e44b0ceee add single-wire s... |
28 |
#include <linux/module.h> |
97f00f712 SSBI: Convert SSB... |
29 30 |
#include <linux/of.h> #include <linux/of_device.h> |
e44b0ceee add single-wire s... |
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
/* SSBI 2.0 controller registers */ #define SSBI2_CMD 0x0008 #define SSBI2_RD 0x0010 #define SSBI2_STATUS 0x0014 #define SSBI2_MODE2 0x001C /* SSBI_CMD fields */ #define SSBI_CMD_RDWRN (1 << 24) /* SSBI_STATUS fields */ #define SSBI_STATUS_RD_READY (1 << 2) #define SSBI_STATUS_READY (1 << 1) #define SSBI_STATUS_MCHN_BUSY (1 << 0) /* SSBI_MODE2 fields */ #define SSBI_MODE2_REG_ADDR_15_8_SHFT 0x04 #define SSBI_MODE2_REG_ADDR_15_8_MASK (0x7f << SSBI_MODE2_REG_ADDR_15_8_SHFT) #define SET_SSBI_MODE2_REG_ADDR_15_8(MD, AD) \ (((MD) & 0x0F) | ((((AD) >> 8) << SSBI_MODE2_REG_ADDR_15_8_SHFT) & \ SSBI_MODE2_REG_ADDR_15_8_MASK)) /* SSBI PMIC Arbiter command registers */ #define SSBI_PA_CMD 0x0000 #define SSBI_PA_RD_STATUS 0x0004 /* SSBI_PA_CMD fields */ #define SSBI_PA_CMD_RDWRN (1 << 24) #define SSBI_PA_CMD_ADDR_MASK 0x7fff /* REG_ADDR_7_0, REG_ADDR_8_14*/ /* SSBI_PA_RD_STATUS fields */ #define SSBI_PA_RD_STATUS_TRANS_DONE (1 << 27) #define SSBI_PA_RD_STATUS_TRANS_DENIED (1 << 26) #define SSBI_TIMEOUT_US 100 |
bae911a05 mfd: ssbi: Remove... |
67 68 69 70 71 |
enum ssbi_controller_type { MSM_SBI_CTRL_SSBI = 0, MSM_SBI_CTRL_SSBI2, MSM_SBI_CTRL_PMIC_ARBITER, }; |
ce44bf5b5 SSBI: Remove MSM_... |
72 |
struct ssbi { |
e44b0ceee add single-wire s... |
73 74 75 |
struct device *slave; void __iomem *base; spinlock_t lock; |
ce44bf5b5 SSBI: Remove MSM_... |
76 77 |
enum ssbi_controller_type controller_type; int (*read)(struct ssbi *, u16 addr, u8 *buf, int len); |
5eec14ccf mfd: ssbi: Consti... |
78 |
int (*write)(struct ssbi *, u16 addr, const u8 *buf, int len); |
e44b0ceee add single-wire s... |
79 |
}; |
ce44bf5b5 SSBI: Remove MSM_... |
80 |
#define to_ssbi(dev) platform_get_drvdata(to_platform_device(dev)) |
e44b0ceee add single-wire s... |
81 |
|
ce44bf5b5 SSBI: Remove MSM_... |
82 |
static inline u32 ssbi_readl(struct ssbi *ssbi, u32 reg) |
e44b0ceee add single-wire s... |
83 84 85 |
{ return readl(ssbi->base + reg); } |
ce44bf5b5 SSBI: Remove MSM_... |
86 |
static inline void ssbi_writel(struct ssbi *ssbi, u32 val, u32 reg) |
e44b0ceee add single-wire s... |
87 88 89 |
{ writel(val, ssbi->base + reg); } |
3f7a73b57 ssbi: Comment the... |
90 91 92 93 94 95 96 97 98 |
/* * Via private exchange with one of the original authors, the hardware * should generally finish a transaction in about 5us. The worst * case, is when using the arbiter and both other CPUs have just * started trying to use the SSBI bus will result in a time of about * 20us. It should never take longer than this. * * As such, this wait merely spins, with a udelay. */ |
ce44bf5b5 SSBI: Remove MSM_... |
99 |
static int ssbi_wait_mask(struct ssbi *ssbi, u32 set_mask, u32 clr_mask) |
e44b0ceee add single-wire s... |
100 101 102 103 104 105 106 107 108 109 |
{ u32 timeout = SSBI_TIMEOUT_US; u32 val; while (timeout--) { val = ssbi_readl(ssbi, SSBI2_STATUS); if (((val & set_mask) == set_mask) && ((val & clr_mask) == 0)) return 0; udelay(1); } |
e44b0ceee add single-wire s... |
110 111 112 113 |
return -ETIMEDOUT; } static int |
ce44bf5b5 SSBI: Remove MSM_... |
114 |
ssbi_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len) |
e44b0ceee add single-wire s... |
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
{ u32 cmd = SSBI_CMD_RDWRN | ((addr & 0xff) << 16); int ret = 0; if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) { u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2); mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr); ssbi_writel(ssbi, mode2, SSBI2_MODE2); } while (len) { ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0); if (ret) goto err; ssbi_writel(ssbi, cmd, SSBI2_CMD); ret = ssbi_wait_mask(ssbi, SSBI_STATUS_RD_READY, 0); if (ret) goto err; *buf++ = ssbi_readl(ssbi, SSBI2_RD) & 0xff; len--; } err: return ret; } static int |
5eec14ccf mfd: ssbi: Consti... |
143 |
ssbi_write_bytes(struct ssbi *ssbi, u16 addr, const u8 *buf, int len) |
e44b0ceee add single-wire s... |
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
{ int ret = 0; if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) { u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2); mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr); ssbi_writel(ssbi, mode2, SSBI2_MODE2); } while (len) { ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0); if (ret) goto err; ssbi_writel(ssbi, ((addr & 0xff) << 16) | *buf, SSBI2_CMD); ret = ssbi_wait_mask(ssbi, 0, SSBI_STATUS_MCHN_BUSY); if (ret) goto err; buf++; len--; } err: return ret; } |
3f7a73b57 ssbi: Comment the... |
169 170 171 172 |
/* * See ssbi_wait_mask for an explanation of the time and the * busywait. */ |
e44b0ceee add single-wire s... |
173 |
static inline int |
ce44bf5b5 SSBI: Remove MSM_... |
174 |
ssbi_pa_transfer(struct ssbi *ssbi, u32 cmd, u8 *data) |
e44b0ceee add single-wire s... |
175 176 177 178 179 180 181 182 |
{ u32 timeout = SSBI_TIMEOUT_US; u32 rd_status = 0; ssbi_writel(ssbi, cmd, SSBI_PA_CMD); while (timeout--) { rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS); |
37799ef4f ssbi: Remove extr... |
183 |
if (rd_status & SSBI_PA_RD_STATUS_TRANS_DENIED) |
e44b0ceee add single-wire s... |
184 |
return -EPERM; |
e44b0ceee add single-wire s... |
185 186 187 188 189 190 191 192 |
if (rd_status & SSBI_PA_RD_STATUS_TRANS_DONE) { if (data) *data = rd_status & 0xff; return 0; } udelay(1); } |
e44b0ceee add single-wire s... |
193 194 195 196 |
return -ETIMEDOUT; } static int |
ce44bf5b5 SSBI: Remove MSM_... |
197 |
ssbi_pa_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len) |
e44b0ceee add single-wire s... |
198 199 200 201 202 203 204 |
{ u32 cmd; int ret = 0; cmd = SSBI_PA_CMD_RDWRN | (addr & SSBI_PA_CMD_ADDR_MASK) << 8; while (len) { |
ce44bf5b5 SSBI: Remove MSM_... |
205 |
ret = ssbi_pa_transfer(ssbi, cmd, buf); |
e44b0ceee add single-wire s... |
206 207 208 209 210 211 212 213 214 215 216 |
if (ret) goto err; buf++; len--; } err: return ret; } static int |
5eec14ccf mfd: ssbi: Consti... |
217 |
ssbi_pa_write_bytes(struct ssbi *ssbi, u16 addr, const u8 *buf, int len) |
e44b0ceee add single-wire s... |
218 219 220 221 222 223 |
{ u32 cmd; int ret = 0; while (len) { cmd = (addr & SSBI_PA_CMD_ADDR_MASK) << 8 | *buf; |
ce44bf5b5 SSBI: Remove MSM_... |
224 |
ret = ssbi_pa_transfer(ssbi, cmd, NULL); |
e44b0ceee add single-wire s... |
225 226 227 228 229 230 231 232 233 |
if (ret) goto err; buf++; len--; } err: return ret; } |
ce44bf5b5 SSBI: Remove MSM_... |
234 |
int ssbi_read(struct device *dev, u16 addr, u8 *buf, int len) |
e44b0ceee add single-wire s... |
235 |
{ |
ce44bf5b5 SSBI: Remove MSM_... |
236 |
struct ssbi *ssbi = to_ssbi(dev); |
e44b0ceee add single-wire s... |
237 238 |
unsigned long flags; int ret; |
e44b0ceee add single-wire s... |
239 240 241 242 243 244 |
spin_lock_irqsave(&ssbi->lock, flags); ret = ssbi->read(ssbi, addr, buf, len); spin_unlock_irqrestore(&ssbi->lock, flags); return ret; } |
ce44bf5b5 SSBI: Remove MSM_... |
245 |
EXPORT_SYMBOL_GPL(ssbi_read); |
e44b0ceee add single-wire s... |
246 |
|
5eec14ccf mfd: ssbi: Consti... |
247 |
int ssbi_write(struct device *dev, u16 addr, const u8 *buf, int len) |
e44b0ceee add single-wire s... |
248 |
{ |
ce44bf5b5 SSBI: Remove MSM_... |
249 |
struct ssbi *ssbi = to_ssbi(dev); |
e44b0ceee add single-wire s... |
250 251 |
unsigned long flags; int ret; |
e44b0ceee add single-wire s... |
252 253 254 255 256 257 |
spin_lock_irqsave(&ssbi->lock, flags); ret = ssbi->write(ssbi, addr, buf, len); spin_unlock_irqrestore(&ssbi->lock, flags); return ret; } |
ce44bf5b5 SSBI: Remove MSM_... |
258 |
EXPORT_SYMBOL_GPL(ssbi_write); |
e44b0ceee add single-wire s... |
259 |
|
ce44bf5b5 SSBI: Remove MSM_... |
260 |
static int ssbi_probe(struct platform_device *pdev) |
e44b0ceee add single-wire s... |
261 |
{ |
97f00f712 SSBI: Convert SSB... |
262 |
struct device_node *np = pdev->dev.of_node; |
e44b0ceee add single-wire s... |
263 |
struct resource *mem_res; |
ce44bf5b5 SSBI: Remove MSM_... |
264 |
struct ssbi *ssbi; |
97f00f712 SSBI: Convert SSB... |
265 |
const char *type; |
e44b0ceee add single-wire s... |
266 |
|
e57843882 mfd: ssbi: Use de... |
267 268 |
ssbi = devm_kzalloc(&pdev->dev, sizeof(*ssbi), GFP_KERNEL); if (!ssbi) |
e44b0ceee add single-wire s... |
269 |
return -ENOMEM; |
e44b0ceee add single-wire s... |
270 271 |
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
e57843882 mfd: ssbi: Use de... |
272 273 274 |
ssbi->base = devm_ioremap_resource(&pdev->dev, mem_res); if (IS_ERR(ssbi->base)) return PTR_ERR(ssbi->base); |
e44b0ceee add single-wire s... |
275 |
|
e44b0ceee add single-wire s... |
276 |
platform_set_drvdata(pdev, ssbi); |
97f00f712 SSBI: Convert SSB... |
277 278 |
type = of_get_property(np, "qcom,controller-type", NULL); if (type == NULL) { |
e57843882 mfd: ssbi: Use de... |
279 280 281 |
dev_err(&pdev->dev, "Missing qcom,controller-type property "); return -EINVAL; |
97f00f712 SSBI: Convert SSB... |
282 283 284 285 286 287 288 289 290 291 |
} dev_info(&pdev->dev, "SSBI controller type: '%s' ", type); if (strcmp(type, "ssbi") == 0) ssbi->controller_type = MSM_SBI_CTRL_SSBI; else if (strcmp(type, "ssbi2") == 0) ssbi->controller_type = MSM_SBI_CTRL_SSBI2; else if (strcmp(type, "pmic-arbiter") == 0) ssbi->controller_type = MSM_SBI_CTRL_PMIC_ARBITER; else { |
e57843882 mfd: ssbi: Use de... |
292 293 294 |
dev_err(&pdev->dev, "Unknown qcom,controller-type "); return -EINVAL; |
97f00f712 SSBI: Convert SSB... |
295 |
} |
e44b0ceee add single-wire s... |
296 |
if (ssbi->controller_type == MSM_SBI_CTRL_PMIC_ARBITER) { |
ce44bf5b5 SSBI: Remove MSM_... |
297 298 |
ssbi->read = ssbi_pa_read_bytes; ssbi->write = ssbi_pa_write_bytes; |
e44b0ceee add single-wire s... |
299 |
} else { |
ce44bf5b5 SSBI: Remove MSM_... |
300 301 |
ssbi->read = ssbi_read_bytes; ssbi->write = ssbi_write_bytes; |
e44b0ceee add single-wire s... |
302 303 304 |
} spin_lock_init(&ssbi->lock); |
e57843882 mfd: ssbi: Use de... |
305 |
return of_platform_populate(np, NULL, NULL, &pdev->dev); |
e44b0ceee add single-wire s... |
306 |
} |
12eda2a2e mfd: ssbi: Mark m... |
307 |
static const struct of_device_id ssbi_match_table[] = { |
97f00f712 SSBI: Convert SSB... |
308 309 310 |
{ .compatible = "qcom,ssbi" }, {} }; |
6378c1e51 mfd: ssbi: Add MO... |
311 |
MODULE_DEVICE_TABLE(of, ssbi_match_table); |
97f00f712 SSBI: Convert SSB... |
312 |
|
ce44bf5b5 SSBI: Remove MSM_... |
313 314 |
static struct platform_driver ssbi_driver = { .probe = ssbi_probe, |
e44b0ceee add single-wire s... |
315 |
.driver = { |
ce44bf5b5 SSBI: Remove MSM_... |
316 |
.name = "ssbi", |
97f00f712 SSBI: Convert SSB... |
317 |
.of_match_table = ssbi_match_table, |
e44b0ceee add single-wire s... |
318 319 |
}, }; |
e57843882 mfd: ssbi: Use de... |
320 |
module_platform_driver(ssbi_driver); |
e44b0ceee add single-wire s... |
321 322 323 |
MODULE_LICENSE("GPL v2"); MODULE_VERSION("1.0"); |
ce44bf5b5 SSBI: Remove MSM_... |
324 |
MODULE_ALIAS("platform:ssbi"); |
e44b0ceee add single-wire s... |
325 |
MODULE_AUTHOR("Dima Zavin <dima@android.com>"); |