blob: 4bce43d4c61faffbbf81b2a154e77603e10bc550 [file] [log] [blame]
/*
* 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);