aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serdev
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serdev')
-rw-r--r--drivers/tty/serdev/Kconfig8
-rw-r--r--drivers/tty/serdev/core.c152
-rw-r--r--drivers/tty/serdev/serdev-ttyport.c31
3 files changed, 152 insertions, 39 deletions
diff --git a/drivers/tty/serdev/Kconfig b/drivers/tty/serdev/Kconfig
index cdc6b820cf93..1dbc8352e027 100644
--- a/drivers/tty/serdev/Kconfig
+++ b/drivers/tty/serdev/Kconfig
@@ -6,11 +6,19 @@ menuconfig SERIAL_DEV_BUS
6 help 6 help
7 Core support for devices connected via a serial port. 7 Core support for devices connected via a serial port.
8 8
9 Note that you typically also want to enable TTY port controller support.
10
9if SERIAL_DEV_BUS 11if SERIAL_DEV_BUS
10 12
11config SERIAL_DEV_CTRL_TTYPORT 13config SERIAL_DEV_CTRL_TTYPORT
12 bool "Serial device TTY port controller" 14 bool "Serial device TTY port controller"
15 help
16 Say Y here if you want to use the Serial device bus with common TTY
17 drivers (e.g. serial drivers).
18
19 If unsure, say Y.
13 depends on TTY 20 depends on TTY
14 depends on SERIAL_DEV_BUS != m 21 depends on SERIAL_DEV_BUS != m
22 default y
15 23
16endif 24endif
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index c68fb3a8ea1c..1bef39828ca7 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -1,19 +1,12 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) 2016-2017 Linaro Ltd., Rob Herring <robh@kernel.org> 3 * Copyright (C) 2016-2017 Linaro Ltd., Rob Herring <robh@kernel.org>
3 * 4 *
4 * Based on drivers/spmi/spmi.c: 5 * Based on drivers/spmi/spmi.c:
5 * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. 6 * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 and
9 * only version 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */ 7 */
16 8
9#include <linux/acpi.h>
17#include <linux/errno.h> 10#include <linux/errno.h>
18#include <linux/idr.h> 11#include <linux/idr.h>
19#include <linux/kernel.h> 12#include <linux/kernel.h>
@@ -49,13 +42,22 @@ static const struct device_type serdev_ctrl_type = {
49 42
50static int serdev_device_match(struct device *dev, struct device_driver *drv) 43static int serdev_device_match(struct device *dev, struct device_driver *drv)
51{ 44{
52 /* TODO: ACPI and platform matching */ 45 /* TODO: platform matching */
46 if (acpi_driver_match_device(dev, drv))
47 return 1;
48
53 return of_driver_match_device(dev, drv); 49 return of_driver_match_device(dev, drv);
54} 50}
55 51
56static int serdev_uevent(struct device *dev, struct kobj_uevent_env *env) 52static int serdev_uevent(struct device *dev, struct kobj_uevent_env *env)
57{ 53{
58 /* TODO: ACPI and platform modalias */ 54 int rc;
55
56 /* TODO: platform modalias */
57 rc = acpi_device_uevent_modalias(dev, env);
58 if (rc != -ENODEV)
59 return rc;
60
59 return of_device_uevent_modalias(dev, env); 61 return of_device_uevent_modalias(dev, env);
60} 62}
61 63
@@ -65,21 +67,32 @@ static int serdev_uevent(struct device *dev, struct kobj_uevent_env *env)
65 */ 67 */
66int serdev_device_add(struct serdev_device *serdev) 68int serdev_device_add(struct serdev_device *serdev)
67{ 69{
70 struct serdev_controller *ctrl = serdev->ctrl;
68 struct device *parent = serdev->dev.parent; 71 struct device *parent = serdev->dev.parent;
69 int err; 72 int err;
70 73
71 dev_set_name(&serdev->dev, "%s-%d", dev_name(parent), serdev->nr); 74 dev_set_name(&serdev->dev, "%s-%d", dev_name(parent), serdev->nr);
72 75
76 /* Only a single slave device is currently supported. */
77 if (ctrl->serdev) {
78 dev_err(&serdev->dev, "controller busy\n");
79 return -EBUSY;
80 }
81 ctrl->serdev = serdev;
82
73 err = device_add(&serdev->dev); 83 err = device_add(&serdev->dev);
74 if (err < 0) { 84 if (err < 0) {
75 dev_err(&serdev->dev, "Can't add %s, status %d\n", 85 dev_err(&serdev->dev, "Can't add %s, status %d\n",
76 dev_name(&serdev->dev), err); 86 dev_name(&serdev->dev), err);
77 goto err_device_add; 87 goto err_clear_serdev;
78 } 88 }
79 89
80 dev_dbg(&serdev->dev, "device %s registered\n", dev_name(&serdev->dev)); 90 dev_dbg(&serdev->dev, "device %s registered\n", dev_name(&serdev->dev));
81 91
82err_device_add: 92 return 0;
93
94err_clear_serdev:
95 ctrl->serdev = NULL;
83 return err; 96 return err;
84} 97}
85EXPORT_SYMBOL_GPL(serdev_device_add); 98EXPORT_SYMBOL_GPL(serdev_device_add);
@@ -90,7 +103,10 @@ EXPORT_SYMBOL_GPL(serdev_device_add);
90 */ 103 */
91void serdev_device_remove(struct serdev_device *serdev) 104void serdev_device_remove(struct serdev_device *serdev)
92{ 105{
106 struct serdev_controller *ctrl = serdev->ctrl;
107
93 device_unregister(&serdev->dev); 108 device_unregister(&serdev->dev);
109 ctrl->serdev = NULL;
94} 110}
95EXPORT_SYMBOL_GPL(serdev_device_remove); 111EXPORT_SYMBOL_GPL(serdev_device_remove);
96 112
@@ -260,6 +276,12 @@ static int serdev_drv_remove(struct device *dev)
260static ssize_t modalias_show(struct device *dev, 276static ssize_t modalias_show(struct device *dev,
261 struct device_attribute *attr, char *buf) 277 struct device_attribute *attr, char *buf)
262{ 278{
279 int len;
280
281 len = acpi_device_modalias(dev, buf, PAGE_SIZE - 1);
282 if (len != -ENODEV)
283 return len;
284
263 return of_device_modalias(dev, buf, PAGE_SIZE); 285 return of_device_modalias(dev, buf, PAGE_SIZE);
264} 286}
265DEVICE_ATTR_RO(modalias); 287DEVICE_ATTR_RO(modalias);
@@ -295,7 +317,6 @@ struct serdev_device *serdev_device_alloc(struct serdev_controller *ctrl)
295 return NULL; 317 return NULL;
296 318
297 serdev->ctrl = ctrl; 319 serdev->ctrl = ctrl;
298 ctrl->serdev = serdev;
299 device_initialize(&serdev->dev); 320 device_initialize(&serdev->dev);
300 serdev->dev.parent = &ctrl->dev; 321 serdev->dev.parent = &ctrl->dev;
301 serdev->dev.bus = &serdev_bus_type; 322 serdev->dev.bus = &serdev_bus_type;
@@ -329,26 +350,31 @@ struct serdev_controller *serdev_controller_alloc(struct device *parent,
329 if (!ctrl) 350 if (!ctrl)
330 return NULL; 351 return NULL;
331 352
332 device_initialize(&ctrl->dev);
333 ctrl->dev.type = &serdev_ctrl_type;
334 ctrl->dev.bus = &serdev_bus_type;
335 ctrl->dev.parent = parent;
336 ctrl->dev.of_node = parent->of_node;
337 serdev_controller_set_drvdata(ctrl, &ctrl[1]);
338
339 id = ida_simple_get(&ctrl_ida, 0, 0, GFP_KERNEL); 353 id = ida_simple_get(&ctrl_ida, 0, 0, GFP_KERNEL);
340 if (id < 0) { 354 if (id < 0) {
341 dev_err(parent, 355 dev_err(parent,
342 "unable to allocate serdev controller identifier.\n"); 356 "unable to allocate serdev controller identifier.\n");
343 serdev_controller_put(ctrl); 357 goto err_free;
344 return NULL;
345 } 358 }
346 359
347 ctrl->nr = id; 360 ctrl->nr = id;
361
362 device_initialize(&ctrl->dev);
363 ctrl->dev.type = &serdev_ctrl_type;
364 ctrl->dev.bus = &serdev_bus_type;
365 ctrl->dev.parent = parent;
366 ctrl->dev.of_node = parent->of_node;
367 serdev_controller_set_drvdata(ctrl, &ctrl[1]);
368
348 dev_set_name(&ctrl->dev, "serial%d", id); 369 dev_set_name(&ctrl->dev, "serial%d", id);
349 370
350 dev_dbg(&ctrl->dev, "allocated controller 0x%p id %d\n", ctrl, id); 371 dev_dbg(&ctrl->dev, "allocated controller 0x%p id %d\n", ctrl, id);
351 return ctrl; 372 return ctrl;
373
374err_free:
375 kfree(ctrl);
376
377 return NULL;
352} 378}
353EXPORT_SYMBOL_GPL(serdev_controller_alloc); 379EXPORT_SYMBOL_GPL(serdev_controller_alloc);
354 380
@@ -385,6 +411,75 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl)
385 return 0; 411 return 0;
386} 412}
387 413
414#ifdef CONFIG_ACPI
415static acpi_status acpi_serdev_register_device(struct serdev_controller *ctrl,
416 struct acpi_device *adev)
417{
418 struct serdev_device *serdev = NULL;
419 int err;
420
421 if (acpi_bus_get_status(adev) || !adev->status.present ||
422 acpi_device_enumerated(adev))
423 return AE_OK;
424
425 serdev = serdev_device_alloc(ctrl);
426 if (!serdev) {
427 dev_err(&ctrl->dev, "failed to allocate serdev device for %s\n",
428 dev_name(&adev->dev));
429 return AE_NO_MEMORY;
430 }
431
432 ACPI_COMPANION_SET(&serdev->dev, adev);
433 acpi_device_set_enumerated(adev);
434
435 err = serdev_device_add(serdev);
436 if (err) {
437 dev_err(&serdev->dev,
438 "failure adding ACPI serdev device. status %d\n", err);
439 serdev_device_put(serdev);
440 }
441
442 return AE_OK;
443}
444
445static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level,
446 void *data, void **return_value)
447{
448 struct serdev_controller *ctrl = data;
449 struct acpi_device *adev;
450
451 if (acpi_bus_get_device(handle, &adev))
452 return AE_OK;
453
454 return acpi_serdev_register_device(ctrl, adev);
455}
456
457static int acpi_serdev_register_devices(struct serdev_controller *ctrl)
458{
459 acpi_status status;
460 acpi_handle handle;
461
462 handle = ACPI_HANDLE(ctrl->dev.parent);
463 if (!handle)
464 return -ENODEV;
465
466 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
467 acpi_serdev_add_device, NULL, ctrl, NULL);
468 if (ACPI_FAILURE(status))
469 dev_dbg(&ctrl->dev, "failed to enumerate serdev slaves\n");
470
471 if (!ctrl->serdev)
472 return -ENODEV;
473
474 return 0;
475}
476#else
477static inline int acpi_serdev_register_devices(struct serdev_controller *ctrl)
478{
479 return -ENODEV;
480}
481#endif /* CONFIG_ACPI */
482
388/** 483/**
389 * serdev_controller_add() - Add an serdev controller 484 * serdev_controller_add() - Add an serdev controller
390 * @ctrl: controller to be registered. 485 * @ctrl: controller to be registered.
@@ -394,7 +489,7 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl)
394 */ 489 */
395int serdev_controller_add(struct serdev_controller *ctrl) 490int serdev_controller_add(struct serdev_controller *ctrl)
396{ 491{
397 int ret; 492 int ret_of, ret_acpi, ret;
398 493
399 /* Can't register until after driver model init */ 494 /* Can't register until after driver model init */
400 if (WARN_ON(!is_registered)) 495 if (WARN_ON(!is_registered))
@@ -404,9 +499,14 @@ int serdev_controller_add(struct serdev_controller *ctrl)
404 if (ret) 499 if (ret)
405 return ret; 500 return ret;
406 501
407 ret = of_serdev_register_devices(ctrl); 502 ret_of = of_serdev_register_devices(ctrl);
408 if (ret) 503 ret_acpi = acpi_serdev_register_devices(ctrl);
504 if (ret_of && ret_acpi) {
505 dev_dbg(&ctrl->dev, "no devices registered: of:%d acpi:%d\n",
506 ret_of, ret_acpi);
507 ret = -ENODEV;
409 goto out_dev_del; 508 goto out_dev_del;
509 }
410 510
411 dev_dbg(&ctrl->dev, "serdev%d registered: dev:%p\n", 511 dev_dbg(&ctrl->dev, "serdev%d registered: dev:%p\n",
412 ctrl->nr, &ctrl->dev); 512 ctrl->nr, &ctrl->dev);
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index 302018d67efa..ce7ad0acee7a 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -1,14 +1,6 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Copyright (C) 2016-2017 Linaro Ltd., Rob Herring <robh@kernel.org> 3 * Copyright (C) 2016-2017 Linaro Ltd., Rob Herring <robh@kernel.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */ 4 */
13#include <linux/kernel.h> 5#include <linux/kernel.h>
14#include <linux/serdev.h> 6#include <linux/serdev.h>
@@ -96,16 +88,21 @@ static int ttyport_open(struct serdev_controller *ctrl)
96 struct serport *serport = serdev_controller_get_drvdata(ctrl); 88 struct serport *serport = serdev_controller_get_drvdata(ctrl);
97 struct tty_struct *tty; 89 struct tty_struct *tty;
98 struct ktermios ktermios; 90 struct ktermios ktermios;
91 int ret;
99 92
100 tty = tty_init_dev(serport->tty_drv, serport->tty_idx); 93 tty = tty_init_dev(serport->tty_drv, serport->tty_idx);
101 if (IS_ERR(tty)) 94 if (IS_ERR(tty))
102 return PTR_ERR(tty); 95 return PTR_ERR(tty);
103 serport->tty = tty; 96 serport->tty = tty;
104 97
105 if (tty->ops->open) 98 if (!tty->ops->open || !tty->ops->close) {
106 tty->ops->open(serport->tty, NULL); 99 ret = -ENODEV;
107 else 100 goto err_unlock;
108 tty_port_open(serport->port, tty, NULL); 101 }
102
103 ret = tty->ops->open(serport->tty, NULL);
104 if (ret)
105 goto err_close;
109 106
110 /* Bring the UART into a known 8 bits no parity hw fc state */ 107 /* Bring the UART into a known 8 bits no parity hw fc state */
111 ktermios = tty->termios; 108 ktermios = tty->termios;
@@ -122,6 +119,14 @@ static int ttyport_open(struct serdev_controller *ctrl)
122 119
123 tty_unlock(serport->tty); 120 tty_unlock(serport->tty);
124 return 0; 121 return 0;
122
123err_close:
124 tty->ops->close(tty, NULL);
125err_unlock:
126 tty_unlock(tty);
127 tty_release_struct(tty, serport->tty_idx);
128
129 return ret;
125} 130}
126 131
127static void ttyport_close(struct serdev_controller *ctrl) 132static void ttyport_close(struct serdev_controller *ctrl)