blob: 14550699cd862902c1a889c508739d908c304b59 [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>
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -070029
30#define EUD_ENABLE_CMD 1
31#define EUD_DISABLE_CMD 0
32
33#define EUD_REG_COM_TX_ID 0x0000
34#define EUD_REG_COM_TX_LEN 0x0004
35#define EUD_REG_COM_TX_DAT 0x0008
36#define EUD_REG_COM_RX_ID 0x000C
37#define EUD_REG_COM_RX_LEN 0x0010
38#define EUD_REG_COM_RX_DAT 0x0014
39#define EUD_REG_INT1_EN_MASK 0x0024
40#define EUD_REG_INT_STATUS_1 0x0044
41#define EUD_REG_CTL_OUT_1 0x0074
42#define EUD_REG_VBUS_INT_CLR 0x0080
43#define EUD_REG_CHGR_INT_CLR 0x0084
44#define EUD_REG_CSR_EUD_EN 0x1014
45#define EUD_REG_SW_ATTACH_DET 0x1018
46
47#define EUD_INT_RX BIT(0)
48#define EUD_INT_TX BIT(1)
49#define EUD_INT_VBUS BIT(2)
50#define EUD_INT_CHGR BIT(3)
51#define EUD_INT_SAFE_MODE BIT(4)
52#define EUD_INT_ALL (EUD_INT_RX | EUD_INT_TX | \
53 EUD_INT_VBUS | EUD_INT_CHGR | \
54 EUD_INT_SAFE_MODE)
55
56#define EUD_NR 1
57#define EUD_CONSOLE NULL
58#define UART_ID 0x90
59#define MAX_FIFO_SIZE 14
60
61struct eud_chip {
62 struct device *dev;
63 int eud_irq;
Channagoud Kadabi75f54e82016-12-06 16:35:10 -080064 unsigned int extcon_id;
65 unsigned int int_status;
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -070066 bool usb_attach;
67 bool chgr_enable;
68 void __iomem *eud_reg_base;
69 struct extcon_dev *extcon;
70 struct uart_port port;
Channagoud Kadabi75f54e82016-12-06 16:35:10 -080071 struct work_struct eud_work;
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -070072};
73
74static const unsigned int eud_extcon_cable[] = {
75 EXTCON_USB,
76 EXTCON_CHG_USB_SDP,
77 EXTCON_NONE,
78};
79
80/*
81 * On the kernel command line specify eud.enable=1 to enable EUD.
82 * EUD is disabled by default.
83 */
84static int enable;
85static struct platform_device *eud_private;
86
87static void enable_eud(struct platform_device *pdev)
88{
89 struct eud_chip *priv = platform_get_drvdata(pdev);
90
91 /* write into CSR to enable EUD */
92 writel_relaxed(BIT(0), priv->eud_reg_base + EUD_REG_CSR_EUD_EN);
Channagoud Kadabi75f54e82016-12-06 16:35:10 -080093 /* Enable vbus, chgr & safe mode warning interrupts */
94 writel_relaxed(EUD_INT_VBUS | EUD_INT_CHGR | EUD_INT_SAFE_MODE,
95 priv->eud_reg_base + EUD_REG_INT1_EN_MASK);
96
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -070097 /* Ensure Register Writes Complete */
98 wmb();
Channagoud Kadabi75f54e82016-12-06 16:35:10 -080099
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700100 dev_dbg(&pdev->dev, "%s: EUD Enabled!\n", __func__);
101}
102
103static void disable_eud(struct platform_device *pdev)
104{
105 struct eud_chip *priv = platform_get_drvdata(pdev);
106
107 /* write into CSR to disable EUD */
108 writel_relaxed(0, priv->eud_reg_base + EUD_REG_CSR_EUD_EN);
109 dev_dbg(&pdev->dev, "%s: EUD Disabled!\n", __func__);
110}
111
112static int param_eud_set(const char *val, const struct kernel_param *kp)
113{
114 int enable = 0;
115
116 if (sscanf(val, "%du", &enable) != 1)
117 return -EINVAL;
118
119 if (enable != EUD_ENABLE_CMD && enable != EUD_DISABLE_CMD)
120 return -EINVAL;
121
122 if (enable == EUD_ENABLE_CMD) {
123 pr_debug("%s: Enbling EUD\n", __func__);
124 enable_eud(eud_private);
125 } else if (enable == EUD_DISABLE_CMD) {
126 pr_debug("%s: Disabling EUD\n", __func__);
127 disable_eud(eud_private);
128 }
129
130 *((uint *)kp->arg) = enable;
131 return 0;
132}
133
134static const struct kernel_param_ops eud_param_ops = {
135 .set = param_eud_set,
136 .get = param_get_int,
137};
138
139module_param_cb(enable, &eud_param_ops, &enable, 0644);
140
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800141static void eud_event_notifier(struct work_struct *eud_work)
142{
143 struct eud_chip *chip = container_of(eud_work, struct eud_chip,
144 eud_work);
145
146 if (chip->int_status == EUD_INT_VBUS)
Jack Pham4e9dff72017-04-04 18:05:53 -0700147 extcon_set_state_sync(chip->extcon, chip->extcon_id,
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800148 chip->usb_attach);
149 else if (chip->int_status == EUD_INT_CHGR)
Jack Pham4e9dff72017-04-04 18:05:53 -0700150 extcon_set_state_sync(chip->extcon, chip->extcon_id,
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800151 chip->chgr_enable);
152}
153
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700154static void usb_attach_detach(struct eud_chip *chip)
155{
156 u32 reg;
157
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800158 chip->extcon_id = EXTCON_USB;
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700159 /* read ctl_out_1[4] to find USB attach or detach event */
160 reg = readl_relaxed(chip->eud_reg_base + EUD_REG_CTL_OUT_1);
161 if (reg & BIT(4))
162 chip->usb_attach = true;
163 else
164 chip->usb_attach = false;
165
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800166 schedule_work(&chip->eud_work);
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700167
168 /* set and clear vbus_int_clr[0] to clear interrupt */
169 writel_relaxed(BIT(0), chip->eud_reg_base + EUD_REG_VBUS_INT_CLR);
170 /* Ensure Register Writes Complete */
171 wmb();
172 writel_relaxed(0, chip->eud_reg_base + EUD_REG_VBUS_INT_CLR);
173}
174
175static void chgr_enable_disable(struct eud_chip *chip)
176{
177 u32 reg;
178
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800179 chip->extcon_id = EXTCON_CHG_USB_SDP;
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700180 /* read ctl_out_1[6] to find charger enable or disable event */
181 reg = readl_relaxed(chip->eud_reg_base + EUD_REG_CTL_OUT_1);
182 if (reg & BIT(6))
183 chip->chgr_enable = true;
184 else
185 chip->chgr_enable = false;
186
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800187 schedule_work(&chip->eud_work);
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700188
189 /* set and clear chgr_int_clr[0] to clear interrupt */
190 writel_relaxed(BIT(0), chip->eud_reg_base + EUD_REG_CHGR_INT_CLR);
191 /* Ensure Register Writes Complete */
192 wmb();
193 writel_relaxed(0, chip->eud_reg_base + EUD_REG_CHGR_INT_CLR);
194}
195
196static void pet_eud(struct eud_chip *chip)
197{
198 u32 reg;
199
200 /* read sw_attach_det[0] to find attach/detach event */
201 reg = readl_relaxed(chip->eud_reg_base + EUD_REG_SW_ATTACH_DET);
202 if (reg & BIT(0)) {
203 /* Detach & Attach pet for EUD */
204 writel_relaxed(0, chip->eud_reg_base + EUD_REG_SW_ATTACH_DET);
205 /* Ensure Register Writes Complete */
206 wmb();
207 /* Delay to make sure detach pet is done before attach pet */
208 udelay(100);
209 writel_relaxed(BIT(0), chip->eud_reg_base +
210 EUD_REG_SW_ATTACH_DET);
211 /* Ensure Register Writes Complete */
212 wmb();
213 } else {
214 /* Attach pet for EUD */
215 writel_relaxed(BIT(0), chip->eud_reg_base +
216 EUD_REG_SW_ATTACH_DET);
217 /* Ensure Register Writes Complete */
218 wmb();
219 }
220}
221
222static unsigned int eud_tx_empty(struct uart_port *port)
223{
224 u32 reg;
225
226 /* read status register and cross check for Tx interrupt */
227 reg = readl_relaxed(port->membase + EUD_REG_INT_STATUS_1);
228 if (reg & EUD_INT_TX)
229 return TIOCSER_TEMT;
230 else
231 return 0;
232}
233
234static void eud_stop_tx(struct uart_port *port)
235{
236 /* Disable Tx interrupt */
237 writel_relaxed(~EUD_INT_TX, port->membase + EUD_REG_INT_STATUS_1);
238 /* Ensure Register Writes Complete */
239 wmb();
240}
241
242static void eud_start_tx(struct uart_port *port)
243{
244 /* Enable Tx interrupt */
245 writel_relaxed(EUD_INT_TX, port->membase + EUD_REG_INT_STATUS_1);
246 /* Ensure Register Writes Complete */
247 wmb();
248}
249
250static void eud_stop_rx(struct uart_port *port)
251{
252 /* Disable Rx interrupt */
253 writel_relaxed(~EUD_INT_RX, port->membase + EUD_REG_INT_STATUS_1);
254 /* Ensure Register Writes Complete */
255 wmb();
256}
257
258static int eud_startup(struct uart_port *port)
259{
260 /* Enable Rx interrupt */
261 writel_relaxed(EUD_INT_RX, port->membase + EUD_REG_INT_STATUS_1);
262 /* Ensure Register Writes Complete */
263 wmb();
264 return 0;
265}
266
267static void eud_shutdown(struct uart_port *port)
268{
269 /* Disable both Tx & Rx interrupts */
270 writel_relaxed(~EUD_INT_TX | ~EUD_INT_RX,
271 port->membase + EUD_REG_INT_STATUS_1);
272 /* Ensure Register Writes Complete */
273 wmb();
274}
275
276static const char *eud_type(struct uart_port *port)
277{
278 return (port->type == PORT_EUD_UART) ? "EUD UART" : NULL;
279}
280
281static int eud_request_port(struct uart_port *port)
282{
283 /* Nothing to request */
284 return 0;
285}
286
287static void eud_release_port(struct uart_port *port)
288{
289 /* Nothing to release */
290}
291
292static void eud_config_port(struct uart_port *port, int flags)
293{
294 /* set port type, clear Tx and Rx interrupts */
295 port->type = PORT_EUD_UART;
296 writel_relaxed(~EUD_INT_TX | ~EUD_INT_RX,
297 port->membase + EUD_REG_INT_STATUS_1);
298 /* Ensure Register Writes Complete */
299 wmb();
300}
301
302static int eud_verify_port(struct uart_port *port,
303 struct serial_struct *ser)
304{
305 if (ser->type != PORT_UNKNOWN && ser->type != PORT_EUD_UART)
306 return -EINVAL;
307 return 0;
308}
309
310/* serial functions supported */
311static const struct uart_ops eud_uart_ops = {
312 .tx_empty = eud_tx_empty,
313 .stop_tx = eud_stop_tx,
314 .start_tx = eud_start_tx,
315 .stop_rx = eud_stop_rx,
316 .startup = eud_startup,
317 .shutdown = eud_shutdown,
318 .type = eud_type,
319 .release_port = eud_release_port,
320 .request_port = eud_request_port,
321 .config_port = eud_config_port,
322 .verify_port = eud_verify_port,
323};
324
325static struct uart_driver eud_uart_driver = {
326 .owner = THIS_MODULE,
327 .driver_name = "msm-eud",
328 .dev_name = "ttyEUD",
329 .nr = EUD_NR,
330 .cons = EUD_CONSOLE,
331};
332
333static void eud_uart_rx(struct eud_chip *chip)
334{
335 struct uart_port *port = &chip->port;
336 u32 reg;
337 unsigned int len;
338 unsigned char ch, flag;
339 int i;
340
341 reg = readl_relaxed(chip->eud_reg_base + EUD_REG_COM_RX_ID);
342 if (reg != UART_ID) {
343 dev_err(chip->dev, "Rx isn't for us!\n");
344 return;
345 }
346 /* Read Rx Len & Data registers */
347 spin_lock(&port->lock);
348 len = readl_relaxed(chip->eud_reg_base + EUD_REG_COM_RX_LEN);
349 for (i = 0; i < len; i++) {
350 ch = readl_relaxed(chip->eud_reg_base + EUD_REG_COM_RX_DAT);
351 flag = TTY_NORMAL;
352 port->icount.rx++;
353
354 if (uart_handle_sysrq_char(port, ch))
355 continue;
356 uart_insert_char(port, 0, 0, ch, flag);
357 }
358
359 spin_unlock(&port->lock);
360 tty_flip_buffer_push(&port->state->port);
361}
362
363static void eud_uart_tx(struct eud_chip *chip)
364{
365 struct uart_port *port = &chip->port;
366 struct circ_buf *xmit = &port->state->xmit;
367 unsigned int len;
368 u32 reg;
369
370 writel_relaxed(UART_ID, chip->eud_reg_base + EUD_REG_COM_TX_ID);
371 reg = readl_relaxed(chip->eud_reg_base + EUD_REG_COM_TX_ID);
372 if (reg != UART_ID) {
373 dev_err(chip->dev, "Tx isn't for us!\n");
374 return;
375 }
376 /* Write to Tx Len & Data registers */
377 spin_lock(&port->lock);
378 len = uart_circ_chars_pending(xmit);
379 if (len > 0) {
380 if (len > port->fifosize)
381 len = port->fifosize;
382 while (len--) {
383 writel_relaxed(xmit->buf[xmit->tail],
384 port->membase + EUD_REG_COM_TX_DAT);
385 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
386 port->icount.tx++;
387 }
388 }
389 spin_unlock(&port->lock);
390}
391
392static irqreturn_t handle_eud_irq(int irq, void *data)
393{
394 struct eud_chip *chip = data;
395 u32 reg;
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800396 u32 int_mask_en1 = readl_relaxed(chip->eud_reg_base +
397 EUD_REG_INT1_EN_MASK);
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700398
399 /* read status register and find out which interrupt triggered */
400 reg = readl_relaxed(chip->eud_reg_base + EUD_REG_INT_STATUS_1);
401 if (reg & EUD_INT_RX) {
402 dev_dbg(chip->dev, "EUD RX Interrupt!\n");
403 eud_uart_rx(chip);
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800404 } else if ((reg & EUD_INT_TX) & int_mask_en1) {
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700405 dev_dbg(chip->dev, "EUD TX Interrupt!\n");
406 eud_uart_tx(chip);
407 } else if (reg & EUD_INT_VBUS) {
408 dev_dbg(chip->dev, "EUD VBUS Interrupt!\n");
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800409 chip->int_status = EUD_INT_VBUS;
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700410 usb_attach_detach(chip);
411 } else if (reg & EUD_INT_CHGR) {
412 dev_dbg(chip->dev, "EUD CHGR Interrupt!\n");
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800413 chip->int_status = EUD_INT_CHGR;
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700414 chgr_enable_disable(chip);
415 } else if (reg & EUD_INT_SAFE_MODE) {
416 dev_dbg(chip->dev, "EUD SAFE MODE Interrupt!\n");
417 pet_eud(chip);
418 } else {
419 dev_dbg(chip->dev, "Unknown/spurious EUD Interrupt!\n");
420 return IRQ_NONE;
421 }
422
423 return IRQ_HANDLED;
424}
425
426static int msm_eud_probe(struct platform_device *pdev)
427{
428 struct eud_chip *chip;
429 struct uart_port *port;
430 struct resource *res;
431 int ret;
432
433 chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
434 if (!chip) {
435 ret = -ENOMEM;
436 return ret;
437 }
438
439 platform_set_drvdata(pdev, chip);
440
441 chip->extcon = devm_extcon_dev_allocate(&pdev->dev, eud_extcon_cable);
442 if (IS_ERR(chip->extcon)) {
443 dev_err(chip->dev, "failed to allocate extcon device\n");
444 return PTR_ERR(chip->extcon);
445 }
446
447 ret = devm_extcon_dev_register(&pdev->dev, chip->extcon);
448 if (ret) {
449 dev_err(chip->dev, "failed to register extcon device\n");
450 return ret;
451 }
452
453 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eud_base");
454 if (!res) {
455 dev_err(chip->dev, "%s: failed to get resource eud_base\n",
456 __func__);
457 ret = -ENOMEM;
458 return ret;
459 }
460
461 chip->eud_reg_base = devm_ioremap_resource(&pdev->dev, res);
462 if (IS_ERR(chip->eud_reg_base))
463 return PTR_ERR(chip->eud_reg_base);
464
465 chip->eud_irq = platform_get_irq_byname(pdev, "eud_irq");
466
467 ret = devm_request_irq(&pdev->dev, chip->eud_irq, handle_eud_irq,
468 IRQF_TRIGGER_HIGH, "eud_irq", chip);
469 if (ret) {
470 dev_err(chip->dev, "request failed for eud irq\n");
471 return ret;
472 }
473
474 device_init_wakeup(&pdev->dev, true);
475 enable_irq_wake(chip->eud_irq);
476
Channagoud Kadabi75f54e82016-12-06 16:35:10 -0800477 INIT_WORK(&chip->eud_work, eud_event_notifier);
478
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700479 port = &chip->port;
480 port->line = pdev->id;
481 port->type = PORT_EUD_UART;
482 port->dev = chip->dev;
483 port->fifosize = MAX_FIFO_SIZE;
484 port->iotype = SERIAL_IO_MEM;
485 port->flags = UPF_BOOT_AUTOCONF;
486 port->membase = chip->eud_reg_base;
487 port->irq = chip->eud_irq;
488 port->ops = &eud_uart_ops;
489
490 ret = uart_add_one_port(&eud_uart_driver, port);
491 if (!ret) {
492 dev_err(chip->dev, "failed to add uart port!\n");
493 return ret;
494 }
495
Satya Durga Srinivasu Prabhala60909002016-09-12 11:36:09 -0700496 eud_private = pdev;
497
498 /* Enable EUD */
499 if (enable)
500 enable_eud(pdev);
501
502 return 0;
503}
504
505static int msm_eud_remove(struct platform_device *pdev)
506{
507 struct eud_chip *chip = platform_get_drvdata(pdev);
508 struct uart_port *port = &chip->port;
509
510 uart_remove_one_port(&eud_uart_driver, port);
511 device_init_wakeup(chip->dev, false);
512
513 return 0;
514}
515
516static const struct of_device_id msm_eud_dt_match[] = {
517 {.compatible = "qcom,msm-eud"},
518 {},
519};
520MODULE_DEVICE_TABLE(of, msm_eud_dt_match);
521
522static struct platform_driver msm_eud_driver = {
523 .probe = msm_eud_probe,
524 .remove = msm_eud_remove,
525 .driver = {
526 .name = "msm-eud",
527 .owner = THIS_MODULE,
528 .of_match_table = msm_eud_dt_match,
529 },
530};
531
532static int __init msm_eud_init(void)
533{
534 int ret;
535
536 ret = uart_register_driver(&eud_uart_driver);
537 if (ret) {
538 pr_err("%s: Failed to register EUD UART driver\n",
539 __func__);
540 return ret;
541 }
542
543 ret = platform_driver_register(&msm_eud_driver);
544 if (ret) {
545 pr_err("%s: Failed to register EUD driver\n",
546 __func__);
547 uart_unregister_driver(&eud_uart_driver);
548 return ret;
549 }
550
551 return 0;
552}
553module_init(msm_eud_init);
554
555static void __exit msm_eud_exit(void)
556{
557 platform_driver_unregister(&msm_eud_driver);
558 uart_unregister_driver(&eud_uart_driver);
559}
560module_exit(msm_eud_exit);
561
562MODULE_DESCRIPTION("QTI EUD driver");
563MODULE_LICENSE("GPL v2");