summaryrefslogtreecommitdiff
path: root/drivers/video/tegra/host/bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra/host/bus.c')
-rw-r--r--drivers/video/tegra/host/bus.c100
1 files changed, 80 insertions, 20 deletions
diff --git a/drivers/video/tegra/host/bus.c b/drivers/video/tegra/host/bus.c
index 774aac7bd431..758a5ca4ad94 100644
--- a/drivers/video/tegra/host/bus.c
+++ b/drivers/video/tegra/host/bus.c
@@ -17,11 +17,14 @@
*
*/
+#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/nvhost.h>
+#include "bus.h"
#include "dev.h"
+struct nvhost_bus *nvhost_bus_inst;
struct nvhost_master *nvhost;
struct resource *nvhost_get_resource(struct nvhost_device *dev,
@@ -72,12 +75,43 @@ int nvhost_get_irq_byname(struct nvhost_device *dev, const char *name)
}
EXPORT_SYMBOL_GPL(nvhost_get_irq_byname);
+static struct nvhost_device_id *nvhost_bus_match_id(struct nvhost_device *dev,
+ struct nvhost_device_id *id_table)
+{
+ while (id_table->name[0]) {
+ if (strcmp(dev->name, id_table->name) == 0
+ && dev->version == id_table->version)
+ return id_table;
+ id_table++;
+ }
+ return NULL;
+}
+
+static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
+{
+ struct nvhost_device *dev = to_nvhost_device(_dev);
+ struct nvhost_driver *ndrv = to_nvhost_driver(drv);
+
+ /* check if driver support multiple devices through id_table */
+ if (ndrv->id_table)
+ return nvhost_bus_match_id(dev, ndrv->id_table) != NULL;
+ else /* driver does not support id_table */
+ return !strncmp(dev->name, drv->name, strlen(drv->name));
+}
+
static int nvhost_drv_probe(struct device *_dev)
{
struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
struct nvhost_device *dev = to_nvhost_device(_dev);
- return drv->probe(dev);
+ if (drv && drv->probe) {
+ if (drv->id_table)
+ return drv->probe(dev, nvhost_bus_match_id(dev, drv->id_table));
+ else
+ return drv->probe(dev, NULL);
+ }
+ else
+ return -ENODEV;
}
static int nvhost_drv_remove(struct device *_dev)
@@ -98,7 +132,7 @@ static void nvhost_drv_shutdown(struct device *_dev)
int nvhost_driver_register(struct nvhost_driver *drv)
{
- drv->driver.bus = &nvhost_bus_type;
+ drv->driver.bus = &nvhost_bus_inst->nvhost_bus_type;
if (drv->probe)
drv->driver.probe = nvhost_drv_probe;
if (drv->remove)
@@ -116,6 +150,23 @@ void nvhost_driver_unregister(struct nvhost_driver *drv)
}
EXPORT_SYMBOL_GPL(nvhost_driver_unregister);
+int nvhost_add_devices(struct nvhost_device **devs, int num)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < num; i++) {
+ ret = nvhost_device_register(devs[i]);
+ if (ret) {
+ while (--i >= 0)
+ nvhost_device_unregister(devs[i]);
+ break;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(nvhost_add_devices);
+
int nvhost_device_register(struct nvhost_device *dev)
{
int i, ret = 0;
@@ -129,7 +180,7 @@ int nvhost_device_register(struct nvhost_device *dev)
if (!dev->dev.parent && nvhost && nvhost->dev != dev)
dev->dev.parent = &nvhost->dev->dev;
- dev->dev.bus = &nvhost_bus_type;
+ dev->dev.bus = &nvhost_bus_inst->nvhost_bus_type;
if (dev->id != -1)
dev_set_name(&dev->dev, "%s.%d", dev->name, dev->id);
@@ -194,13 +245,6 @@ void nvhost_device_unregister(struct nvhost_device *dev)
}
EXPORT_SYMBOL_GPL(nvhost_device_unregister);
-static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
-{
- struct nvhost_device *dev = to_nvhost_device(_dev);
-
- return !strncmp(dev->name, drv->name, strlen(drv->name));
-}
-
#ifdef CONFIG_PM_SLEEP
static int nvhost_legacy_suspend(struct device *dev, pm_message_t mesg)
@@ -528,13 +572,6 @@ static const struct dev_pm_ops nvhost_dev_pm_ops = {
.runtime_idle = nvhost_pm_runtime_idle,
};
-struct bus_type nvhost_bus_type = {
- .name = "nvhost",
- .match = nvhost_bus_match,
- .pm = &nvhost_dev_pm_ops,
-};
-EXPORT_SYMBOL(nvhost_bus_type);
-
static int set_parent(struct device *dev, void *data)
{
struct nvhost_device *ndev = to_nvhost_device(dev);
@@ -549,21 +586,44 @@ int nvhost_bus_add_host(struct nvhost_master *host)
nvhost = host;
/* Assign host1x as parent to all devices in nvhost bus */
- bus_for_each_dev(&nvhost_bus_type, NULL, host, set_parent);
+ bus_for_each_dev(&nvhost_bus_inst->nvhost_bus_type, NULL, host, set_parent);
return 0;
}
+struct nvhost_bus *nvhost_bus_get(void)
+{
+ return nvhost_bus_inst;
+}
int nvhost_bus_init(void)
{
int err;
+ struct nvhost_chip_support *chip_ops;
pr_info("host1x bus init\n");
- err = bus_register(&nvhost_bus_type);
+ nvhost_bus_inst = kzalloc(sizeof(*nvhost_bus_inst), GFP_KERNEL);
+ if (nvhost_bus_inst == NULL) {
+ pr_err("%s: Cannot allocate nvhost_bus\n", __func__);
+ return -ENOMEM;
+ }
+
+ chip_ops = kzalloc(sizeof(*chip_ops), GFP_KERNEL);
+ if (chip_ops == NULL) {
+ pr_err("%s: Cannot allocate nvhost_chip_support\n", __func__);
+ kfree(nvhost_bus_inst);
+ nvhost_bus_inst = NULL;
+ return -ENOMEM;
+ }
+
+ nvhost_bus_inst->nvhost_bus_type.name = "nvhost";
+ nvhost_bus_inst->nvhost_bus_type.match = nvhost_bus_match;
+ nvhost_bus_inst->nvhost_bus_type.pm = &nvhost_dev_pm_ops;
+ nvhost_bus_inst->nvhost_chip_ops = chip_ops;
+
+ err = bus_register(&nvhost_bus_inst->nvhost_bus_type);
return err;
}
postcore_initcall(nvhost_bus_init);
-