184a9582fSTony Lindgren // SPDX-License-Identifier: GPL-2.0+ 284a9582fSTony Lindgren /* 384a9582fSTony Lindgren * Serial base bus layer for controllers 484a9582fSTony Lindgren * 584a9582fSTony Lindgren * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ 684a9582fSTony Lindgren * Author: Tony Lindgren <tony@atomide.com> 784a9582fSTony Lindgren * 884a9582fSTony Lindgren * The serial core bus manages the serial core controller instances. 984a9582fSTony Lindgren */ 1084a9582fSTony Lindgren 1184a9582fSTony Lindgren #include <linux/container_of.h> 1284a9582fSTony Lindgren #include <linux/device.h> 13*04c7f60cSTony Lindgren #include <linux/idr.h> 1484a9582fSTony Lindgren #include <linux/module.h> 1584a9582fSTony Lindgren #include <linux/serial_core.h> 1684a9582fSTony Lindgren #include <linux/slab.h> 1784a9582fSTony Lindgren #include <linux/spinlock.h> 1884a9582fSTony Lindgren 1984a9582fSTony Lindgren #include "serial_base.h" 2084a9582fSTony Lindgren 2153991424STony Lindgren static bool serial_base_initialized; 2253991424STony Lindgren 231ef2c2dfSTony Lindgren static const struct device_type serial_ctrl_type = { 241ef2c2dfSTony Lindgren .name = "ctrl", 251ef2c2dfSTony Lindgren }; 261ef2c2dfSTony Lindgren 271ef2c2dfSTony Lindgren static const struct device_type serial_port_type = { 281ef2c2dfSTony Lindgren .name = "port", 291ef2c2dfSTony Lindgren }; 301ef2c2dfSTony Lindgren 3184a9582fSTony Lindgren static int serial_base_match(struct device *dev, struct device_driver *drv) 3284a9582fSTony Lindgren { 337d695d83STony Lindgren if (dev->type == &serial_ctrl_type && 347d695d83STony Lindgren str_has_prefix(drv->name, serial_ctrl_type.name)) 357d695d83STony Lindgren return 1; 3684a9582fSTony Lindgren 377d695d83STony Lindgren if (dev->type == &serial_port_type && 387d695d83STony Lindgren str_has_prefix(drv->name, serial_port_type.name)) 397d695d83STony Lindgren return 1; 407d695d83STony Lindgren 417d695d83STony Lindgren return 0; 4284a9582fSTony Lindgren } 4384a9582fSTony Lindgren 4484a9582fSTony Lindgren static struct bus_type serial_base_bus_type = { 4584a9582fSTony Lindgren .name = "serial-base", 4684a9582fSTony Lindgren .match = serial_base_match, 4784a9582fSTony Lindgren }; 4884a9582fSTony Lindgren 4984a9582fSTony Lindgren int serial_base_driver_register(struct device_driver *driver) 5084a9582fSTony Lindgren { 5184a9582fSTony Lindgren driver->bus = &serial_base_bus_type; 5284a9582fSTony Lindgren 5384a9582fSTony Lindgren return driver_register(driver); 5484a9582fSTony Lindgren } 5584a9582fSTony Lindgren 5684a9582fSTony Lindgren void serial_base_driver_unregister(struct device_driver *driver) 5784a9582fSTony Lindgren { 5884a9582fSTony Lindgren driver_unregister(driver); 5984a9582fSTony Lindgren } 6084a9582fSTony Lindgren 6184a9582fSTony Lindgren static int serial_base_device_init(struct uart_port *port, 6284a9582fSTony Lindgren struct device *dev, 6384a9582fSTony Lindgren struct device *parent_dev, 6484a9582fSTony Lindgren const struct device_type *type, 6584a9582fSTony Lindgren void (*release)(struct device *dev), 661ef2c2dfSTony Lindgren unsigned int ctrl_id, 671ef2c2dfSTony Lindgren unsigned int port_id) 6884a9582fSTony Lindgren { 6984a9582fSTony Lindgren device_initialize(dev); 7084a9582fSTony Lindgren dev->type = type; 7184a9582fSTony Lindgren dev->parent = parent_dev; 7284a9582fSTony Lindgren dev->bus = &serial_base_bus_type; 7384a9582fSTony Lindgren dev->release = release; 7484a9582fSTony Lindgren 75cef09673SDan Carpenter if (!serial_base_initialized) { 76cef09673SDan Carpenter dev_dbg(port->dev, "uart_add_one_port() called before arch_initcall()?\n"); 77cef09673SDan Carpenter return -EPROBE_DEFER; 78cef09673SDan Carpenter } 79cef09673SDan Carpenter 801ef2c2dfSTony Lindgren if (type == &serial_ctrl_type) 811ef2c2dfSTony Lindgren return dev_set_name(dev, "%s:%d", dev_name(port->dev), ctrl_id); 8284a9582fSTony Lindgren 831ef2c2dfSTony Lindgren if (type == &serial_port_type) 841ef2c2dfSTony Lindgren return dev_set_name(dev, "%s:%d.%d", dev_name(port->dev), 851ef2c2dfSTony Lindgren ctrl_id, port_id); 861ef2c2dfSTony Lindgren 871ef2c2dfSTony Lindgren return -EINVAL; 881ef2c2dfSTony Lindgren } 8984a9582fSTony Lindgren 9084a9582fSTony Lindgren static void serial_base_ctrl_release(struct device *dev) 9184a9582fSTony Lindgren { 9284a9582fSTony Lindgren struct serial_ctrl_device *ctrl_dev = to_serial_base_ctrl_device(dev); 9384a9582fSTony Lindgren 9484a9582fSTony Lindgren kfree(ctrl_dev); 9584a9582fSTony Lindgren } 9684a9582fSTony Lindgren 9784a9582fSTony Lindgren void serial_base_ctrl_device_remove(struct serial_ctrl_device *ctrl_dev) 9884a9582fSTony Lindgren { 9984a9582fSTony Lindgren if (!ctrl_dev) 10084a9582fSTony Lindgren return; 10184a9582fSTony Lindgren 10284a9582fSTony Lindgren device_del(&ctrl_dev->dev); 1036be1a8d5STony Lindgren put_device(&ctrl_dev->dev); 10484a9582fSTony Lindgren } 10584a9582fSTony Lindgren 10684a9582fSTony Lindgren struct serial_ctrl_device *serial_base_ctrl_add(struct uart_port *port, 10784a9582fSTony Lindgren struct device *parent) 10884a9582fSTony Lindgren { 10984a9582fSTony Lindgren struct serial_ctrl_device *ctrl_dev; 11084a9582fSTony Lindgren int err; 11184a9582fSTony Lindgren 11284a9582fSTony Lindgren ctrl_dev = kzalloc(sizeof(*ctrl_dev), GFP_KERNEL); 11384a9582fSTony Lindgren if (!ctrl_dev) 11484a9582fSTony Lindgren return ERR_PTR(-ENOMEM); 11584a9582fSTony Lindgren 116*04c7f60cSTony Lindgren ida_init(&ctrl_dev->port_ida); 117*04c7f60cSTony Lindgren 11884a9582fSTony Lindgren err = serial_base_device_init(port, &ctrl_dev->dev, 11984a9582fSTony Lindgren parent, &serial_ctrl_type, 12084a9582fSTony Lindgren serial_base_ctrl_release, 1211ef2c2dfSTony Lindgren port->ctrl_id, 0); 12284a9582fSTony Lindgren if (err) 12352861a3bSDan Carpenter goto err_put_device; 12484a9582fSTony Lindgren 12584a9582fSTony Lindgren err = device_add(&ctrl_dev->dev); 12684a9582fSTony Lindgren if (err) 12784a9582fSTony Lindgren goto err_put_device; 12884a9582fSTony Lindgren 12984a9582fSTony Lindgren return ctrl_dev; 13084a9582fSTony Lindgren 13184a9582fSTony Lindgren err_put_device: 13284a9582fSTony Lindgren put_device(&ctrl_dev->dev); 13384a9582fSTony Lindgren 13484a9582fSTony Lindgren return ERR_PTR(err); 13584a9582fSTony Lindgren } 13684a9582fSTony Lindgren 13784a9582fSTony Lindgren static void serial_base_port_release(struct device *dev) 13884a9582fSTony Lindgren { 13984a9582fSTony Lindgren struct serial_port_device *port_dev = to_serial_base_port_device(dev); 14084a9582fSTony Lindgren 14184a9582fSTony Lindgren kfree(port_dev); 14284a9582fSTony Lindgren } 14384a9582fSTony Lindgren 14484a9582fSTony Lindgren struct serial_port_device *serial_base_port_add(struct uart_port *port, 14584a9582fSTony Lindgren struct serial_ctrl_device *ctrl_dev) 14684a9582fSTony Lindgren { 14784a9582fSTony Lindgren struct serial_port_device *port_dev; 148*04c7f60cSTony Lindgren int min = 0, max = -1; /* Use -1 for max to apply IDA defaults */ 14984a9582fSTony Lindgren int err; 15084a9582fSTony Lindgren 15184a9582fSTony Lindgren port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); 15284a9582fSTony Lindgren if (!port_dev) 15384a9582fSTony Lindgren return ERR_PTR(-ENOMEM); 15484a9582fSTony Lindgren 155*04c7f60cSTony Lindgren /* Device driver specified port_id vs automatic assignment? */ 156*04c7f60cSTony Lindgren if (port->port_id) { 157*04c7f60cSTony Lindgren min = port->port_id; 158*04c7f60cSTony Lindgren max = port->port_id; 159*04c7f60cSTony Lindgren } 160*04c7f60cSTony Lindgren 161*04c7f60cSTony Lindgren err = ida_alloc_range(&ctrl_dev->port_ida, min, max, GFP_KERNEL); 162*04c7f60cSTony Lindgren if (err < 0) { 163*04c7f60cSTony Lindgren kfree(port_dev); 164*04c7f60cSTony Lindgren return ERR_PTR(err); 165*04c7f60cSTony Lindgren } 166*04c7f60cSTony Lindgren 167*04c7f60cSTony Lindgren port->port_id = err; 168*04c7f60cSTony Lindgren 16984a9582fSTony Lindgren err = serial_base_device_init(port, &port_dev->dev, 17084a9582fSTony Lindgren &ctrl_dev->dev, &serial_port_type, 17184a9582fSTony Lindgren serial_base_port_release, 172*04c7f60cSTony Lindgren port->ctrl_id, port->port_id); 17384a9582fSTony Lindgren if (err) 17452861a3bSDan Carpenter goto err_put_device; 17584a9582fSTony Lindgren 17684a9582fSTony Lindgren port_dev->port = port; 17784a9582fSTony Lindgren 17884a9582fSTony Lindgren err = device_add(&port_dev->dev); 17984a9582fSTony Lindgren if (err) 18084a9582fSTony Lindgren goto err_put_device; 18184a9582fSTony Lindgren 18284a9582fSTony Lindgren return port_dev; 18384a9582fSTony Lindgren 18484a9582fSTony Lindgren err_put_device: 18584a9582fSTony Lindgren put_device(&port_dev->dev); 186*04c7f60cSTony Lindgren ida_free(&ctrl_dev->port_ida, port->port_id); 18784a9582fSTony Lindgren 18884a9582fSTony Lindgren return ERR_PTR(err); 18984a9582fSTony Lindgren } 19084a9582fSTony Lindgren 19184a9582fSTony Lindgren void serial_base_port_device_remove(struct serial_port_device *port_dev) 19284a9582fSTony Lindgren { 193*04c7f60cSTony Lindgren struct serial_ctrl_device *ctrl_dev; 194*04c7f60cSTony Lindgren struct device *parent; 195*04c7f60cSTony Lindgren 19684a9582fSTony Lindgren if (!port_dev) 19784a9582fSTony Lindgren return; 19884a9582fSTony Lindgren 199*04c7f60cSTony Lindgren parent = port_dev->dev.parent; 200*04c7f60cSTony Lindgren ctrl_dev = to_serial_base_ctrl_device(parent); 201*04c7f60cSTony Lindgren 20284a9582fSTony Lindgren device_del(&port_dev->dev); 203*04c7f60cSTony Lindgren ida_free(&ctrl_dev->port_ida, port_dev->port->port_id); 2046be1a8d5STony Lindgren put_device(&port_dev->dev); 20584a9582fSTony Lindgren } 20684a9582fSTony Lindgren 20784a9582fSTony Lindgren static int serial_base_init(void) 20884a9582fSTony Lindgren { 20984a9582fSTony Lindgren int ret; 21084a9582fSTony Lindgren 21184a9582fSTony Lindgren ret = bus_register(&serial_base_bus_type); 21284a9582fSTony Lindgren if (ret) 21384a9582fSTony Lindgren return ret; 21484a9582fSTony Lindgren 21584a9582fSTony Lindgren ret = serial_base_ctrl_init(); 21684a9582fSTony Lindgren if (ret) 21784a9582fSTony Lindgren goto err_bus_unregister; 21884a9582fSTony Lindgren 21984a9582fSTony Lindgren ret = serial_base_port_init(); 22084a9582fSTony Lindgren if (ret) 22184a9582fSTony Lindgren goto err_ctrl_exit; 22284a9582fSTony Lindgren 22353991424STony Lindgren serial_base_initialized = true; 22453991424STony Lindgren 22584a9582fSTony Lindgren return 0; 22684a9582fSTony Lindgren 22784a9582fSTony Lindgren err_ctrl_exit: 22884a9582fSTony Lindgren serial_base_ctrl_exit(); 22984a9582fSTony Lindgren 23084a9582fSTony Lindgren err_bus_unregister: 23184a9582fSTony Lindgren bus_unregister(&serial_base_bus_type); 23284a9582fSTony Lindgren 23384a9582fSTony Lindgren return ret; 23484a9582fSTony Lindgren } 23553991424STony Lindgren arch_initcall(serial_base_init); 23684a9582fSTony Lindgren 23784a9582fSTony Lindgren static void serial_base_exit(void) 23884a9582fSTony Lindgren { 23984a9582fSTony Lindgren serial_base_port_exit(); 24084a9582fSTony Lindgren serial_base_ctrl_exit(); 24184a9582fSTony Lindgren bus_unregister(&serial_base_bus_type); 24284a9582fSTony Lindgren } 24384a9582fSTony Lindgren module_exit(serial_base_exit); 24484a9582fSTony Lindgren 24584a9582fSTony Lindgren MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); 24684a9582fSTony Lindgren MODULE_DESCRIPTION("Serial core bus"); 24784a9582fSTony Lindgren MODULE_LICENSE("GPL"); 248