blob: 9232f67d70424ebc779c36253be23e23e1d3347f [file] [log] [blame]
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +05301/* Copyright (c) 2012, Code Aurora Forum. 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
13#include <linux/platform_device.h>
14#include <linux/err.h>
15#include <linux/pm_runtime.h>
16#include <linux/regulator/consumer.h>
17#include <linux/i2c.h>
18#include <linux/gpio.h>
19#include <linux/slab.h>
20#include <linux/delay.h>
21#include <linux/smsc3503.h>
22#include <mach/msm_xo.h>
23
24#define SMSC3503_I2C_ADDR 0x08
25#define SMSC_GSBI_I2C_BUS_ID 10
26static const unsigned short normal_i2c[] = {
27SMSC3503_I2C_ADDR, I2C_CLIENT_END };
28
29struct hsic_hub {
30 struct regulator *hsic_hub_reg;
31 struct device *dev;
32 struct i2c_client *client;
33 struct msm_xo_voter *xo_handle;
34};
35static struct hsic_hub *smsc_hub;
36
37/* APIs for setting/clearing bits and for reading/writing values */
38static inline int hsic_hub_get_u8(struct i2c_client *client, u8 reg)
39{
40 int ret;
41
42 ret = i2c_smbus_read_byte_data(client, reg);
43 if (ret < 0)
44 pr_err("%s:i2c_read8 failed\n", __func__);
45 return ret;
46}
47
48static inline int hsic_hub_get_u16(struct i2c_client *client, u8 reg)
49{
50 int ret;
51
52 ret = i2c_smbus_read_word_data(client, reg);
53 if (ret < 0)
54 pr_err("%s:i2c_read16 failed\n", __func__);
55 return ret;
56}
57
58static inline int hsic_hub_write_word_data(struct i2c_client *client, u8 reg,
59 u16 value)
60{
61 int ret;
62
63 ret = i2c_smbus_write_word_data(client, reg, value);
64 if (ret)
65 pr_err("%s:i2c_write16 failed\n", __func__);
66 return ret;
67}
68
69static inline int hsic_hub_write_byte_data(struct i2c_client *client, u8 reg,
70 u8 value)
71{
72 int ret;
73
74 ret = i2c_smbus_write_byte_data(client, reg, value);
75 if (ret)
76 pr_err("%s:i2c_write_byte_data failed\n", __func__);
77 return ret;
78}
79
80static inline int hsic_hub_set_bits(struct i2c_client *client, u8 reg,
81 u8 value)
82{
83 int ret;
84
85 ret = i2c_smbus_read_byte_data(client, reg);
86 if (ret < 0) {
87 pr_err("%s:i2c_read_byte_data failed\n", __func__);
88 return ret;
89 }
90 return i2c_smbus_write_byte_data(client, reg, (ret | value));
91}
92
93static inline int hsic_hub_clear_bits(struct i2c_client *client, u8 reg,
94 u8 value)
95{
96 int ret;
97
98 ret = i2c_smbus_read_byte_data(client, reg);
99 if (ret < 0) {
100 pr_err("%s:i2c_read_byte_data failed\n", __func__);
101 return ret;
102 }
103 return i2c_smbus_write_byte_data(client, reg, (ret & ~value));
104}
105
106static int i2c_hsic_hub_probe(struct i2c_client *client,
107 const struct i2c_device_id *id)
108{
109 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
110 I2C_FUNC_SMBUS_WORD_DATA))
111 return -EIO;
112
Vijayavardhan Vennapusa361da682012-04-12 19:50:02 +0530113 /* CONFIG_N bit in SP_ILOCK register has to be set before changing
114 * other registers to change default configuration of hsic hub.
115 */
116 hsic_hub_set_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
117
118 /* Can change default configuartion like VID,PID, strings etc
119 * by writing new values to hsic hub registers.
120 */
121 hsic_hub_write_word_data(client, SMSC3503_VENDORID, 0x05C6);
122
123 /* CONFIG_N bit in SP_ILOCK register has to be cleared for new
124 * values in registers to be effective after writing to
125 * other registers.
126 */
127 hsic_hub_clear_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
128
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530129 return 0;
130}
131
132static int i2c_hsic_hub_remove(struct i2c_client *client)
133{
134 return 0;
135}
136
137static const struct i2c_device_id hsic_hub_id[] = {
138 {"i2c_hsic_hub", 0},
139 {}
140};
141MODULE_DEVICE_TABLE(i2c, hsichub_id);
142
143static struct i2c_driver hsic_hub_driver = {
144 .driver = {
145 .name = "i2c_hsic_hub",
146 },
147 .probe = i2c_hsic_hub_probe,
148 .remove = i2c_hsic_hub_remove,
149 .id_table = hsic_hub_id,
150};
151
152#define HSIC_HUB_VDD_VOL_MIN 1650000 /* uV */
153#define HSIC_HUB_VDD_VOL_MAX 1950000 /* uV */
154#define HSIC_HUB_VDD_LOAD 36000 /* uA */
155static int __devinit smsc_hub_probe(struct platform_device *pdev)
156{
157 int ret = 0;
158 const struct smsc_hub_platform_data *pdata;
159 struct i2c_adapter *i2c_adap;
160 struct i2c_board_info i2c_info;
161
162 if (!pdev->dev.platform_data) {
163 dev_err(&pdev->dev, "No platform data\n");
164 return -ENODEV;
165 }
166
167 pdata = pdev->dev.platform_data;
168 if (!pdata->hub_reset)
169 return -EINVAL;
170
171 smsc_hub = kzalloc(sizeof(*smsc_hub), GFP_KERNEL);
172 if (!smsc_hub)
173 return -ENOMEM;
174
175 smsc_hub->hsic_hub_reg = regulator_get(&pdev->dev, "EXT_HUB_VDDIO");
176 if (IS_ERR(smsc_hub->hsic_hub_reg)) {
177 dev_err(&pdev->dev, "unable to get ext hub vddcx\n");
178 ret = PTR_ERR(smsc_hub->hsic_hub_reg);
179 goto free_mem;
180 }
181
182 ret = gpio_request(pdata->hub_reset, "HSIC_HUB_RESET_GPIO");
183 if (ret < 0) {
184 dev_err(&pdev->dev, "gpio request failed for GPIO%d\n",
185 pdata->hub_reset);
186 goto gpio_req_fail;
187 }
188
189 ret = regulator_set_voltage(smsc_hub->hsic_hub_reg,
190 HSIC_HUB_VDD_VOL_MIN,
191 HSIC_HUB_VDD_VOL_MAX);
192 if (ret) {
193 dev_err(&pdev->dev, "unable to set the voltage"
194 "for hsic hub reg\n");
195 goto reg_set_voltage_fail;
196 }
197
198 ret = regulator_set_optimum_mode(smsc_hub->hsic_hub_reg,
199 HSIC_HUB_VDD_LOAD);
200 if (ret < 0) {
201 dev_err(&pdev->dev, "Unable to set optimum mode of regulator:"
202 "VDDCX\n");
203 goto reg_optimum_mode_fail;
204 }
205
206 ret = regulator_enable(smsc_hub->hsic_hub_reg);
207 if (ret) {
208 dev_err(&pdev->dev, "unable to enable ext hub vddcx\n");
209 goto reg_enable_fail;
210 }
211
212 smsc_hub->xo_handle = msm_xo_get(MSM_XO_TCXO_D1, "hsic_hub");
213 if (IS_ERR(smsc_hub->xo_handle)) {
214 dev_err(&pdev->dev, "not able to get the handle"
215 "for TCXO D1 buffer\n");
216 goto disable_regulator;
217 }
218
219 ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
220 if (ret) {
221 dev_err(&pdev->dev, "failed to vote for TCXO"
222 "D1 buffer\n");
223 goto xo_vote_fail;
224 }
225
226 gpio_direction_output(pdata->hub_reset, 0);
227 /* Hub reset should be asserted for minimum 2microsec
228 * before deasserting.
229 */
230 udelay(5);
231 gpio_direction_output(pdata->hub_reset, 1);
232
233 ret = i2c_add_driver(&hsic_hub_driver);
234 if (ret < 0) {
235 dev_err(&pdev->dev, "failed to add I2C hsic_hub_driver\n");
236 goto i2c_add_fail;
237 }
238 usleep_range(10000, 12000);
239 i2c_adap = i2c_get_adapter(SMSC_GSBI_I2C_BUS_ID);
240
241 if (!i2c_adap) {
242 dev_err(&pdev->dev, "failed to get i2c adapter\n");
243 i2c_del_driver(&hsic_hub_driver);
244 goto i2c_add_fail;
245 }
246
247 memset(&i2c_info, 0, sizeof(struct i2c_board_info));
248 strlcpy(i2c_info.type, "i2c_hsic_hub", I2C_NAME_SIZE);
249
250 smsc_hub->client = i2c_new_probed_device(i2c_adap, &i2c_info,
251 normal_i2c, NULL);
252 i2c_put_adapter(i2c_adap);
253 if (!smsc_hub->client)
254 dev_err(&pdev->dev, "failed to connect to smsc_hub"
255 "through I2C\n");
256
257i2c_add_fail:
258 pm_runtime_set_active(&pdev->dev);
259 pm_runtime_enable(&pdev->dev);
260
261 return 0;
262
263xo_vote_fail:
264 msm_xo_put(smsc_hub->xo_handle);
265disable_regulator:
266 regulator_disable(smsc_hub->hsic_hub_reg);
267reg_enable_fail:
268 regulator_set_optimum_mode(smsc_hub->hsic_hub_reg, 0);
269reg_optimum_mode_fail:
270 regulator_set_voltage(smsc_hub->hsic_hub_reg, 0,
271 HSIC_HUB_VDD_VOL_MIN);
272reg_set_voltage_fail:
273 gpio_free(pdata->hub_reset);
274gpio_req_fail:
275 regulator_put(smsc_hub->hsic_hub_reg);
276free_mem:
277 kfree(smsc_hub);
278
279 return ret;
280}
281
282static int smsc_hub_remove(struct platform_device *pdev)
283{
284 const struct smsc_hub_platform_data *pdata;
285
286 pdata = pdev->dev.platform_data;
287 if (smsc_hub->client) {
288 i2c_unregister_device(smsc_hub->client);
289 smsc_hub->client = NULL;
290 i2c_del_driver(&hsic_hub_driver);
291 }
292 pm_runtime_disable(&pdev->dev);
293 msm_xo_put(smsc_hub->xo_handle);
294
295 regulator_disable(smsc_hub->hsic_hub_reg);
296 regulator_set_optimum_mode(smsc_hub->hsic_hub_reg, 0);
297 regulator_set_voltage(smsc_hub->hsic_hub_reg, 0,
298 HSIC_HUB_VDD_VOL_MIN);
299 gpio_free(pdata->hub_reset);
300 regulator_put(smsc_hub->hsic_hub_reg);
301 kfree(smsc_hub);
302
303 return 0;
304}
305
306#ifdef CONFIG_PM_RUNTIME
307static int msm_smsc_runtime_idle(struct device *dev)
308{
309 dev_dbg(dev, "SMSC HUB runtime idle\n");
310
311 return 0;
312}
313
314static int smsc_hub_lpm_enter(struct device *dev)
315{
316 int ret;
317
318 ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_OFF);
319 if (ret) {
320 pr_err("%s: failed to devote for TCXO"
321 "D1 buffer%d\n", __func__, ret);
322 }
323 return ret;
324}
325
326static int smsc_hub_lpm_exit(struct device *dev)
327{
328 int ret;
329
330 ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
331 if (ret) {
332 pr_err("%s: failed to vote for TCXO"
333 "D1 buffer%d\n", __func__, ret);
334 }
335 return ret;
336}
337#endif
338
339#ifdef CONFIG_PM
340static const struct dev_pm_ops smsc_hub_dev_pm_ops = {
341 SET_SYSTEM_SLEEP_PM_OPS(smsc_hub_lpm_enter, smsc_hub_lpm_exit)
342 SET_RUNTIME_PM_OPS(smsc_hub_lpm_enter, smsc_hub_lpm_exit,
343 msm_smsc_runtime_idle)
344};
345#endif
346
347static struct platform_driver smsc_hub_driver = {
348 .driver = {
349 .name = "msm_smsc_hub",
350 .owner = THIS_MODULE,
351#ifdef CONFIG_PM
352 .pm = &smsc_hub_dev_pm_ops,
353#endif
354 },
355 .remove = smsc_hub_remove,
356};
357
358static int __init smsc_hub_init(void)
359{
360 return platform_driver_probe(&smsc_hub_driver, smsc_hub_probe);
361}
362
363static void __exit smsc_hub_exit(void)
364{
365 platform_driver_unregister(&smsc_hub_driver);
366}
367subsys_initcall(smsc_hub_init);
368module_exit(smsc_hub_exit);
369
370MODULE_LICENSE("GPL v2");
371MODULE_DESCRIPTION("SMSC HSIC HUB driver");