/* * hsi_driver_bus.c * * Implements an HSI bus, device and driver interface. * * Copyright (C) 2007-2008 Nokia Corporation. All rights reserved. * Copyright (C) 2009 Texas Instruments, Inc. * * Author: Carlos Chinea <carlos.chinea@nokia.com> * Author: Sebastien JAN <s-jan@ti.com> * * This package is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include <linux/device.h> #include "hsi_driver.h" #define HSI_PREFIX "hsi:" struct bus_type hsi_bus_type; static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf) { return snprintf(buf, PAGE_SIZE + 1, "%s%s\n", HSI_PREFIX, dev_name(dev)); } static struct device_attribute hsi_dev_attrs[] = { __ATTR_RO(modalias), __ATTR_NULL, }; static int hsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { add_uevent_var(env, "MODALIAS=%s%s", HSI_PREFIX, dev_name(dev)); return 0; } static int hsi_bus_match(struct device *device, struct device_driver *driver) { struct hsi_device *dev = to_hsi_device(device); struct hsi_device_driver *drv = to_hsi_device_driver(driver); pr_debug("HSI DRIVER BUS : hsi_bus_match for ctrl:%d, port:%d, ch%d\n", dev->n_ctrl, dev->n_p, dev->n_ch); if (!test_bit(dev->n_ctrl, &drv->ctrl_mask)) return 0; if (!test_bit(dev->n_ch, &drv->ch_mask[dev->n_p])) return 0; pr_info ("HSI DRIVER BUS : hsi_bus_match SUCCESS : ctrl:%d (mask:%x)," " port:%d, ch:%d (mask:%x)\n", dev->n_ctrl, (u32) drv->ctrl_mask, dev->n_p, dev->n_ch, (u32) drv->ch_mask[dev->n_p]); return 1; } int hsi_bus_unreg_dev(struct device *device, void *p) { device->release(device); device_unregister(device); return 0; } int __init hsi_bus_init(void) { return bus_register(&hsi_bus_type); } void hsi_bus_exit(void) { bus_for_each_dev(&hsi_bus_type, NULL, NULL, hsi_bus_unreg_dev); bus_unregister(&hsi_bus_type); } static int hsi_bus_probe(struct device *dev) { struct hsi_device_driver *drv; int rc; pr_debug("HSI DRIVER BUS : hsi_bus_probe\n"); if (!dev->driver) return 0; drv = to_hsi_device_driver(dev->driver); if (!drv->probe) return -ENODEV; rc = drv->probe(to_hsi_device(dev)); return rc; } static int hsi_bus_remove(struct device *dev) { struct hsi_device_driver *drv; int ret; pr_debug("HSI DRIVER BUS : hsi_bus_remove\n"); if (!dev->driver) return 0; drv = to_hsi_device_driver(dev->driver); if (drv->remove) { ret = drv->remove(to_hsi_device(dev)); } else { dev->driver = NULL; ret = 0; } return ret; } static int hsi_bus_suspend(struct device *dev, pm_message_t mesg) { struct hsi_device_driver *drv; if (!dev->driver) return 0; drv = to_hsi_device_driver(dev->driver); if (!drv->suspend) return 0; return drv->suspend(to_hsi_device(dev), mesg); } static int hsi_bus_resume(struct device *dev) { struct hsi_device_driver *drv; if (!dev->driver) return 0; drv = to_hsi_device_driver(dev->driver); if (!drv->resume) return 0; return drv->resume(to_hsi_device(dev)); } struct bus_type hsi_bus_type = { .name = "hsi", .dev_attrs = hsi_dev_attrs, .match = hsi_bus_match, .uevent = hsi_bus_uevent, .probe = hsi_bus_probe, .remove = hsi_bus_remove, .suspend = hsi_bus_suspend, .resume = hsi_bus_resume, }; /** * hsi_register_driver - Register HSI device driver * @driver - reference to the HSI device driver. */ int hsi_register_driver(struct hsi_device_driver *driver) { int ret = 0; if (driver == NULL) return -EINVAL; driver->driver.bus = &hsi_bus_type; ret = driver_register(&driver->driver); if (ret == 0) pr_debug("hsi: driver %s registered\n", driver->driver.name); return ret; } EXPORT_SYMBOL(hsi_register_driver); /** * hsi_unregister_driver - Unregister HSI device driver * @driver - reference to the HSI device driver. */ void hsi_unregister_driver(struct hsi_device_driver *driver) { if (driver == NULL) return; driver_unregister(&driver->driver); pr_debug("hsi: driver %s unregistered\n", driver->driver.name); } EXPORT_SYMBOL(hsi_unregister_driver);