2 * Driver for SMSC USB4604 USB HSIC 4-port 2.0 hub controller driver
3 * Based on usb3503 driver
5 * Copyright (c) 2012-2013 Dongjin Kim (tobetter@gmail.com)
6 * Copyright (c) 2016 Linaro Ltd.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
19 #include <linux/i2c.h>
20 #include <linux/delay.h>
21 #include <linux/slab.h>
22 #include <linux/module.h>
23 #include <linux/gpio/consumer.h>
32 enum usb4604_mode mode
;
34 struct gpio_desc
*gpio_reset
;
37 static void usb4604_reset(struct usb4604
*hub
, int state
)
39 gpiod_set_value_cansleep(hub
->gpio_reset
, state
);
41 /* Wait for i2c logic to come up */
46 static int usb4604_connect(struct usb4604
*hub
)
48 struct device
*dev
= hub
->dev
;
49 struct i2c_client
*client
= to_i2c_client(dev
);
51 u8 connect_cmd
[] = { 0xaa, 0x55, 0x00 };
53 usb4604_reset(hub
, 1);
55 err
= i2c_master_send(client
, connect_cmd
, ARRAY_SIZE(connect_cmd
));
57 usb4604_reset(hub
, 0);
61 hub
->mode
= USB4604_MODE_HUB
;
62 dev_dbg(dev
, "switched to HUB mode\n");
67 static int usb4604_switch_mode(struct usb4604
*hub
, enum usb4604_mode mode
)
69 struct device
*dev
= hub
->dev
;
73 case USB4604_MODE_HUB
:
74 err
= usb4604_connect(hub
);
77 case USB4604_MODE_STANDBY
:
78 usb4604_reset(hub
, 0);
79 dev_dbg(dev
, "switched to STANDBY mode\n");
83 dev_err(dev
, "unknown mode is requested\n");
91 static int usb4604_probe(struct usb4604
*hub
)
93 struct device
*dev
= hub
->dev
;
94 struct device_node
*np
= dev
->of_node
;
95 struct gpio_desc
*gpio
;
96 u32 mode
= USB4604_MODE_HUB
;
98 gpio
= devm_gpiod_get_optional(dev
, "reset", GPIOD_OUT_LOW
);
100 return PTR_ERR(gpio
);
101 hub
->gpio_reset
= gpio
;
103 if (of_property_read_u32(np
, "initial-mode", &hub
->mode
))
106 return usb4604_switch_mode(hub
, hub
->mode
);
109 static int usb4604_i2c_probe(struct i2c_client
*i2c
,
110 const struct i2c_device_id
*id
)
114 hub
= devm_kzalloc(&i2c
->dev
, sizeof(*hub
), GFP_KERNEL
);
118 i2c_set_clientdata(i2c
, hub
);
119 hub
->dev
= &i2c
->dev
;
121 return usb4604_probe(hub
);
124 #ifdef CONFIG_PM_SLEEP
125 static int usb4604_i2c_suspend(struct device
*dev
)
127 struct i2c_client
*client
= to_i2c_client(dev
);
128 struct usb4604
*hub
= i2c_get_clientdata(client
);
130 usb4604_switch_mode(hub
, USB4604_MODE_STANDBY
);
135 static int usb4604_i2c_resume(struct device
*dev
)
137 struct i2c_client
*client
= to_i2c_client(dev
);
138 struct usb4604
*hub
= i2c_get_clientdata(client
);
140 usb4604_switch_mode(hub
, hub
->mode
);
146 static SIMPLE_DEV_PM_OPS(usb4604_i2c_pm_ops
, usb4604_i2c_suspend
,
149 static const struct i2c_device_id usb4604_id
[] = {
153 MODULE_DEVICE_TABLE(i2c
, usb4604_id
);
156 static const struct of_device_id usb4604_of_match
[] = {
157 { .compatible
= "smsc,usb4604" },
160 MODULE_DEVICE_TABLE(of
, usb4604_of_match
);
163 static struct i2c_driver usb4604_i2c_driver
= {
166 .pm
= &usb4604_i2c_pm_ops
,
167 .of_match_table
= of_match_ptr(usb4604_of_match
),
169 .probe
= usb4604_i2c_probe
,
170 .id_table
= usb4604_id
,
172 module_i2c_driver(usb4604_i2c_driver
);
174 MODULE_DESCRIPTION("USB4604 USB HUB driver");
175 MODULE_LICENSE("GPL v2");