Blame view

drivers/mfd/ssbi.c 7.9 KB
ce44bf5b5   David Brown   SSBI: Remove MSM_...
1
  /* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
e44b0ceee   Kenneth Heitke   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   David Brown   SSBI: Remove MSM_...
27
  #include <linux/ssbi.h>
e44b0ceee   Kenneth Heitke   add single-wire s...
28
  #include <linux/module.h>
97f00f712   David Brown   SSBI: Convert SSB...
29
30
  #include <linux/of.h>
  #include <linux/of_device.h>
e44b0ceee   Kenneth Heitke   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   Stephen Boyd   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   David Brown   SSBI: Remove MSM_...
72
  struct ssbi {
e44b0ceee   Kenneth Heitke   add single-wire s...
73
74
75
  	struct device		*slave;
  	void __iomem		*base;
  	spinlock_t		lock;
ce44bf5b5   David Brown   SSBI: Remove MSM_...
76
77
  	enum ssbi_controller_type controller_type;
  	int (*read)(struct ssbi *, u16 addr, u8 *buf, int len);
5eec14ccf   Stephen Boyd   mfd: ssbi: Consti...
78
  	int (*write)(struct ssbi *, u16 addr, const u8 *buf, int len);
e44b0ceee   Kenneth Heitke   add single-wire s...
79
  };
ce44bf5b5   David Brown   SSBI: Remove MSM_...
80
  #define to_ssbi(dev)	platform_get_drvdata(to_platform_device(dev))
e44b0ceee   Kenneth Heitke   add single-wire s...
81

ce44bf5b5   David Brown   SSBI: Remove MSM_...
82
  static inline u32 ssbi_readl(struct ssbi *ssbi, u32 reg)
e44b0ceee   Kenneth Heitke   add single-wire s...
83
84
85
  {
  	return readl(ssbi->base + reg);
  }
ce44bf5b5   David Brown   SSBI: Remove MSM_...
86
  static inline void ssbi_writel(struct ssbi *ssbi, u32 val, u32 reg)
e44b0ceee   Kenneth Heitke   add single-wire s...
87
88
89
  {
  	writel(val, ssbi->base + reg);
  }
3f7a73b57   David Brown   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   David Brown   SSBI: Remove MSM_...
99
  static int ssbi_wait_mask(struct ssbi *ssbi, u32 set_mask, u32 clr_mask)
e44b0ceee   Kenneth Heitke   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   Kenneth Heitke   add single-wire s...
110
111
112
113
  	return -ETIMEDOUT;
  }
  
  static int
ce44bf5b5   David Brown   SSBI: Remove MSM_...
114
  ssbi_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
e44b0ceee   Kenneth Heitke   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   Stephen Boyd   mfd: ssbi: Consti...
143
  ssbi_write_bytes(struct ssbi *ssbi, u16 addr, const u8 *buf, int len)
e44b0ceee   Kenneth Heitke   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   David Brown   ssbi: Comment the...
169
170
171
172
  /*
   * See ssbi_wait_mask for an explanation of the time and the
   * busywait.
   */
e44b0ceee   Kenneth Heitke   add single-wire s...
173
  static inline int
ce44bf5b5   David Brown   SSBI: Remove MSM_...
174
  ssbi_pa_transfer(struct ssbi *ssbi, u32 cmd, u8 *data)
e44b0ceee   Kenneth Heitke   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   David Brown   ssbi: Remove extr...
183
  		if (rd_status & SSBI_PA_RD_STATUS_TRANS_DENIED)
e44b0ceee   Kenneth Heitke   add single-wire s...
184
  			return -EPERM;
e44b0ceee   Kenneth Heitke   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   Kenneth Heitke   add single-wire s...
193
194
195
196
  	return -ETIMEDOUT;
  }
  
  static int
ce44bf5b5   David Brown   SSBI: Remove MSM_...
197
  ssbi_pa_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len)
e44b0ceee   Kenneth Heitke   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   David Brown   SSBI: Remove MSM_...
205
  		ret = ssbi_pa_transfer(ssbi, cmd, buf);
e44b0ceee   Kenneth Heitke   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   Stephen Boyd   mfd: ssbi: Consti...
217
  ssbi_pa_write_bytes(struct ssbi *ssbi, u16 addr, const u8 *buf, int len)
e44b0ceee   Kenneth Heitke   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   David Brown   SSBI: Remove MSM_...
224
  		ret = ssbi_pa_transfer(ssbi, cmd, NULL);
e44b0ceee   Kenneth Heitke   add single-wire s...
225
226
227
228
229
230
231
232
233
  		if (ret)
  			goto err;
  		buf++;
  		len--;
  	}
  
  err:
  	return ret;
  }
ce44bf5b5   David Brown   SSBI: Remove MSM_...
234
  int ssbi_read(struct device *dev, u16 addr, u8 *buf, int len)
e44b0ceee   Kenneth Heitke   add single-wire s...
235
  {
ce44bf5b5   David Brown   SSBI: Remove MSM_...
236
  	struct ssbi *ssbi = to_ssbi(dev);
e44b0ceee   Kenneth Heitke   add single-wire s...
237
238
  	unsigned long flags;
  	int ret;
e44b0ceee   Kenneth Heitke   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   David Brown   SSBI: Remove MSM_...
245
  EXPORT_SYMBOL_GPL(ssbi_read);
e44b0ceee   Kenneth Heitke   add single-wire s...
246

5eec14ccf   Stephen Boyd   mfd: ssbi: Consti...
247
  int ssbi_write(struct device *dev, u16 addr, const u8 *buf, int len)
e44b0ceee   Kenneth Heitke   add single-wire s...
248
  {
ce44bf5b5   David Brown   SSBI: Remove MSM_...
249
  	struct ssbi *ssbi = to_ssbi(dev);
e44b0ceee   Kenneth Heitke   add single-wire s...
250
251
  	unsigned long flags;
  	int ret;
e44b0ceee   Kenneth Heitke   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   David Brown   SSBI: Remove MSM_...
258
  EXPORT_SYMBOL_GPL(ssbi_write);
e44b0ceee   Kenneth Heitke   add single-wire s...
259

ce44bf5b5   David Brown   SSBI: Remove MSM_...
260
  static int ssbi_probe(struct platform_device *pdev)
e44b0ceee   Kenneth Heitke   add single-wire s...
261
  {
97f00f712   David Brown   SSBI: Convert SSB...
262
  	struct device_node *np = pdev->dev.of_node;
e44b0ceee   Kenneth Heitke   add single-wire s...
263
  	struct resource *mem_res;
ce44bf5b5   David Brown   SSBI: Remove MSM_...
264
  	struct ssbi *ssbi;
97f00f712   David Brown   SSBI: Convert SSB...
265
  	const char *type;
e44b0ceee   Kenneth Heitke   add single-wire s...
266

e57843882   Stephen Boyd   mfd: ssbi: Use de...
267
268
  	ssbi = devm_kzalloc(&pdev->dev, sizeof(*ssbi), GFP_KERNEL);
  	if (!ssbi)
e44b0ceee   Kenneth Heitke   add single-wire s...
269
  		return -ENOMEM;
e44b0ceee   Kenneth Heitke   add single-wire s...
270
271
  
  	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
e57843882   Stephen Boyd   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   Kenneth Heitke   add single-wire s...
275

e44b0ceee   Kenneth Heitke   add single-wire s...
276
  	platform_set_drvdata(pdev, ssbi);
97f00f712   David Brown   SSBI: Convert SSB...
277
278
  	type = of_get_property(np, "qcom,controller-type", NULL);
  	if (type == NULL) {
e57843882   Stephen Boyd   mfd: ssbi: Use de...
279
280
281
  		dev_err(&pdev->dev, "Missing qcom,controller-type property
  ");
  		return -EINVAL;
97f00f712   David Brown   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   Stephen Boyd   mfd: ssbi: Use de...
292
293
294
  		dev_err(&pdev->dev, "Unknown qcom,controller-type
  ");
  		return -EINVAL;
97f00f712   David Brown   SSBI: Convert SSB...
295
  	}
e44b0ceee   Kenneth Heitke   add single-wire s...
296
  	if (ssbi->controller_type == MSM_SBI_CTRL_PMIC_ARBITER) {
ce44bf5b5   David Brown   SSBI: Remove MSM_...
297
298
  		ssbi->read = ssbi_pa_read_bytes;
  		ssbi->write = ssbi_pa_write_bytes;
e44b0ceee   Kenneth Heitke   add single-wire s...
299
  	} else {
ce44bf5b5   David Brown   SSBI: Remove MSM_...
300
301
  		ssbi->read = ssbi_read_bytes;
  		ssbi->write = ssbi_write_bytes;
e44b0ceee   Kenneth Heitke   add single-wire s...
302
303
304
  	}
  
  	spin_lock_init(&ssbi->lock);
e57843882   Stephen Boyd   mfd: ssbi: Use de...
305
  	return of_platform_populate(np, NULL, NULL, &pdev->dev);
e44b0ceee   Kenneth Heitke   add single-wire s...
306
  }
12eda2a2e   Stephen Boyd   mfd: ssbi: Mark m...
307
  static const struct of_device_id ssbi_match_table[] = {
97f00f712   David Brown   SSBI: Convert SSB...
308
309
310
  	{ .compatible = "qcom,ssbi" },
  	{}
  };
6378c1e51   Stephen Boyd   mfd: ssbi: Add MO...
311
  MODULE_DEVICE_TABLE(of, ssbi_match_table);
97f00f712   David Brown   SSBI: Convert SSB...
312

ce44bf5b5   David Brown   SSBI: Remove MSM_...
313
314
  static struct platform_driver ssbi_driver = {
  	.probe		= ssbi_probe,
e44b0ceee   Kenneth Heitke   add single-wire s...
315
  	.driver		= {
ce44bf5b5   David Brown   SSBI: Remove MSM_...
316
  		.name	= "ssbi",
97f00f712   David Brown   SSBI: Convert SSB...
317
  		.of_match_table = ssbi_match_table,
e44b0ceee   Kenneth Heitke   add single-wire s...
318
319
  	},
  };
e57843882   Stephen Boyd   mfd: ssbi: Use de...
320
  module_platform_driver(ssbi_driver);
e44b0ceee   Kenneth Heitke   add single-wire s...
321
322
323
  
  MODULE_LICENSE("GPL v2");
  MODULE_VERSION("1.0");
ce44bf5b5   David Brown   SSBI: Remove MSM_...
324
  MODULE_ALIAS("platform:ssbi");
e44b0ceee   Kenneth Heitke   add single-wire s...
325
  MODULE_AUTHOR("Dima Zavin <dima@android.com>");