blob: 0147e667b53cb23d4339a9fecc5e162580863774 [file] [log] [blame]
Eugene Yasmana0e29152013-03-04 19:40:58 +02001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +05302 *
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>
Manu Gautam863b74132012-11-21 14:30:04 +053019#include <linux/of_gpio.h>
20#include <linux/of_device.h>
21#include <linux/clk.h>
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +053022#include <linux/slab.h>
23#include <linux/delay.h>
Eugene Yasman4b1935f2013-08-13 04:08:21 +030024#include <linux/smsc_hub.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070025#include <linux/module.h>
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +053026#include <mach/msm_xo.h>
27
Eugene Yasman4b1935f2013-08-13 04:08:21 +030028static unsigned short normal_i2c[] = {
290, I2C_CLIENT_END };
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +053030
31struct hsic_hub {
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +053032 struct device *dev;
Manu Gautam863b74132012-11-21 14:30:04 +053033 struct smsc_hub_platform_data *pdata;
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +053034 struct i2c_client *client;
35 struct msm_xo_voter *xo_handle;
Manu Gautam863b74132012-11-21 14:30:04 +053036 struct clk *ref_clk;
37 struct regulator *hsic_hub_reg;
38 struct regulator *int_pad_reg, *hub_vbus_reg;
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +053039};
40static struct hsic_hub *smsc_hub;
Manu Gautam863b74132012-11-21 14:30:04 +053041static struct platform_driver smsc_hub_driver;
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +053042
43/* APIs for setting/clearing bits and for reading/writing values */
44static inline int hsic_hub_get_u8(struct i2c_client *client, u8 reg)
45{
46 int ret;
47
48 ret = i2c_smbus_read_byte_data(client, reg);
49 if (ret < 0)
50 pr_err("%s:i2c_read8 failed\n", __func__);
51 return ret;
52}
53
54static inline int hsic_hub_get_u16(struct i2c_client *client, u8 reg)
55{
56 int ret;
57
58 ret = i2c_smbus_read_word_data(client, reg);
59 if (ret < 0)
60 pr_err("%s:i2c_read16 failed\n", __func__);
61 return ret;
62}
63
64static inline int hsic_hub_write_word_data(struct i2c_client *client, u8 reg,
65 u16 value)
66{
67 int ret;
68
69 ret = i2c_smbus_write_word_data(client, reg, value);
70 if (ret)
71 pr_err("%s:i2c_write16 failed\n", __func__);
72 return ret;
73}
74
75static inline int hsic_hub_write_byte_data(struct i2c_client *client, u8 reg,
76 u8 value)
77{
78 int ret;
79
80 ret = i2c_smbus_write_byte_data(client, reg, value);
81 if (ret)
82 pr_err("%s:i2c_write_byte_data failed\n", __func__);
83 return ret;
84}
85
86static inline int hsic_hub_set_bits(struct i2c_client *client, u8 reg,
87 u8 value)
88{
89 int ret;
90
91 ret = i2c_smbus_read_byte_data(client, reg);
92 if (ret < 0) {
93 pr_err("%s:i2c_read_byte_data failed\n", __func__);
94 return ret;
95 }
96 return i2c_smbus_write_byte_data(client, reg, (ret | value));
97}
98
99static inline int hsic_hub_clear_bits(struct i2c_client *client, u8 reg,
100 u8 value)
101{
102 int ret;
103
104 ret = i2c_smbus_read_byte_data(client, reg);
105 if (ret < 0) {
106 pr_err("%s:i2c_read_byte_data failed\n", __func__);
107 return ret;
108 }
109 return i2c_smbus_write_byte_data(client, reg, (ret & ~value));
110}
111
Eugene Yasman4b1935f2013-08-13 04:08:21 +0300112static int smsc4604_send_connect_cmd(struct i2c_client *client)
113{
114 u8 buf[3];
115
116 buf[0] = 0xAA;
117 buf[1] = 0x55;
118 buf[2] = 0x00;
119
120 if (i2c_master_send(client, buf, 3) != 3) {
121 dev_err(&client->dev, "%s: i2c send failed\n", __func__);
122 return -EIO;
123 }
124
125 return 0;
126}
127
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530128static int i2c_hsic_hub_probe(struct i2c_client *client,
129 const struct i2c_device_id *id)
130{
131 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
132 I2C_FUNC_SMBUS_WORD_DATA))
133 return -EIO;
134
Eugene Yasman4b1935f2013-08-13 04:08:21 +0300135 switch (smsc_hub->pdata->model_id) {
136 case SMSC3503_ID:
137 /*
138 * CONFIG_N bit in SP_ILOCK register has to be set before
139 * changing other registers to change default configuration
140 * of hsic hub.
141 */
142 hsic_hub_set_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
Vijayavardhan Vennapusa361da682012-04-12 19:50:02 +0530143
Eugene Yasman4b1935f2013-08-13 04:08:21 +0300144 /*
145 * Can change default configuartion like VID,PID,
146 * strings etc by writing new values to hsic hub registers
147 */
148 hsic_hub_write_word_data(client, SMSC3503_VENDORID, 0x05C6);
Vijayavardhan Vennapusa361da682012-04-12 19:50:02 +0530149
Eugene Yasman4b1935f2013-08-13 04:08:21 +0300150 /*
151 * CONFIG_N bit in SP_ILOCK register has to be cleared
152 * for new values in registers to be effective after
153 * writing to other registers.
154 */
155 hsic_hub_clear_bits(client, SMSC3503_SP_ILOCK, CONFIG_N);
156 break;
157 case SMSC4604_ID:
158 /*
159 * SMSC4604 requires an I2C attach command to be issued
160 * if I2C bus is connected
161 */
162 return smsc4604_send_connect_cmd(client);
163 default:
164 return -EINVAL;
165 }
Vijayavardhan Vennapusa361da682012-04-12 19:50:02 +0530166
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530167 return 0;
168}
169
170static int i2c_hsic_hub_remove(struct i2c_client *client)
171{
172 return 0;
173}
174
175static const struct i2c_device_id hsic_hub_id[] = {
176 {"i2c_hsic_hub", 0},
177 {}
178};
179MODULE_DEVICE_TABLE(i2c, hsichub_id);
180
181static struct i2c_driver hsic_hub_driver = {
182 .driver = {
183 .name = "i2c_hsic_hub",
184 },
185 .probe = i2c_hsic_hub_probe,
186 .remove = i2c_hsic_hub_remove,
187 .id_table = hsic_hub_id,
188};
189
Manu Gautam863b74132012-11-21 14:30:04 +0530190static int msm_hsic_hub_init_clock(struct hsic_hub *hub, int init)
191{
192 int ret;
193
194 if (!init) {
195 if (!IS_ERR(hub->ref_clk))
196 clk_disable_unprepare(hub->ref_clk);
197 else
198 msm_xo_put(smsc_hub->xo_handle);
199
200 return 0;
201 }
202
203 hub->ref_clk = devm_clk_get(hub->dev, "ref_clk");
204 if (IS_ERR(hub->ref_clk)) {
205 dev_dbg(hub->dev, "failed to get ref_clk\n");
206
207 /* In the absence of dedicated ref_clk, xo clocks the HUB */
208 smsc_hub->xo_handle = msm_xo_get(MSM_XO_TCXO_D1, "hsic_hub");
209 if (IS_ERR(smsc_hub->xo_handle)) {
210 dev_err(hub->dev, "not able to get the handle\n"
211 "for TCXO D1 buffer\n");
212 return PTR_ERR(smsc_hub->xo_handle);
213 }
214
215 ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
216 if (ret) {
217 dev_err(hub->dev, "failed to vote for TCXO\n"
218 "D1 buffer\n");
219 msm_xo_put(smsc_hub->xo_handle);
220 return ret;
221 }
222 } else {
223 ret = clk_prepare_enable(hub->ref_clk);
224 if (ret)
225 dev_err(hub->dev, "clk_enable failed for ref_clk\n");
226 }
227
228 return ret;
229}
230#define HSIC_HUB_INT_VOL_MIN 1800000 /* uV */
231#define HSIC_HUB_INT_VOL_MAX 2950000 /* uV */
232static int msm_hsic_hub_init_gpio(struct hsic_hub *hub, int init)
233{
234 int ret;
235 struct smsc_hub_platform_data *pdata = hub->pdata;
236
237 if (!init) {
238 if (!IS_ERR(smsc_hub->int_pad_reg)) {
239 regulator_disable(smsc_hub->int_pad_reg);
240 regulator_set_voltage(smsc_hub->int_pad_reg, 0,
241 HSIC_HUB_INT_VOL_MAX);
242 }
243 return 0;
244 }
245
246 ret = devm_gpio_request(hub->dev, pdata->hub_reset, "HSIC_HUB_RESET");
247 if (ret < 0) {
248 dev_err(hub->dev, "gpio request failed for GPIO%d\n",
249 pdata->hub_reset);
250 return ret;
251 }
252
253 if (pdata->refclk_gpio) {
254 ret = devm_gpio_request(hub->dev, pdata->refclk_gpio,
255 "HSIC_HUB_CLK");
256 if (ret < 0)
257 dev_err(hub->dev, "gpio request failed (CLK GPIO)\n");
258 }
259
260 if (pdata->int_gpio) {
261 ret = devm_gpio_request(hub->dev, pdata->int_gpio,
262 "HSIC_HUB_INT");
263 if (ret < 0) {
264 dev_err(hub->dev, "gpio request failed (INT GPIO)\n");
265 return ret;
266 }
267
268 /* Enable LDO if required for external pull-up */
269 smsc_hub->int_pad_reg = devm_regulator_get(hub->dev, "hub_int");
270 if (IS_ERR(smsc_hub->int_pad_reg)) {
271 dev_dbg(hub->dev, "unable to get ext hub_int reg\n");
272 } else {
273 ret = regulator_set_voltage(smsc_hub->int_pad_reg,
274 HSIC_HUB_INT_VOL_MIN,
275 HSIC_HUB_INT_VOL_MAX);
276 if (ret) {
277 dev_err(hub->dev, "unable to set the voltage\n"
278 " for hsic hub int reg\n");
279 return ret;
280 }
281 ret = regulator_enable(smsc_hub->int_pad_reg);
282 if (ret) {
283 dev_err(hub->dev, "unable to enable int reg\n");
284 regulator_set_voltage(smsc_hub->int_pad_reg, 0,
285 HSIC_HUB_INT_VOL_MAX);
286 return ret;
287 }
288 }
289 }
290
291 return 0;
292}
293
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530294#define HSIC_HUB_VDD_VOL_MIN 1650000 /* uV */
295#define HSIC_HUB_VDD_VOL_MAX 1950000 /* uV */
296#define HSIC_HUB_VDD_LOAD 36000 /* uA */
Manu Gautam863b74132012-11-21 14:30:04 +0530297static int msm_hsic_hub_init_vdd(struct hsic_hub *hub, int init)
298{
299 int ret;
300
301 if (!init) {
302 if (!IS_ERR(smsc_hub->hsic_hub_reg)) {
303 regulator_disable(smsc_hub->hsic_hub_reg);
304 regulator_set_optimum_mode(smsc_hub->hsic_hub_reg, 0);
305 regulator_set_voltage(smsc_hub->hsic_hub_reg, 0,
306 HSIC_HUB_VDD_VOL_MAX);
307 }
308 return 0;
309 }
310
311 smsc_hub->hsic_hub_reg = devm_regulator_get(hub->dev, "EXT_HUB_VDDIO");
312 if (IS_ERR(smsc_hub->hsic_hub_reg)) {
313 dev_dbg(hub->dev, "unable to get ext hub vddcx\n");
314 } else {
315 ret = regulator_set_voltage(smsc_hub->hsic_hub_reg,
316 HSIC_HUB_VDD_VOL_MIN,
317 HSIC_HUB_VDD_VOL_MAX);
318 if (ret) {
319 dev_err(hub->dev, "unable to set the voltage\n"
320 "for hsic hub reg\n");
321 return ret;
322 }
323
324 ret = regulator_set_optimum_mode(smsc_hub->hsic_hub_reg,
325 HSIC_HUB_VDD_LOAD);
326 if (ret < 0) {
327 dev_err(hub->dev, "Unable to set mode of VDDCX\n");
328 goto reg_optimum_mode_fail;
329 }
330
331 ret = regulator_enable(smsc_hub->hsic_hub_reg);
332 if (ret) {
333 dev_err(hub->dev, "unable to enable ext hub vddcx\n");
334 goto reg_enable_fail;
335 }
336 }
337
338 return 0;
339
340reg_enable_fail:
341 regulator_set_optimum_mode(smsc_hub->hsic_hub_reg, 0);
342reg_optimum_mode_fail:
343 regulator_set_voltage(smsc_hub->hsic_hub_reg, 0,
344 HSIC_HUB_VDD_VOL_MAX);
345
346 return ret;
347}
348struct smsc_hub_platform_data *msm_hub_dt_to_pdata(
349 struct platform_device *pdev)
350{
Eugene Yasman4b1935f2013-08-13 04:08:21 +0300351 int rc;
352 u32 temp_val;
Manu Gautam863b74132012-11-21 14:30:04 +0530353 struct device_node *node = pdev->dev.of_node;
354 struct smsc_hub_platform_data *pdata;
355
356 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
357 if (!pdata) {
358 dev_err(&pdev->dev, "unable to allocate platform data\n");
359 return ERR_PTR(-ENOMEM);
360 }
361
Eugene Yasman4b1935f2013-08-13 04:08:21 +0300362 rc = of_property_read_u32(node, "smsc,model-id", &temp_val);
363 if (rc) {
364 dev_err(&pdev->dev, "Unable to read smsc,model-id\n");
365 return ERR_PTR(rc);
366 } else {
367 pdata->model_id = temp_val;
368 }
369
Manu Gautam863b74132012-11-21 14:30:04 +0530370 pdata->hub_reset = of_get_named_gpio(node, "smsc,reset-gpio", 0);
371 if (pdata->hub_reset < 0)
372 return ERR_PTR(pdata->hub_reset);
373
374 pdata->refclk_gpio = of_get_named_gpio(node, "smsc,refclk-gpio", 0);
375 if (pdata->refclk_gpio < 0)
376 pdata->refclk_gpio = 0;
377
378 pdata->int_gpio = of_get_named_gpio(node, "smsc,int-gpio", 0);
379 if (pdata->int_gpio < 0)
380 pdata->int_gpio = 0;
381
382 return pdata;
383}
384
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530385static int __devinit smsc_hub_probe(struct platform_device *pdev)
386{
387 int ret = 0;
388 const struct smsc_hub_platform_data *pdata;
Manu Gautam863b74132012-11-21 14:30:04 +0530389 struct device_node *node = pdev->dev.of_node;
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530390 struct i2c_adapter *i2c_adap;
391 struct i2c_board_info i2c_info;
392
Manu Gautam863b74132012-11-21 14:30:04 +0530393 if (pdev->dev.of_node) {
394 dev_dbg(&pdev->dev, "device tree enabled\n");
395 pdev->dev.platform_data = msm_hub_dt_to_pdata(pdev);
396 if (IS_ERR(pdev->dev.platform_data))
397 return PTR_ERR(pdev->dev.platform_data);
398
399 dev_set_name(&pdev->dev, smsc_hub_driver.driver.name);
400 }
401
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530402 if (!pdev->dev.platform_data) {
403 dev_err(&pdev->dev, "No platform data\n");
404 return -ENODEV;
405 }
406
407 pdata = pdev->dev.platform_data;
408 if (!pdata->hub_reset)
409 return -EINVAL;
410
Manu Gautam863b74132012-11-21 14:30:04 +0530411 smsc_hub = devm_kzalloc(&pdev->dev, sizeof(*smsc_hub), GFP_KERNEL);
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530412 if (!smsc_hub)
413 return -ENOMEM;
414
Manu Gautam863b74132012-11-21 14:30:04 +0530415 smsc_hub->dev = &pdev->dev;
416 smsc_hub->pdata = pdev->dev.platform_data;
417
418 smsc_hub->hub_vbus_reg = devm_regulator_get(&pdev->dev, "hub_vbus");
419 ret = PTR_ERR(smsc_hub->hub_vbus_reg);
420 if (ret == -EPROBE_DEFER) {
421 dev_dbg(&pdev->dev, "failed to get hub_vbus\n");
422 return ret;
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530423 }
424
Manu Gautam863b74132012-11-21 14:30:04 +0530425 ret = msm_hsic_hub_init_vdd(smsc_hub, 1);
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530426 if (ret) {
Manu Gautam863b74132012-11-21 14:30:04 +0530427 dev_err(&pdev->dev, "failed to init hub VDD\n");
428 return ret;
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530429 }
Manu Gautam863b74132012-11-21 14:30:04 +0530430 ret = msm_hsic_hub_init_clock(smsc_hub, 1);
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530431 if (ret) {
Manu Gautam863b74132012-11-21 14:30:04 +0530432 dev_err(&pdev->dev, "failed to init hub clock\n");
433 goto uninit_vdd;
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530434 }
Manu Gautam863b74132012-11-21 14:30:04 +0530435 ret = msm_hsic_hub_init_gpio(smsc_hub, 1);
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530436 if (ret) {
Manu Gautam863b74132012-11-21 14:30:04 +0530437 dev_err(&pdev->dev, "failed to init hub gpios\n");
438 goto uninit_clock;
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530439 }
440
441 gpio_direction_output(pdata->hub_reset, 0);
Eugene Yasman4b1935f2013-08-13 04:08:21 +0300442 /*
443 * Hub reset should be asserted for minimum 2microsec
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530444 * before deasserting.
445 */
446 udelay(5);
447 gpio_direction_output(pdata->hub_reset, 1);
448
Manu Gautam863b74132012-11-21 14:30:04 +0530449 if (!IS_ERR(smsc_hub->hub_vbus_reg)) {
450 ret = regulator_enable(smsc_hub->hub_vbus_reg);
451 if (ret) {
452 dev_err(&pdev->dev, "unable to enable hub_vbus\n");
453 goto uninit_gpio;
454 }
455 }
456
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530457 ret = i2c_add_driver(&hsic_hub_driver);
458 if (ret < 0) {
459 dev_err(&pdev->dev, "failed to add I2C hsic_hub_driver\n");
460 goto i2c_add_fail;
461 }
462 usleep_range(10000, 12000);
463 i2c_adap = i2c_get_adapter(SMSC_GSBI_I2C_BUS_ID);
464
465 if (!i2c_adap) {
466 dev_err(&pdev->dev, "failed to get i2c adapter\n");
467 i2c_del_driver(&hsic_hub_driver);
468 goto i2c_add_fail;
469 }
470
471 memset(&i2c_info, 0, sizeof(struct i2c_board_info));
472 strlcpy(i2c_info.type, "i2c_hsic_hub", I2C_NAME_SIZE);
473
Eugene Yasman4b1935f2013-08-13 04:08:21 +0300474 /* 250ms delay is required for SMSC4604 HUB to get I2C up */
475 msleep(250);
476
477 /* Assign I2C slave address per SMSC model */
478 switch (pdata->model_id) {
479 case SMSC3503_ID:
480 normal_i2c[0] = SMSC3503_I2C_ADDR;
481 break;
482 case SMSC4604_ID:
483 normal_i2c[0] = SMSC4604_I2C_ADDR;
484 break;
485 default:
486 dev_err(&pdev->dev, "unsupported SMSC model-id\n");
487 i2c_put_adapter(i2c_adap);
488 i2c_del_driver(&hsic_hub_driver);
489 goto uninit_gpio;
490 }
491
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530492 smsc_hub->client = i2c_new_probed_device(i2c_adap, &i2c_info,
493 normal_i2c, NULL);
494 i2c_put_adapter(i2c_adap);
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530495
496i2c_add_fail:
Eugene Yasman4b1935f2013-08-13 04:08:21 +0300497 ret = of_platform_populate(node, NULL, NULL, &pdev->dev);
498 if (ret) {
499 dev_err(&pdev->dev, "failed to add child node, ret=%d\n", ret);
500 goto uninit_gpio;
501 }
502
503 if (!smsc_hub->client)
504 dev_err(&pdev->dev,
505 "failed to connect to smsc_hub through I2C\n");
506
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530507 pm_runtime_set_active(&pdev->dev);
508 pm_runtime_enable(&pdev->dev);
509
510 return 0;
511
Manu Gautam863b74132012-11-21 14:30:04 +0530512uninit_gpio:
513 msm_hsic_hub_init_gpio(smsc_hub, 0);
514uninit_clock:
515 msm_hsic_hub_init_clock(smsc_hub, 0);
516uninit_vdd:
517 msm_hsic_hub_init_vdd(smsc_hub, 0);
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530518
519 return ret;
520}
521
522static int smsc_hub_remove(struct platform_device *pdev)
523{
524 const struct smsc_hub_platform_data *pdata;
525
526 pdata = pdev->dev.platform_data;
527 if (smsc_hub->client) {
528 i2c_unregister_device(smsc_hub->client);
529 smsc_hub->client = NULL;
530 i2c_del_driver(&hsic_hub_driver);
531 }
532 pm_runtime_disable(&pdev->dev);
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530533
Eugene Yasmana0e29152013-03-04 19:40:58 +0200534 if (!IS_ERR(smsc_hub->hub_vbus_reg))
535 regulator_disable(smsc_hub->hub_vbus_reg);
Manu Gautam863b74132012-11-21 14:30:04 +0530536 msm_hsic_hub_init_gpio(smsc_hub, 0);
537 msm_hsic_hub_init_clock(smsc_hub, 0);
538 msm_hsic_hub_init_vdd(smsc_hub, 0);
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530539
540 return 0;
541}
542
543#ifdef CONFIG_PM_RUNTIME
544static int msm_smsc_runtime_idle(struct device *dev)
545{
546 dev_dbg(dev, "SMSC HUB runtime idle\n");
547
548 return 0;
549}
550
551static int smsc_hub_lpm_enter(struct device *dev)
552{
Manu Gautam863b74132012-11-21 14:30:04 +0530553 int ret = 0;
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530554
Manu Gautam0417d982013-02-20 12:29:32 +0530555 if (smsc_hub->xo_handle) {
Manu Gautam863b74132012-11-21 14:30:04 +0530556 ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_OFF);
557 if (ret) {
558 pr_err("%s: failed to devote for TCXO\n"
559 "D1 buffer%d\n", __func__, ret);
560 }
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530561 }
562 return ret;
563}
564
565static int smsc_hub_lpm_exit(struct device *dev)
566{
Manu Gautam863b74132012-11-21 14:30:04 +0530567 int ret = 0;
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530568
Manu Gautam0417d982013-02-20 12:29:32 +0530569 if (smsc_hub->xo_handle) {
Manu Gautam863b74132012-11-21 14:30:04 +0530570 ret = msm_xo_mode_vote(smsc_hub->xo_handle, MSM_XO_MODE_ON);
571 if (ret) {
572 pr_err("%s: failed to vote for TCXO\n"
573 "D1 buffer%d\n", __func__, ret);
574 }
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530575 }
576 return ret;
577}
578#endif
579
580#ifdef CONFIG_PM
581static const struct dev_pm_ops smsc_hub_dev_pm_ops = {
582 SET_SYSTEM_SLEEP_PM_OPS(smsc_hub_lpm_enter, smsc_hub_lpm_exit)
583 SET_RUNTIME_PM_OPS(smsc_hub_lpm_enter, smsc_hub_lpm_exit,
584 msm_smsc_runtime_idle)
585};
586#endif
587
Manu Gautam863b74132012-11-21 14:30:04 +0530588static const struct of_device_id hsic_hub_dt_match[] = {
589 { .compatible = "qcom,hsic-smsc-hub",
590 },
591 {}
592};
593MODULE_DEVICE_TABLE(of, hsic_hub_dt_match);
594
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530595static struct platform_driver smsc_hub_driver = {
596 .driver = {
597 .name = "msm_smsc_hub",
598 .owner = THIS_MODULE,
599#ifdef CONFIG_PM
600 .pm = &smsc_hub_dev_pm_ops,
601#endif
Manu Gautam863b74132012-11-21 14:30:04 +0530602 .of_match_table = hsic_hub_dt_match,
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530603 },
Manu Gautam863b74132012-11-21 14:30:04 +0530604 .probe = smsc_hub_probe,
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530605 .remove = smsc_hub_remove,
606};
607
608static int __init smsc_hub_init(void)
609{
Manu Gautam863b74132012-11-21 14:30:04 +0530610 return platform_driver_register(&smsc_hub_driver);
Vijayavardhan Vennapusaafbbb8f2012-04-13 16:28:45 +0530611}
612
613static void __exit smsc_hub_exit(void)
614{
615 platform_driver_unregister(&smsc_hub_driver);
616}
617subsys_initcall(smsc_hub_init);
618module_exit(smsc_hub_exit);
619
620MODULE_LICENSE("GPL v2");
621MODULE_DESCRIPTION("SMSC HSIC HUB driver");