aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoger Quadros <rogerq@ti.com>2015-08-03 10:40:51 -0400
committerChanwoo Choi <cw00.choi@samsung.com>2015-08-10 08:26:25 -0400
commit92b7cb5dc885b38b21093eefed8028b615952965 (patch)
treede56922baf3fee8dd9ec7c7f9a43599de61c07f0
parenta598af7f0279195abffbfb9bf2070457e9c89ff3 (diff)
extcon: palmas: Support GPIO based USB ID detection
Some palmas based chip variants do not have OTG based ID logic. For these variants we rely on GPIO based USB ID detection. These chips do have VBUS comparator for VBUS detection so we continue to use the old way of detecting VBUS. Signed-off-by: Roger Quadros <rogerq@ti.com> Acked-by: Chanwoo Choi <cw00.choi@samsung.com> Acked-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
-rw-r--r--Documentation/devicetree/bindings/extcon/extcon-palmas.txt5
-rw-r--r--drivers/extcon/extcon-palmas.c129
-rw-r--r--drivers/extcon/extcon-usb-gpio.c1
-rw-r--r--include/linux/mfd/palmas.h7
4 files changed, 126 insertions, 16 deletions
diff --git a/Documentation/devicetree/bindings/extcon/extcon-palmas.txt b/Documentation/devicetree/bindings/extcon/extcon-palmas.txt
index 45414bbcd945..f61d5af44a27 100644
--- a/Documentation/devicetree/bindings/extcon/extcon-palmas.txt
+++ b/Documentation/devicetree/bindings/extcon/extcon-palmas.txt
@@ -10,8 +10,11 @@ Required Properties:
10 10
11Optional Properties: 11Optional Properties:
12 - ti,wakeup : To enable the wakeup comparator in probe 12 - ti,wakeup : To enable the wakeup comparator in probe
13 - ti,enable-id-detection: Perform ID detection. 13 - ti,enable-id-detection: Perform ID detection. If id-gpio is specified
14 it performs id-detection using GPIO else using OTG core.
14 - ti,enable-vbus-detection: Perform VBUS detection. 15 - ti,enable-vbus-detection: Perform VBUS detection.
16 - id-gpio: gpio for GPIO ID detection. See gpio binding.
17 - debounce-delay-ms: debounce delay for GPIO ID pin in milliseconds.
15 18
16palmas-usb { 19palmas-usb {
17 compatible = "ti,twl6035-usb", "ti,palmas-usb"; 20 compatible = "ti,twl6035-usb", "ti,palmas-usb";
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c
index 8933e7e0d9da..662e91778cb0 100644
--- a/drivers/extcon/extcon-palmas.c
+++ b/drivers/extcon/extcon-palmas.c
@@ -28,6 +28,10 @@
28#include <linux/mfd/palmas.h> 28#include <linux/mfd/palmas.h>
29#include <linux/of.h> 29#include <linux/of.h>
30#include <linux/of_platform.h> 30#include <linux/of_platform.h>
31#include <linux/of_gpio.h>
32#include <linux/workqueue.h>
33
34#define USB_GPIO_DEBOUNCE_MS 20 /* ms */
31 35
32static const unsigned int palmas_extcon_cable[] = { 36static const unsigned int palmas_extcon_cable[] = {
33 EXTCON_USB, 37 EXTCON_USB,
@@ -118,19 +122,54 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
118 return IRQ_HANDLED; 122 return IRQ_HANDLED;
119} 123}
120 124
125static void palmas_gpio_id_detect(struct work_struct *work)
126{
127 int id;
128 struct palmas_usb *palmas_usb = container_of(to_delayed_work(work),
129 struct palmas_usb,
130 wq_detectid);
131 struct extcon_dev *edev = palmas_usb->edev;
132
133 if (!palmas_usb->id_gpiod)
134 return;
135
136 id = gpiod_get_value_cansleep(palmas_usb->id_gpiod);
137
138 if (id) {
139 extcon_set_cable_state_(edev, EXTCON_USB_HOST, false);
140 dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
141 } else {
142 extcon_set_cable_state_(edev, EXTCON_USB_HOST, true);
143 dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
144 }
145}
146
147static irqreturn_t palmas_gpio_id_irq_handler(int irq, void *_palmas_usb)
148{
149 struct palmas_usb *palmas_usb = _palmas_usb;
150
151 queue_delayed_work(system_power_efficient_wq, &palmas_usb->wq_detectid,
152 palmas_usb->sw_debounce_jiffies);
153
154 return IRQ_HANDLED;
155}
156
121static void palmas_enable_irq(struct palmas_usb *palmas_usb) 157static void palmas_enable_irq(struct palmas_usb *palmas_usb)
122{ 158{
123 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, 159 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
124 PALMAS_USB_VBUS_CTRL_SET, 160 PALMAS_USB_VBUS_CTRL_SET,
125 PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP); 161 PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP);
126 162
127 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, 163 if (palmas_usb->enable_id_detection) {
128 PALMAS_USB_ID_CTRL_SET, PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP); 164 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
165 PALMAS_USB_ID_CTRL_SET,
166 PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP);
129 167
130 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, 168 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
131 PALMAS_USB_ID_INT_EN_HI_SET, 169 PALMAS_USB_ID_INT_EN_HI_SET,
132 PALMAS_USB_ID_INT_EN_HI_SET_ID_GND | 170 PALMAS_USB_ID_INT_EN_HI_SET_ID_GND |
133 PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT); 171 PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
172 }
134 173
135 if (palmas_usb->enable_vbus_detection) 174 if (palmas_usb->enable_vbus_detection)
136 palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb); 175 palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb);
@@ -169,20 +208,36 @@ static int palmas_usb_probe(struct platform_device *pdev)
169 palmas_usb->wakeup = pdata->wakeup; 208 palmas_usb->wakeup = pdata->wakeup;
170 } 209 }
171 210
211 palmas_usb->id_gpiod = devm_gpiod_get_optional(&pdev->dev, "id");
212 if (IS_ERR(palmas_usb->id_gpiod)) {
213 dev_err(&pdev->dev, "failed to get id gpio\n");
214 return PTR_ERR(palmas_usb->id_gpiod);
215 }
216
217 if (palmas_usb->enable_id_detection && palmas_usb->id_gpiod) {
218 palmas_usb->enable_id_detection = false;
219 palmas_usb->enable_gpio_id_detection = true;
220 }
221
222 if (palmas_usb->enable_gpio_id_detection) {
223 u32 debounce;
224
225 if (of_property_read_u32(node, "debounce-delay-ms", &debounce))
226 debounce = USB_GPIO_DEBOUNCE_MS;
227
228 status = gpiod_set_debounce(palmas_usb->id_gpiod,
229 debounce * 1000);
230 if (status < 0)
231 palmas_usb->sw_debounce_jiffies = msecs_to_jiffies(debounce);
232 }
233
234 INIT_DELAYED_WORK(&palmas_usb->wq_detectid, palmas_gpio_id_detect);
235
172 palmas->usb = palmas_usb; 236 palmas->usb = palmas_usb;
173 palmas_usb->palmas = palmas; 237 palmas_usb->palmas = palmas;
174 238
175 palmas_usb->dev = &pdev->dev; 239 palmas_usb->dev = &pdev->dev;
176 240
177 palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data,
178 PALMAS_ID_OTG_IRQ);
179 palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data,
180 PALMAS_ID_IRQ);
181 palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data,
182 PALMAS_VBUS_OTG_IRQ);
183 palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data,
184 PALMAS_VBUS_IRQ);
185
186 palmas_usb_wakeup(palmas, palmas_usb->wakeup); 241 palmas_usb_wakeup(palmas, palmas_usb->wakeup);
187 242
188 platform_set_drvdata(pdev, palmas_usb); 243 platform_set_drvdata(pdev, palmas_usb);
@@ -201,6 +256,10 @@ static int palmas_usb_probe(struct platform_device *pdev)
201 } 256 }
202 257
203 if (palmas_usb->enable_id_detection) { 258 if (palmas_usb->enable_id_detection) {
259 palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data,
260 PALMAS_ID_OTG_IRQ);
261 palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data,
262 PALMAS_ID_IRQ);
204 status = devm_request_threaded_irq(palmas_usb->dev, 263 status = devm_request_threaded_irq(palmas_usb->dev,
205 palmas_usb->id_irq, 264 palmas_usb->id_irq,
206 NULL, palmas_id_irq_handler, 265 NULL, palmas_id_irq_handler,
@@ -212,9 +271,33 @@ static int palmas_usb_probe(struct platform_device *pdev)
212 palmas_usb->id_irq, status); 271 palmas_usb->id_irq, status);
213 return status; 272 return status;
214 } 273 }
274 } else if (palmas_usb->enable_gpio_id_detection) {
275 palmas_usb->gpio_id_irq = gpiod_to_irq(palmas_usb->id_gpiod);
276 if (palmas_usb->gpio_id_irq < 0) {
277 dev_err(&pdev->dev, "failed to get id irq\n");
278 return palmas_usb->gpio_id_irq;
279 }
280 status = devm_request_threaded_irq(&pdev->dev,
281 palmas_usb->gpio_id_irq,
282 NULL,
283 palmas_gpio_id_irq_handler,
284 IRQF_TRIGGER_RISING |
285 IRQF_TRIGGER_FALLING |
286 IRQF_ONESHOT,
287 "palmas_usb_id",
288 palmas_usb);
289 if (status < 0) {
290 dev_err(&pdev->dev,
291 "failed to request handler for id irq\n");
292 return status;
293 }
215 } 294 }
216 295
217 if (palmas_usb->enable_vbus_detection) { 296 if (palmas_usb->enable_vbus_detection) {
297 palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data,
298 PALMAS_VBUS_OTG_IRQ);
299 palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data,
300 PALMAS_VBUS_IRQ);
218 status = devm_request_threaded_irq(palmas_usb->dev, 301 status = devm_request_threaded_irq(palmas_usb->dev,
219 palmas_usb->vbus_irq, NULL, 302 palmas_usb->vbus_irq, NULL,
220 palmas_vbus_irq_handler, 303 palmas_vbus_irq_handler,
@@ -229,10 +312,21 @@ static int palmas_usb_probe(struct platform_device *pdev)
229 } 312 }
230 313
231 palmas_enable_irq(palmas_usb); 314 palmas_enable_irq(palmas_usb);
315 /* perform initial detection */
316 palmas_gpio_id_detect(&palmas_usb->wq_detectid.work);
232 device_set_wakeup_capable(&pdev->dev, true); 317 device_set_wakeup_capable(&pdev->dev, true);
233 return 0; 318 return 0;
234} 319}
235 320
321static int palmas_usb_remove(struct platform_device *pdev)
322{
323 struct palmas_usb *palmas_usb = platform_get_drvdata(pdev);
324
325 cancel_delayed_work_sync(&palmas_usb->wq_detectid);
326
327 return 0;
328}
329
236#ifdef CONFIG_PM_SLEEP 330#ifdef CONFIG_PM_SLEEP
237static int palmas_usb_suspend(struct device *dev) 331static int palmas_usb_suspend(struct device *dev)
238{ 332{
@@ -243,6 +337,8 @@ static int palmas_usb_suspend(struct device *dev)
243 enable_irq_wake(palmas_usb->vbus_irq); 337 enable_irq_wake(palmas_usb->vbus_irq);
244 if (palmas_usb->enable_id_detection) 338 if (palmas_usb->enable_id_detection)
245 enable_irq_wake(palmas_usb->id_irq); 339 enable_irq_wake(palmas_usb->id_irq);
340 if (palmas_usb->enable_gpio_id_detection)
341 enable_irq_wake(palmas_usb->gpio_id_irq);
246 } 342 }
247 return 0; 343 return 0;
248} 344}
@@ -256,6 +352,8 @@ static int palmas_usb_resume(struct device *dev)
256 disable_irq_wake(palmas_usb->vbus_irq); 352 disable_irq_wake(palmas_usb->vbus_irq);
257 if (palmas_usb->enable_id_detection) 353 if (palmas_usb->enable_id_detection)
258 disable_irq_wake(palmas_usb->id_irq); 354 disable_irq_wake(palmas_usb->id_irq);
355 if (palmas_usb->enable_gpio_id_detection)
356 disable_irq_wake(palmas_usb->gpio_id_irq);
259 } 357 }
260 return 0; 358 return 0;
261}; 359};
@@ -273,6 +371,7 @@ static const struct of_device_id of_palmas_match_tbl[] = {
273 371
274static struct platform_driver palmas_usb_driver = { 372static struct platform_driver palmas_usb_driver = {
275 .probe = palmas_usb_probe, 373 .probe = palmas_usb_probe,
374 .remove = palmas_usb_remove,
276 .driver = { 375 .driver = {
277 .name = "palmas-usb", 376 .name = "palmas-usb",
278 .of_match_table = of_palmas_match_tbl, 377 .of_match_table = of_palmas_match_tbl,
diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c
index a2a44536a608..2b2fecffb1ad 100644
--- a/drivers/extcon/extcon-usb-gpio.c
+++ b/drivers/extcon/extcon-usb-gpio.c
@@ -15,6 +15,7 @@
15 */ 15 */
16 16
17#include <linux/extcon.h> 17#include <linux/extcon.h>
18#include <linux/gpio.h>
18#include <linux/gpio/consumer.h> 19#include <linux/gpio/consumer.h>
19#include <linux/init.h> 20#include <linux/init.h>
20#include <linux/interrupt.h> 21#include <linux/interrupt.h>
diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h
index bb270bd03eed..13e1d96935ed 100644
--- a/include/linux/mfd/palmas.h
+++ b/include/linux/mfd/palmas.h
@@ -21,6 +21,7 @@
21#include <linux/regmap.h> 21#include <linux/regmap.h>
22#include <linux/regulator/driver.h> 22#include <linux/regulator/driver.h>
23#include <linux/extcon.h> 23#include <linux/extcon.h>
24#include <linux/of_gpio.h>
24#include <linux/usb/phy_companion.h> 25#include <linux/usb/phy_companion.h>
25 26
26#define PALMAS_NUM_CLIENTS 3 27#define PALMAS_NUM_CLIENTS 3
@@ -551,10 +552,16 @@ struct palmas_usb {
551 int vbus_otg_irq; 552 int vbus_otg_irq;
552 int vbus_irq; 553 int vbus_irq;
553 554
555 int gpio_id_irq;
556 struct gpio_desc *id_gpiod;
557 unsigned long sw_debounce_jiffies;
558 struct delayed_work wq_detectid;
559
554 enum palmas_usb_state linkstat; 560 enum palmas_usb_state linkstat;
555 int wakeup; 561 int wakeup;
556 bool enable_vbus_detection; 562 bool enable_vbus_detection;
557 bool enable_id_detection; 563 bool enable_id_detection;
564 bool enable_gpio_id_detection;
558}; 565};
559 566
560#define comparator_to_palmas(x) container_of((x), struct palmas_usb, comparator) 567#define comparator_to_palmas(x) container_of((x), struct palmas_usb, comparator)