aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/extcon
diff options
context:
space:
mode:
authorGraeme Gregory <gg@slimlogic.co.uk>2013-05-27 21:50:11 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-06-17 19:08:36 -0400
commitb1f254e35d85535b17af2786d06fe88f15f304f7 (patch)
treef20a4fc680fa2af1793ab11e11c09a6d23acad40 /drivers/extcon
parent9c8a013af49cb82a1a47bede56e8ce5efd93b734 (diff)
extcon: Palmas Extcon Driver
This is the driver for the USB comparator built into the palmas chip. It handles the various USB OTG events that can be generated by cable insertion/removal. Signed-off-by: Graeme Gregory <gg@slimlogic.co.uk> Signed-off-by: Moiz Sonasath <m-sonasath@ti.com> Signed-off-by: Ruchika Kharwar <ruchika@ti.com> Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com> Signed-off-by: George Cherian <george.cherian@ti.com> [kishon@ti.com: adapted palmas usb driver to use the extcon framework] Signed-off-by: Sebastien Guiriec <s-guiriec@ti.com> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Myungjoo Ham <myungjoo.ham@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/extcon')
-rw-r--r--drivers/extcon/Kconfig7
-rw-r--r--drivers/extcon/Makefile1
-rw-r--r--drivers/extcon/extcon-palmas.c246
3 files changed, 254 insertions, 0 deletions
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 3297301a42d4..63f454e20576 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -53,4 +53,11 @@ config EXTCON_ARIZONA
53 with Wolfson Arizona devices. These are audio CODECs with 53 with Wolfson Arizona devices. These are audio CODECs with
54 advanced audio accessory detection support. 54 advanced audio accessory detection support.
55 55
56config EXTCON_PALMAS
57 tristate "Palmas USB EXTCON support"
58 depends on MFD_PALMAS
59 help
60 Say Y here to enable support for USB peripheral and USB host
61 detection by palmas usb.
62
56endif # MULTISTATE_SWITCH 63endif # MULTISTATE_SWITCH
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index f98a3c4d46e0..540e2c3a4431 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
8obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o 8obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
9obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o 9obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
10obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o 10obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
11obj-$(CONFIG_EXTCON_PALMAS) += extcon-palmas.o
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c
new file mode 100644
index 000000000000..b752a0ad7b63
--- /dev/null
+++ b/drivers/extcon/extcon-palmas.c
@@ -0,0 +1,246 @@
1/*
2 * Palmas USB transceiver driver
3 *
4 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * Author: Graeme Gregory <gg@slimlogic.co.uk>
11 * Author: Kishon Vijay Abraham I <kishon@ti.com>
12 *
13 * Based on twl6030_usb.c
14 *
15 * Author: Hema HK <hemahk@ti.com>
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 */
22
23#include <linux/module.h>
24#include <linux/interrupt.h>
25#include <linux/platform_device.h>
26#include <linux/err.h>
27#include <linux/mfd/palmas.h>
28#include <linux/of.h>
29#include <linux/of_platform.h>
30
31static const char *palmas_extcon_cable[] = {
32 [0] = "USB",
33 [1] = "USB-HOST",
34 NULL,
35};
36
37static const int mutually_exclusive[] = {0x3, 0x0};
38
39static void palmas_usb_wakeup(struct palmas *palmas, int enable)
40{
41 if (enable)
42 palmas_write(palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_WAKEUP,
43 PALMAS_USB_WAKEUP_ID_WK_UP_COMP);
44 else
45 palmas_write(palmas, PALMAS_USB_OTG_BASE, PALMAS_USB_WAKEUP, 0);
46}
47
48static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
49{
50 struct palmas_usb *palmas_usb = _palmas_usb;
51 unsigned int vbus_line_state;
52
53 palmas_read(palmas_usb->palmas, PALMAS_INTERRUPT_BASE,
54 PALMAS_INT3_LINE_STATE, &vbus_line_state);
55
56 if (vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS) {
57 if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) {
58 palmas_usb->linkstat = PALMAS_USB_STATE_VBUS;
59 extcon_set_cable_state(&palmas_usb->edev, "USB", true);
60 } else {
61 dev_dbg(palmas_usb->dev,
62 "Spurious connect event detected\n");
63 }
64 } else if (!(vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS)) {
65 if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) {
66 palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
67 extcon_set_cable_state(&palmas_usb->edev, "USB", false);
68 } else {
69 dev_dbg(palmas_usb->dev,
70 "Spurious disconnect event detected\n");
71 }
72 }
73
74 return IRQ_HANDLED;
75}
76
77static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
78{
79 unsigned int set;
80 struct palmas_usb *palmas_usb = _palmas_usb;
81
82 palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
83 PALMAS_USB_ID_INT_LATCH_SET, &set);
84
85 if (set & PALMAS_USB_ID_INT_SRC_ID_GND) {
86 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
87 PALMAS_USB_ID_INT_EN_HI_SET,
88 PALMAS_USB_ID_INT_EN_HI_SET_ID_FLOAT);
89 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
90 PALMAS_USB_ID_INT_EN_HI_CLR,
91 PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
92 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
93 PALMAS_USB_ID_INT_LATCH_CLR,
94 PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
95 palmas_usb->linkstat = PALMAS_USB_STATE_ID;
96 extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true);
97 } else if (set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) {
98 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
99 PALMAS_USB_ID_INT_EN_HI_SET,
100 PALMAS_USB_ID_INT_EN_HI_SET_ID_GND);
101 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
102 PALMAS_USB_ID_INT_EN_HI_CLR,
103 PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
104 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
105 PALMAS_USB_ID_INT_LATCH_CLR,
106 PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
107 palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
108 extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
109 }
110
111 return IRQ_HANDLED;
112}
113
114static void palmas_enable_irq(struct palmas_usb *palmas_usb)
115{
116 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
117 PALMAS_USB_VBUS_CTRL_SET,
118 PALMAS_USB_VBUS_CTRL_SET_VBUS_ACT_COMP);
119
120 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
121 PALMAS_USB_ID_CTRL_SET, PALMAS_USB_ID_CTRL_SET_ID_ACT_COMP);
122
123 palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
124 PALMAS_USB_ID_INT_EN_HI_SET,
125 PALMAS_USB_ID_INT_EN_HI_SET_ID_GND);
126
127 palmas_vbus_irq_handler(palmas_usb->vbus_irq, palmas_usb);
128
129 /* cold plug for host mode needs this delay */
130 msleep(30);
131 palmas_id_irq_handler(palmas_usb->id_irq, palmas_usb);
132}
133
134static int palmas_usb_probe(struct platform_device *pdev)
135{
136 struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
137 struct palmas_usb_platform_data *pdata = pdev->dev.platform_data;
138 struct device_node *node = pdev->dev.of_node;
139 struct palmas_usb *palmas_usb;
140 int status;
141
142 if (node && !pdata) {
143 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
144
145 if (!pdata)
146 return -ENOMEM;
147
148 pdata->wakeup = of_property_read_bool(node, "ti,wakeup");
149 } else if (!pdata) {
150 return -EINVAL;
151 }
152
153 palmas_usb = devm_kzalloc(&pdev->dev, sizeof(*palmas_usb), GFP_KERNEL);
154 if (!palmas_usb)
155 return -ENOMEM;
156
157 palmas->usb = palmas_usb;
158 palmas_usb->palmas = palmas;
159
160 palmas_usb->dev = &pdev->dev;
161
162 palmas_usb->id_otg_irq = regmap_irq_get_virq(palmas->irq_data,
163 PALMAS_ID_OTG_IRQ);
164 palmas_usb->id_irq = regmap_irq_get_virq(palmas->irq_data,
165 PALMAS_ID_IRQ);
166 palmas_usb->vbus_otg_irq = regmap_irq_get_virq(palmas->irq_data,
167 PALMAS_VBUS_OTG_IRQ);
168 palmas_usb->vbus_irq = regmap_irq_get_virq(palmas->irq_data,
169 PALMAS_VBUS_IRQ);
170
171 palmas_usb_wakeup(palmas, pdata->wakeup);
172
173 platform_set_drvdata(pdev, palmas_usb);
174
175 palmas_usb->edev.name = "palmas-usb";
176 palmas_usb->edev.supported_cable = palmas_extcon_cable;
177 palmas_usb->edev.mutually_exclusive = mutually_exclusive;
178
179 status = extcon_dev_register(&palmas_usb->edev, palmas_usb->dev);
180 if (status) {
181 dev_err(&pdev->dev, "failed to register extcon device\n");
182 return status;
183 }
184
185 status = devm_request_threaded_irq(palmas_usb->dev, palmas_usb->id_irq,
186 NULL, palmas_id_irq_handler,
187 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
188 "palmas_usb_id", palmas_usb);
189 if (status < 0) {
190 dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
191 palmas_usb->id_irq, status);
192 goto fail_extcon;
193 }
194
195 status = devm_request_threaded_irq(palmas_usb->dev,
196 palmas_usb->vbus_irq, NULL, palmas_vbus_irq_handler,
197 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
198 "palmas_usb_vbus", palmas_usb);
199 if (status < 0) {
200 dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
201 palmas_usb->vbus_irq, status);
202 goto fail_extcon;
203 }
204
205 palmas_enable_irq(palmas_usb);
206
207 return 0;
208
209fail_extcon:
210 extcon_dev_unregister(&palmas_usb->edev);
211
212 return status;
213}
214
215static int palmas_usb_remove(struct platform_device *pdev)
216{
217 struct palmas_usb *palmas_usb = platform_get_drvdata(pdev);
218
219 extcon_dev_unregister(&palmas_usb->edev);
220
221 return 0;
222}
223
224static struct of_device_id of_palmas_match_tbl[] = {
225 { .compatible = "ti,palmas-usb", },
226 { .compatible = "ti,twl6035-usb", },
227 { /* end */ }
228};
229
230static struct platform_driver palmas_usb_driver = {
231 .probe = palmas_usb_probe,
232 .remove = palmas_usb_remove,
233 .driver = {
234 .name = "palmas-usb",
235 .of_match_table = of_palmas_match_tbl,
236 .owner = THIS_MODULE,
237 },
238};
239
240module_platform_driver(palmas_usb_driver);
241
242MODULE_ALIAS("platform:palmas-usb");
243MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
244MODULE_DESCRIPTION("Palmas USB transceiver driver");
245MODULE_LICENSE("GPL");
246MODULE_DEVICE_TABLE(of, of_palmas_match_tbl);