blob: 51c08c68426259b9955ecf131c1ea5c2fe946a72 [file] [log] [blame]
Jack Pham4e9dff72017-04-04 18:05:53 -07001/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -07002 *
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/kernel.h>
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/interrupt.h>
17#include <linux/err.h>
18#include <linux/platform_device.h>
19#include <linux/extcon.h>
20#include <linux/delay.h>
21#include <linux/sysfs.h>
22#include <linux/io.h>
23#include <linux/bitops.h>
24#include <linux/tty.h>
25#include <linux/tty_flip.h>
26#include <linux/serial_core.h>
27#include <linux/serial.h>
Channagoud Kadabi75f54e82016-12-06 16:35:10 -080028#include <linux/workqueue.h>
Channagoud Kadabi0c1fec12017-05-24 16:47:18 -070029#include <linux/power_supply.h>
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -070030
31#define EUD_ENABLE_CMD 1
32#define EUD_DISABLE_CMD 0
33
34#define EUD_REG_COM_TX_ID 0x0000
35#define EUD_REG_COM_TX_LEN 0x0004
36#define EUD_REG_COM_TX_DAT 0x0008
37#define EUD_REG_COM_RX_ID 0x000C
38#define EUD_REG_COM_RX_LEN 0x0010
39#define EUD_REG_COM_RX_DAT 0x0014
40#define EUD_REG_INT1_EN_MASK 0x0024
41#define EUD_REG_INT_STATUS_1 0x0044
42#define EUD_REG_CTL_OUT_1 0x0074
43#define EUD_REG_VBUS_INT_CLR 0x0080
44#define EUD_REG_CHGR_INT_CLR 0x0084
45#define EUD_REG_CSR_EUD_EN 0x1014
46#define EUD_REG_SW_ATTACH_DET 0x1018
47
48#define EUD_INT_RX BIT(0)
49#define EUD_INT_TX BIT(1)
50#define EUD_INT_VBUS BIT(2)
51#define EUD_INT_CHGR BIT(3)
52#define EUD_INT_SAFE_MODE BIT(4)
53#define EUD_INT_ALL (EUD_INT_RX | EUD_INT_TX | \
54 EUD_INT_VBUS | EUD_INT_CHGR | \
55 EUD_INT_SAFE_MODE)
56
57#define EUD_NR 1
58#define EUD_CONSOLE NULL
59#define UART_ID 0x90
60#define MAX_FIFO_SIZE 14
61
62struct eud_chip {
63 struct device *dev;
64 int eud_irq;
Channagoud Kadabi75f54e82016-12-06 16:35:10 -080065 unsigned int extcon_id;
66 unsigned int int_status;
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -070067 bool usb_attach;
68 bool chgr_enable;
69 void __iomem *eud_reg_base;
70 struct extcon_dev *extcon;
71 struct uart_port port;
Channagoud Kadabi75f54e82016-12-06 16:35:10 -080072 struct work_struct eud_work;
Harry Yange2dd0e52017-08-03 14:50:32 -070073 struct power_supply *batt_psy;
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -070074};
75
76static const unsigned int eud_extcon_cable[] = {
77 EXTCON_USB,
78 EXTCON_CHG_USB_SDP,
79 EXTCON_NONE,
80};
81
82/*
83 * On the kernel command line specify eud.enable=1 to enable EUD.
84 * EUD is disabled by default.
85 */
86static int enable;
87static struct platform_device *eud_private;
88
89static void enable_eud(struct platform_device *pdev)
90{
91 struct eud_chip *priv = platform_get_drvdata(pdev);
Channagoud Kadabi0c1fec12017-05-24 16:47:18 -070092 struct power_supply *usb_psy = NULL;
93 union power_supply_propval pval = {0};
94 union power_supply_propval tval = {0};
95 int ret;
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -070096
Channagoud Kadabi0c1fec12017-05-24 16:47:18 -070097 usb_psy = power_supply_get_by_name("usb");
98 if (!usb_psy) {
99 dev_warn(&pdev->dev, "Could not get usb power_supply\n");
100 return;
101 }
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800102
Channagoud Kadabi0c1fec12017-05-24 16:47:18 -0700103 ret = power_supply_get_property(usb_psy,
104 POWER_SUPPLY_PROP_PRESENT, &pval);
105 if (ret) {
106 dev_err(&pdev->dev, "Unable to read USB PRESENT: %x\n", ret);
107 return;
108 }
109
110 ret = power_supply_get_property(usb_psy,
111 POWER_SUPPLY_PROP_REAL_TYPE, &tval);
112 if (ret) {
113 dev_err(&pdev->dev, "Unable to read USB TYPE: %x\n", ret);
114 return;
115 }
116
117 if (pval.intval && (tval.intval == POWER_SUPPLY_TYPE_USB ||
118 tval.intval == POWER_SUPPLY_TYPE_USB_CDP)) {
119 /* write into CSR to enable EUD */
120 writel_relaxed(BIT(0), priv->eud_reg_base + EUD_REG_CSR_EUD_EN);
121 /* Enable vbus, chgr & safe mode warning interrupts */
122 writel_relaxed(EUD_INT_VBUS | EUD_INT_CHGR | EUD_INT_SAFE_MODE,
123 priv->eud_reg_base + EUD_REG_INT1_EN_MASK);
124
125 /* Ensure Register Writes Complete */
126 wmb();
127
128 /*
129 * Set the default cable state to usb connect and charger
130 * enable
131 */
132 extcon_set_state_sync(priv->extcon, EXTCON_USB, true);
133 extcon_set_state_sync(priv->extcon, EXTCON_CHG_USB_SDP, true);
134 } else {
135 dev_warn(&pdev->dev, "Connect USB cable before enabling EUD\n");
136 return;
137 }
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800138
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700139 dev_dbg(&pdev->dev, "%s: EUD Enabled!\n", __func__);
140}
141
142static void disable_eud(struct platform_device *pdev)
143{
144 struct eud_chip *priv = platform_get_drvdata(pdev);
145
146 /* write into CSR to disable EUD */
147 writel_relaxed(0, priv->eud_reg_base + EUD_REG_CSR_EUD_EN);
148 dev_dbg(&pdev->dev, "%s: EUD Disabled!\n", __func__);
149}
150
151static int param_eud_set(const char *val, const struct kernel_param *kp)
152{
153 int enable = 0;
154
155 if (sscanf(val, "%du", &enable) != 1)
156 return -EINVAL;
157
158 if (enable != EUD_ENABLE_CMD && enable != EUD_DISABLE_CMD)
159 return -EINVAL;
160
161 if (enable == EUD_ENABLE_CMD) {
162 pr_debug("%s: Enbling EUD\n", __func__);
163 enable_eud(eud_private);
164 } else if (enable == EUD_DISABLE_CMD) {
165 pr_debug("%s: Disabling EUD\n", __func__);
166 disable_eud(eud_private);
167 }
168
169 *((uint *)kp->arg) = enable;
170 return 0;
171}
172
173static const struct kernel_param_ops eud_param_ops = {
174 .set = param_eud_set,
175 .get = param_get_int,
176};
177
178module_param_cb(enable, &eud_param_ops, &enable, 0644);
179
Harry Yange2dd0e52017-08-03 14:50:32 -0700180static bool is_batt_available(struct eud_chip *chip)
181{
182 if (!chip->batt_psy)
183 chip->batt_psy = power_supply_get_by_name("battery");
184
185 if (!chip->batt_psy)
186 return false;
187
188 return true;
189}
190
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800191static void eud_event_notifier(struct work_struct *eud_work)
192{
193 struct eud_chip *chip = container_of(eud_work, struct eud_chip,
194 eud_work);
Harry Yange2dd0e52017-08-03 14:50:32 -0700195 union power_supply_propval pval;
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800196
197 if (chip->int_status == EUD_INT_VBUS)
Jack Pham4e9dff72017-04-04 18:05:53 -0700198 extcon_set_state_sync(chip->extcon, chip->extcon_id,
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800199 chip->usb_attach);
Harry Yange2dd0e52017-08-03 14:50:32 -0700200 else if (chip->int_status == EUD_INT_CHGR) {
201 if (is_batt_available(chip)) {
202 pval.intval = !chip->chgr_enable;
203 power_supply_set_property(chip->batt_psy,
204 POWER_SUPPLY_PROP_INPUT_SUSPEND, &pval);
205 }
206 }
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800207}
208
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700209static void usb_attach_detach(struct eud_chip *chip)
210{
211 u32 reg;
212
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800213 chip->extcon_id = EXTCON_USB;
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700214 /* read ctl_out_1[4] to find USB attach or detach event */
215 reg = readl_relaxed(chip->eud_reg_base + EUD_REG_CTL_OUT_1);
216 if (reg & BIT(4))
217 chip->usb_attach = true;
218 else
219 chip->usb_attach = false;
220
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800221 schedule_work(&chip->eud_work);
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700222
223 /* set and clear vbus_int_clr[0] to clear interrupt */
224 writel_relaxed(BIT(0), chip->eud_reg_base + EUD_REG_VBUS_INT_CLR);
225 /* Ensure Register Writes Complete */
226 wmb();
227 writel_relaxed(0, chip->eud_reg_base + EUD_REG_VBUS_INT_CLR);
228}
229
230static void chgr_enable_disable(struct eud_chip *chip)
231{
232 u32 reg;
233
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800234 chip->extcon_id = EXTCON_CHG_USB_SDP;
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700235 /* read ctl_out_1[6] to find charger enable or disable event */
236 reg = readl_relaxed(chip->eud_reg_base + EUD_REG_CTL_OUT_1);
237 if (reg & BIT(6))
238 chip->chgr_enable = true;
239 else
240 chip->chgr_enable = false;
241
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800242 schedule_work(&chip->eud_work);
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700243
244 /* set and clear chgr_int_clr[0] to clear interrupt */
245 writel_relaxed(BIT(0), chip->eud_reg_base + EUD_REG_CHGR_INT_CLR);
246 /* Ensure Register Writes Complete */
247 wmb();
248 writel_relaxed(0, chip->eud_reg_base + EUD_REG_CHGR_INT_CLR);
249}
250
251static void pet_eud(struct eud_chip *chip)
252{
253 u32 reg;
254
255 /* read sw_attach_det[0] to find attach/detach event */
256 reg = readl_relaxed(chip->eud_reg_base + EUD_REG_SW_ATTACH_DET);
257 if (reg & BIT(0)) {
258 /* Detach & Attach pet for EUD */
259 writel_relaxed(0, chip->eud_reg_base + EUD_REG_SW_ATTACH_DET);
260 /* Ensure Register Writes Complete */
261 wmb();
262 /* Delay to make sure detach pet is done before attach pet */
263 udelay(100);
264 writel_relaxed(BIT(0), chip->eud_reg_base +
265 EUD_REG_SW_ATTACH_DET);
266 /* Ensure Register Writes Complete */
267 wmb();
268 } else {
269 /* Attach pet for EUD */
270 writel_relaxed(BIT(0), chip->eud_reg_base +
271 EUD_REG_SW_ATTACH_DET);
272 /* Ensure Register Writes Complete */
273 wmb();
274 }
275}
276
277static unsigned int eud_tx_empty(struct uart_port *port)
278{
279 u32 reg;
280
281 /* read status register and cross check for Tx interrupt */
282 reg = readl_relaxed(port->membase + EUD_REG_INT_STATUS_1);
283 if (reg & EUD_INT_TX)
284 return TIOCSER_TEMT;
285 else
286 return 0;
287}
288
289static void eud_stop_tx(struct uart_port *port)
290{
291 /* Disable Tx interrupt */
292 writel_relaxed(~EUD_INT_TX, port->membase + EUD_REG_INT_STATUS_1);
293 /* Ensure Register Writes Complete */
294 wmb();
295}
296
297static void eud_start_tx(struct uart_port *port)
298{
299 /* Enable Tx interrupt */
300 writel_relaxed(EUD_INT_TX, port->membase + EUD_REG_INT_STATUS_1);
301 /* Ensure Register Writes Complete */
302 wmb();
303}
304
305static void eud_stop_rx(struct uart_port *port)
306{
307 /* Disable Rx interrupt */
308 writel_relaxed(~EUD_INT_RX, port->membase + EUD_REG_INT_STATUS_1);
309 /* Ensure Register Writes Complete */
310 wmb();
311}
312
313static int eud_startup(struct uart_port *port)
314{
315 /* Enable Rx interrupt */
316 writel_relaxed(EUD_INT_RX, port->membase + EUD_REG_INT_STATUS_1);
317 /* Ensure Register Writes Complete */
318 wmb();
319 return 0;
320}
321
322static void eud_shutdown(struct uart_port *port)
323{
324 /* Disable both Tx & Rx interrupts */
325 writel_relaxed(~EUD_INT_TX | ~EUD_INT_RX,
326 port->membase + EUD_REG_INT_STATUS_1);
327 /* Ensure Register Writes Complete */
328 wmb();
329}
330
331static const char *eud_type(struct uart_port *port)
332{
333 return (port->type == PORT_EUD_UART) ? "EUD UART" : NULL;
334}
335
336static int eud_request_port(struct uart_port *port)
337{
338 /* Nothing to request */
339 return 0;
340}
341
342static void eud_release_port(struct uart_port *port)
343{
344 /* Nothing to release */
345}
346
347static void eud_config_port(struct uart_port *port, int flags)
348{
349 /* set port type, clear Tx and Rx interrupts */
350 port->type = PORT_EUD_UART;
351 writel_relaxed(~EUD_INT_TX | ~EUD_INT_RX,
352 port->membase + EUD_REG_INT_STATUS_1);
353 /* Ensure Register Writes Complete */
354 wmb();
355}
356
357static int eud_verify_port(struct uart_port *port,
358 struct serial_struct *ser)
359{
360 if (ser->type != PORT_UNKNOWN && ser->type != PORT_EUD_UART)
361 return -EINVAL;
362 return 0;
363}
364
365/* serial functions supported */
366static const struct uart_ops eud_uart_ops = {
367 .tx_empty = eud_tx_empty,
368 .stop_tx = eud_stop_tx,
369 .start_tx = eud_start_tx,
370 .stop_rx = eud_stop_rx,
371 .startup = eud_startup,
372 .shutdown = eud_shutdown,
373 .type = eud_type,
374 .release_port = eud_release_port,
375 .request_port = eud_request_port,
376 .config_port = eud_config_port,
377 .verify_port = eud_verify_port,
378};
379
380static struct uart_driver eud_uart_driver = {
381 .owner = THIS_MODULE,
382 .driver_name = "msm-eud",
383 .dev_name = "ttyEUD",
384 .nr = EUD_NR,
385 .cons = EUD_CONSOLE,
386};
387
388static void eud_uart_rx(struct eud_chip *chip)
389{
390 struct uart_port *port = &chip->port;
391 u32 reg;
392 unsigned int len;
393 unsigned char ch, flag;
394 int i;
395
396 reg = readl_relaxed(chip->eud_reg_base + EUD_REG_COM_RX_ID);
397 if (reg != UART_ID) {
398 dev_err(chip->dev, "Rx isn't for us!\n");
399 return;
400 }
401 /* Read Rx Len & Data registers */
402 spin_lock(&port->lock);
403 len = readl_relaxed(chip->eud_reg_base + EUD_REG_COM_RX_LEN);
404 for (i = 0; i < len; i++) {
405 ch = readl_relaxed(chip->eud_reg_base + EUD_REG_COM_RX_DAT);
406 flag = TTY_NORMAL;
407 port->icount.rx++;
408
409 if (uart_handle_sysrq_char(port, ch))
410 continue;
411 uart_insert_char(port, 0, 0, ch, flag);
412 }
413
414 spin_unlock(&port->lock);
415 tty_flip_buffer_push(&port->state->port);
416}
417
418static void eud_uart_tx(struct eud_chip *chip)
419{
420 struct uart_port *port = &chip->port;
421 struct circ_buf *xmit = &port->state->xmit;
422 unsigned int len;
423 u32 reg;
424
425 writel_relaxed(UART_ID, chip->eud_reg_base + EUD_REG_COM_TX_ID);
426 reg = readl_relaxed(chip->eud_reg_base + EUD_REG_COM_TX_ID);
427 if (reg != UART_ID) {
428 dev_err(chip->dev, "Tx isn't for us!\n");
429 return;
430 }
431 /* Write to Tx Len & Data registers */
432 spin_lock(&port->lock);
433 len = uart_circ_chars_pending(xmit);
434 if (len > 0) {
435 if (len > port->fifosize)
436 len = port->fifosize;
437 while (len--) {
438 writel_relaxed(xmit->buf[xmit->tail],
439 port->membase + EUD_REG_COM_TX_DAT);
440 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
441 port->icount.tx++;
442 }
443 }
444 spin_unlock(&port->lock);
445}
446
447static irqreturn_t handle_eud_irq(int irq, void *data)
448{
449 struct eud_chip *chip = data;
450 u32 reg;
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800451 u32 int_mask_en1 = readl_relaxed(chip->eud_reg_base +
452 EUD_REG_INT1_EN_MASK);
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700453
454 /* read status register and find out which interrupt triggered */
455 reg = readl_relaxed(chip->eud_reg_base + EUD_REG_INT_STATUS_1);
456 if (reg & EUD_INT_RX) {
457 dev_dbg(chip->dev, "EUD RX Interrupt!\n");
458 eud_uart_rx(chip);
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800459 } else if ((reg & EUD_INT_TX) & int_mask_en1) {
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700460 dev_dbg(chip->dev, "EUD TX Interrupt!\n");
461 eud_uart_tx(chip);
462 } else if (reg & EUD_INT_VBUS) {
463 dev_dbg(chip->dev, "EUD VBUS Interrupt!\n");
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800464 chip->int_status = EUD_INT_VBUS;
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700465 usb_attach_detach(chip);
466 } else if (reg & EUD_INT_CHGR) {
467 dev_dbg(chip->dev, "EUD CHGR Interrupt!\n");
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800468 chip->int_status = EUD_INT_CHGR;
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700469 chgr_enable_disable(chip);
470 } else if (reg & EUD_INT_SAFE_MODE) {
471 dev_dbg(chip->dev, "EUD SAFE MODE Interrupt!\n");
472 pet_eud(chip);
473 } else {
474 dev_dbg(chip->dev, "Unknown/spurious EUD Interrupt!\n");
475 return IRQ_NONE;
476 }
477
478 return IRQ_HANDLED;
479}
480
481static int msm_eud_probe(struct platform_device *pdev)
482{
483 struct eud_chip *chip;
484 struct uart_port *port;
485 struct resource *res;
486 int ret;
487
488 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
489 if (!chip) {
490 ret = -ENOMEM;
491 return ret;
492 }
493
494 platform_set_drvdata(pdev, chip);
495
496 chip->extcon = devm_extcon_dev_allocate(&pdev->dev, eud_extcon_cable);
497 if (IS_ERR(chip->extcon)) {
498 dev_err(chip->dev, "failed to allocate extcon device\n");
499 return PTR_ERR(chip->extcon);
500 }
501
502 ret = devm_extcon_dev_register(&pdev->dev, chip->extcon);
503 if (ret) {
504 dev_err(chip->dev, "failed to register extcon device\n");
505 return ret;
506 }
507
508 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eud_base");
509 if (!res) {
510 dev_err(chip->dev, "%s: failed to get resource eud_base\n",
511 __func__);
512 ret = -ENOMEM;
513 return ret;
514 }
515
516 chip->eud_reg_base = devm_ioremap_resource(&pdev->dev, res);
517 if (IS_ERR(chip->eud_reg_base))
518 return PTR_ERR(chip->eud_reg_base);
519
520 chip->eud_irq = platform_get_irq_byname(pdev, "eud_irq");
521
522 ret = devm_request_irq(&pdev->dev, chip->eud_irq, handle_eud_irq,
523 IRQF_TRIGGER_HIGH, "eud_irq", chip);
524 if (ret) {
525 dev_err(chip->dev, "request failed for eud irq\n");
526 return ret;
527 }
528
529 device_init_wakeup(&pdev->dev, true);
530 enable_irq_wake(chip->eud_irq);
531
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800532 INIT_WORK(&chip->eud_work, eud_event_notifier);
533
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700534 port = &chip->port;
535 port->line = pdev->id;
536 port->type = PORT_EUD_UART;
537 port->dev = chip->dev;
538 port->fifosize = MAX_FIFO_SIZE;
539 port->iotype = SERIAL_IO_MEM;
540 port->flags = UPF_BOOT_AUTOCONF;
541 port->membase = chip->eud_reg_base;
542 port->irq = chip->eud_irq;
543 port->ops = &eud_uart_ops;
544
545 ret = uart_add_one_port(&eud_uart_driver, port);
546 if (!ret) {
547 dev_err(chip->dev, "failed to add uart port!\n");
548 return ret;
549 }
550
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700551 eud_private = pdev;
552
553 /* Enable EUD */
554 if (enable)
555 enable_eud(pdev);
556
557 return 0;
558}
559
560static int msm_eud_remove(struct platform_device *pdev)
561{
562 struct eud_chip *chip = platform_get_drvdata(pdev);
563 struct uart_port *port = &chip->port;
564
565 uart_remove_one_port(&eud_uart_driver, port);
566 device_init_wakeup(chip->dev, false);
567
568 return 0;
569}
570
571static const struct of_device_id msm_eud_dt_match[] = {
572 {.compatible = "qcom,msm-eud"},
573 {},
574};
575MODULE_DEVICE_TABLE(of, msm_eud_dt_match);
576
577static struct platform_driver msm_eud_driver = {
578 .probe = msm_eud_probe,
579 .remove = msm_eud_remove,
580 .driver = {
581 .name = "msm-eud",
582 .owner = THIS_MODULE,
583 .of_match_table = msm_eud_dt_match,
584 },
585};
586
587static int __init msm_eud_init(void)
588{
589 int ret;
590
591 ret = uart_register_driver(&eud_uart_driver);
592 if (ret) {
593 pr_err("%s: Failed to register EUD UART driver\n",
594 __func__);
595 return ret;
596 }
597
598 ret = platform_driver_register(&msm_eud_driver);
599 if (ret) {
600 pr_err("%s: Failed to register EUD driver\n",
601 __func__);
602 uart_unregister_driver(&eud_uart_driver);
603 return ret;
604 }
605
606 return 0;
607}
608module_init(msm_eud_init);
609
610static void __exit msm_eud_exit(void)
611{
612 platform_driver_unregister(&msm_eud_driver);
613 uart_unregister_driver(&eud_uart_driver);
614}
615module_exit(msm_eud_exit);
616
617MODULE_DESCRIPTION("QTI EUD driver");
618MODULE_LICENSE("GPL v2");