diff options
author | Jochen Friedrich <jochen@scram.de> | 2011-11-27 22:00:54 +0100 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-01-09 00:37:33 +0100 |
commit | 5dd7bf59e0e8563265b3e5b33276099ef628fcc7 (patch) | |
tree | 1372dd626865e4ed21cac103a706f06ef6ff700e /drivers | |
parent | c9531227b289947950cce29cfe881b768bf9d7d9 (diff) |
ARM: sa11x0: Implement autoloading of codec and codec pdata for mcp bus.
Signed-off-by: Jochen Friedrich <jochen@scram.de>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mfd/mcp-core.c | 44 | ||||
-rw-r--r-- | drivers/mfd/mcp-sa11x0.c | 7 | ||||
-rw-r--r-- | drivers/mfd/ucb1x00-core.c | 48 | ||||
-rw-r--r-- | drivers/mfd/ucb1x00-ts.c | 2 |
4 files changed, 85 insertions, 16 deletions
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c index 84815f9ef636..63be60bc3455 100644 --- a/drivers/mfd/mcp-core.c +++ b/drivers/mfd/mcp-core.c @@ -26,9 +26,35 @@ #define to_mcp(d) container_of(d, struct mcp, attached_device) #define to_mcp_driver(d) container_of(d, struct mcp_driver, drv) +static const struct mcp_device_id *mcp_match_id(const struct mcp_device_id *id, + const char *codec) +{ + while (id->name[0]) { + if (strcmp(codec, id->name) == 0) + return id; + id++; + } + return NULL; +} + +const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp) +{ + const struct mcp_driver *driver = + to_mcp_driver(mcp->attached_device.driver); + + return mcp_match_id(driver->id_table, mcp->codec); +} +EXPORT_SYMBOL(mcp_get_device_id); + static int mcp_bus_match(struct device *dev, struct device_driver *drv) { - return 1; + const struct mcp *mcp = to_mcp(dev); + const struct mcp_driver *driver = to_mcp_driver(drv); + + if (driver->id_table) + return !!mcp_match_id(driver->id_table, mcp->codec); + + return 0; } static int mcp_bus_probe(struct device *dev) @@ -74,9 +100,18 @@ static int mcp_bus_resume(struct device *dev) return ret; } +static int mcp_bus_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct mcp *mcp = to_mcp(dev); + + add_uevent_var(env, "MODALIAS=%s%s", MCP_MODULE_PREFIX, mcp->codec); + return 0; +} + static struct bus_type mcp_bus_type = { .name = "mcp", .match = mcp_bus_match, + .uevent = mcp_bus_uevent, .probe = mcp_bus_probe, .remove = mcp_bus_remove, .suspend = mcp_bus_suspend, @@ -212,9 +247,14 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size) } EXPORT_SYMBOL(mcp_host_alloc); -int mcp_host_register(struct mcp *mcp) +int mcp_host_register(struct mcp *mcp, void *pdata) { + if (!mcp->codec) + return -EINVAL; + + mcp->attached_device.platform_data = pdata; dev_set_name(&mcp->attached_device, "mcp0"); + request_module("%s%s", MCP_MODULE_PREFIX, mcp->codec); return device_register(&mcp->attached_device); } EXPORT_SYMBOL(mcp_host_register); diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 02c53a0766c4..da4e077a1bee 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -146,6 +146,9 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) if (!data) return -ENODEV; + if (!data->codec) + return -ENODEV; + if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp")) return -EBUSY; @@ -162,7 +165,7 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) mcp->dma_audio_wr = DMA_Ser4MCP0Wr; mcp->dma_telco_rd = DMA_Ser4MCP1Rd; mcp->dma_telco_wr = DMA_Ser4MCP1Wr; - mcp->gpio_base = data->gpio_base; + mcp->codec = data->codec; platform_set_drvdata(pdev, mcp); @@ -195,7 +198,7 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) / mcp->sclk_rate; - ret = mcp_host_register(mcp); + ret = mcp_host_register(mcp, data->codec_pdata); if (ret == 0) goto out; diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index b281217334eb..91c4f25e0e55 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -36,6 +36,15 @@ static DEFINE_MUTEX(ucb1x00_mutex); static LIST_HEAD(ucb1x00_drivers); static LIST_HEAD(ucb1x00_devices); +static struct mcp_device_id ucb1x00_id[] = { + { "ucb1x00", 0 }, /* auto-detection */ + { "ucb1200", UCB_ID_1200 }, + { "ucb1300", UCB_ID_1300 }, + { "tc35143", UCB_ID_TC35143 }, + { } +}; +MODULE_DEVICE_TABLE(mcp, ucb1x00_id); + /** * ucb1x00_io_set_dir - set IO direction * @ucb: UCB1x00 structure describing chip @@ -527,17 +536,33 @@ static struct class ucb1x00_class = { static int ucb1x00_probe(struct mcp *mcp) { + const struct mcp_device_id *mid; struct ucb1x00 *ucb; struct ucb1x00_driver *drv; + struct ucb1x00_plat_data *pdata; unsigned int id; int ret = -ENODEV; int temp; mcp_enable(mcp); id = mcp_reg_read(mcp, UCB_ID); + mid = mcp_get_device_id(mcp); - if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) { - printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id); + if (mid && mid->driver_data) { + if (id != mid->driver_data) { + printk(KERN_WARNING "%s wrong ID %04x found: %04x\n", + mid->name, (unsigned int) mid->driver_data, id); + goto err_disable; + } + } else { + mid = &ucb1x00_id[1]; + while (mid->driver_data) { + if (id == mid->driver_data) + break; + mid++; + } + printk(KERN_WARNING "%s ID not found: %04x\n", + ucb1x00_id[0].name, id); goto err_disable; } @@ -546,28 +571,28 @@ static int ucb1x00_probe(struct mcp *mcp) if (!ucb) goto err_disable; - + pdata = mcp->attached_device.platform_data; ucb->dev.class = &ucb1x00_class; ucb->dev.parent = &mcp->attached_device; - dev_set_name(&ucb->dev, "ucb1x00"); + dev_set_name(&ucb->dev, mid->name); spin_lock_init(&ucb->lock); spin_lock_init(&ucb->io_lock); sema_init(&ucb->adc_sem, 1); - ucb->id = id; + ucb->id = mid; ucb->mcp = mcp; ucb->irq = ucb1x00_detect_irq(ucb); if (ucb->irq == NO_IRQ) { - printk(KERN_ERR "UCB1x00: IRQ probe failed\n"); + printk(KERN_ERR "%s: IRQ probe failed\n", mid->name); ret = -ENODEV; goto err_free; } ucb->gpio.base = -1; - if (mcp->gpio_base != 0) { + if (pdata && (pdata->gpio_base >= 0)) { ucb->gpio.label = dev_name(&ucb->dev); - ucb->gpio.base = mcp->gpio_base; + ucb->gpio.base = pdata->gpio_base; ucb->gpio.ngpio = 10; ucb->gpio.set = ucb1x00_gpio_set; ucb->gpio.get = ucb1x00_gpio_get; @@ -580,10 +605,10 @@ static int ucb1x00_probe(struct mcp *mcp) dev_info(&ucb->dev, "gpio_base not set so no gpiolib support"); ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING, - "UCB1x00", ucb); + mid->name, ucb); if (ret) { - printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", - ucb->irq, ret); + printk(KERN_ERR "%s: unable to grab irq%d: %d\n", + mid->name, ucb->irq, ret); goto err_gpio; } @@ -705,6 +730,7 @@ static struct mcp_driver ucb1x00_driver = { .remove = ucb1x00_remove, .suspend = ucb1x00_suspend, .resume = ucb1x00_resume, + .id_table = ucb1x00_id, }; static int __init ucb1x00_init(void) diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 38ffbd50a0d2..40ec3c118868 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -382,7 +382,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev) ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; idev->name = "Touchscreen panel"; - idev->id.product = ts->ucb->id; + idev->id.product = ts->ucb->id->driver_data; idev->open = ucb1x00_ts_open; idev->close = ucb1x00_ts_close; |