diff options
author | Jochen Friedrich <jochen@scram.de> | 2011-11-27 16:00:54 -0500 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2012-01-08 18:37:33 -0500 |
commit | 5dd7bf59e0e8563265b3e5b33276099ef628fcc7 (patch) | |
tree | 1372dd626865e4ed21cac103a706f06ef6ff700e /drivers/mfd | |
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/mfd')
-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 @@ | |||
26 | #define to_mcp(d) container_of(d, struct mcp, attached_device) | 26 | #define to_mcp(d) container_of(d, struct mcp, attached_device) |
27 | #define to_mcp_driver(d) container_of(d, struct mcp_driver, drv) | 27 | #define to_mcp_driver(d) container_of(d, struct mcp_driver, drv) |
28 | 28 | ||
29 | static const struct mcp_device_id *mcp_match_id(const struct mcp_device_id *id, | ||
30 | const char *codec) | ||
31 | { | ||
32 | while (id->name[0]) { | ||
33 | if (strcmp(codec, id->name) == 0) | ||
34 | return id; | ||
35 | id++; | ||
36 | } | ||
37 | return NULL; | ||
38 | } | ||
39 | |||
40 | const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp) | ||
41 | { | ||
42 | const struct mcp_driver *driver = | ||
43 | to_mcp_driver(mcp->attached_device.driver); | ||
44 | |||
45 | return mcp_match_id(driver->id_table, mcp->codec); | ||
46 | } | ||
47 | EXPORT_SYMBOL(mcp_get_device_id); | ||
48 | |||
29 | static int mcp_bus_match(struct device *dev, struct device_driver *drv) | 49 | static int mcp_bus_match(struct device *dev, struct device_driver *drv) |
30 | { | 50 | { |
31 | return 1; | 51 | const struct mcp *mcp = to_mcp(dev); |
52 | const struct mcp_driver *driver = to_mcp_driver(drv); | ||
53 | |||
54 | if (driver->id_table) | ||
55 | return !!mcp_match_id(driver->id_table, mcp->codec); | ||
56 | |||
57 | return 0; | ||
32 | } | 58 | } |
33 | 59 | ||
34 | static int mcp_bus_probe(struct device *dev) | 60 | static int mcp_bus_probe(struct device *dev) |
@@ -74,9 +100,18 @@ static int mcp_bus_resume(struct device *dev) | |||
74 | return ret; | 100 | return ret; |
75 | } | 101 | } |
76 | 102 | ||
103 | static int mcp_bus_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
104 | { | ||
105 | struct mcp *mcp = to_mcp(dev); | ||
106 | |||
107 | add_uevent_var(env, "MODALIAS=%s%s", MCP_MODULE_PREFIX, mcp->codec); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
77 | static struct bus_type mcp_bus_type = { | 111 | static struct bus_type mcp_bus_type = { |
78 | .name = "mcp", | 112 | .name = "mcp", |
79 | .match = mcp_bus_match, | 113 | .match = mcp_bus_match, |
114 | .uevent = mcp_bus_uevent, | ||
80 | .probe = mcp_bus_probe, | 115 | .probe = mcp_bus_probe, |
81 | .remove = mcp_bus_remove, | 116 | .remove = mcp_bus_remove, |
82 | .suspend = mcp_bus_suspend, | 117 | .suspend = mcp_bus_suspend, |
@@ -212,9 +247,14 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size) | |||
212 | } | 247 | } |
213 | EXPORT_SYMBOL(mcp_host_alloc); | 248 | EXPORT_SYMBOL(mcp_host_alloc); |
214 | 249 | ||
215 | int mcp_host_register(struct mcp *mcp) | 250 | int mcp_host_register(struct mcp *mcp, void *pdata) |
216 | { | 251 | { |
252 | if (!mcp->codec) | ||
253 | return -EINVAL; | ||
254 | |||
255 | mcp->attached_device.platform_data = pdata; | ||
217 | dev_set_name(&mcp->attached_device, "mcp0"); | 256 | dev_set_name(&mcp->attached_device, "mcp0"); |
257 | request_module("%s%s", MCP_MODULE_PREFIX, mcp->codec); | ||
218 | return device_register(&mcp->attached_device); | 258 | return device_register(&mcp->attached_device); |
219 | } | 259 | } |
220 | EXPORT_SYMBOL(mcp_host_register); | 260 | 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) | |||
146 | if (!data) | 146 | if (!data) |
147 | return -ENODEV; | 147 | return -ENODEV; |
148 | 148 | ||
149 | if (!data->codec) | ||
150 | return -ENODEV; | ||
151 | |||
149 | if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp")) | 152 | if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp")) |
150 | return -EBUSY; | 153 | return -EBUSY; |
151 | 154 | ||
@@ -162,7 +165,7 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) | |||
162 | mcp->dma_audio_wr = DMA_Ser4MCP0Wr; | 165 | mcp->dma_audio_wr = DMA_Ser4MCP0Wr; |
163 | mcp->dma_telco_rd = DMA_Ser4MCP1Rd; | 166 | mcp->dma_telco_rd = DMA_Ser4MCP1Rd; |
164 | mcp->dma_telco_wr = DMA_Ser4MCP1Wr; | 167 | mcp->dma_telco_wr = DMA_Ser4MCP1Wr; |
165 | mcp->gpio_base = data->gpio_base; | 168 | mcp->codec = data->codec; |
166 | 169 | ||
167 | platform_set_drvdata(pdev, mcp); | 170 | platform_set_drvdata(pdev, mcp); |
168 | 171 | ||
@@ -195,7 +198,7 @@ static int mcp_sa11x0_probe(struct platform_device *pdev) | |||
195 | mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) / | 198 | mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) / |
196 | mcp->sclk_rate; | 199 | mcp->sclk_rate; |
197 | 200 | ||
198 | ret = mcp_host_register(mcp); | 201 | ret = mcp_host_register(mcp, data->codec_pdata); |
199 | if (ret == 0) | 202 | if (ret == 0) |
200 | goto out; | 203 | goto out; |
201 | 204 | ||
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); | |||
36 | static LIST_HEAD(ucb1x00_drivers); | 36 | static LIST_HEAD(ucb1x00_drivers); |
37 | static LIST_HEAD(ucb1x00_devices); | 37 | static LIST_HEAD(ucb1x00_devices); |
38 | 38 | ||
39 | static struct mcp_device_id ucb1x00_id[] = { | ||
40 | { "ucb1x00", 0 }, /* auto-detection */ | ||
41 | { "ucb1200", UCB_ID_1200 }, | ||
42 | { "ucb1300", UCB_ID_1300 }, | ||
43 | { "tc35143", UCB_ID_TC35143 }, | ||
44 | { } | ||
45 | }; | ||
46 | MODULE_DEVICE_TABLE(mcp, ucb1x00_id); | ||
47 | |||
39 | /** | 48 | /** |
40 | * ucb1x00_io_set_dir - set IO direction | 49 | * ucb1x00_io_set_dir - set IO direction |
41 | * @ucb: UCB1x00 structure describing chip | 50 | * @ucb: UCB1x00 structure describing chip |
@@ -527,17 +536,33 @@ static struct class ucb1x00_class = { | |||
527 | 536 | ||
528 | static int ucb1x00_probe(struct mcp *mcp) | 537 | static int ucb1x00_probe(struct mcp *mcp) |
529 | { | 538 | { |
539 | const struct mcp_device_id *mid; | ||
530 | struct ucb1x00 *ucb; | 540 | struct ucb1x00 *ucb; |
531 | struct ucb1x00_driver *drv; | 541 | struct ucb1x00_driver *drv; |
542 | struct ucb1x00_plat_data *pdata; | ||
532 | unsigned int id; | 543 | unsigned int id; |
533 | int ret = -ENODEV; | 544 | int ret = -ENODEV; |
534 | int temp; | 545 | int temp; |
535 | 546 | ||
536 | mcp_enable(mcp); | 547 | mcp_enable(mcp); |
537 | id = mcp_reg_read(mcp, UCB_ID); | 548 | id = mcp_reg_read(mcp, UCB_ID); |
549 | mid = mcp_get_device_id(mcp); | ||
538 | 550 | ||
539 | if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) { | 551 | if (mid && mid->driver_data) { |
540 | printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id); | 552 | if (id != mid->driver_data) { |
553 | printk(KERN_WARNING "%s wrong ID %04x found: %04x\n", | ||
554 | mid->name, (unsigned int) mid->driver_data, id); | ||
555 | goto err_disable; | ||
556 | } | ||
557 | } else { | ||
558 | mid = &ucb1x00_id[1]; | ||
559 | while (mid->driver_data) { | ||
560 | if (id == mid->driver_data) | ||
561 | break; | ||
562 | mid++; | ||
563 | } | ||
564 | printk(KERN_WARNING "%s ID not found: %04x\n", | ||
565 | ucb1x00_id[0].name, id); | ||
541 | goto err_disable; | 566 | goto err_disable; |
542 | } | 567 | } |
543 | 568 | ||
@@ -546,28 +571,28 @@ static int ucb1x00_probe(struct mcp *mcp) | |||
546 | if (!ucb) | 571 | if (!ucb) |
547 | goto err_disable; | 572 | goto err_disable; |
548 | 573 | ||
549 | 574 | pdata = mcp->attached_device.platform_data; | |
550 | ucb->dev.class = &ucb1x00_class; | 575 | ucb->dev.class = &ucb1x00_class; |
551 | ucb->dev.parent = &mcp->attached_device; | 576 | ucb->dev.parent = &mcp->attached_device; |
552 | dev_set_name(&ucb->dev, "ucb1x00"); | 577 | dev_set_name(&ucb->dev, mid->name); |
553 | 578 | ||
554 | spin_lock_init(&ucb->lock); | 579 | spin_lock_init(&ucb->lock); |
555 | spin_lock_init(&ucb->io_lock); | 580 | spin_lock_init(&ucb->io_lock); |
556 | sema_init(&ucb->adc_sem, 1); | 581 | sema_init(&ucb->adc_sem, 1); |
557 | 582 | ||
558 | ucb->id = id; | 583 | ucb->id = mid; |
559 | ucb->mcp = mcp; | 584 | ucb->mcp = mcp; |
560 | ucb->irq = ucb1x00_detect_irq(ucb); | 585 | ucb->irq = ucb1x00_detect_irq(ucb); |
561 | if (ucb->irq == NO_IRQ) { | 586 | if (ucb->irq == NO_IRQ) { |
562 | printk(KERN_ERR "UCB1x00: IRQ probe failed\n"); | 587 | printk(KERN_ERR "%s: IRQ probe failed\n", mid->name); |
563 | ret = -ENODEV; | 588 | ret = -ENODEV; |
564 | goto err_free; | 589 | goto err_free; |
565 | } | 590 | } |
566 | 591 | ||
567 | ucb->gpio.base = -1; | 592 | ucb->gpio.base = -1; |
568 | if (mcp->gpio_base != 0) { | 593 | if (pdata && (pdata->gpio_base >= 0)) { |
569 | ucb->gpio.label = dev_name(&ucb->dev); | 594 | ucb->gpio.label = dev_name(&ucb->dev); |
570 | ucb->gpio.base = mcp->gpio_base; | 595 | ucb->gpio.base = pdata->gpio_base; |
571 | ucb->gpio.ngpio = 10; | 596 | ucb->gpio.ngpio = 10; |
572 | ucb->gpio.set = ucb1x00_gpio_set; | 597 | ucb->gpio.set = ucb1x00_gpio_set; |
573 | ucb->gpio.get = ucb1x00_gpio_get; | 598 | ucb->gpio.get = ucb1x00_gpio_get; |
@@ -580,10 +605,10 @@ static int ucb1x00_probe(struct mcp *mcp) | |||
580 | dev_info(&ucb->dev, "gpio_base not set so no gpiolib support"); | 605 | dev_info(&ucb->dev, "gpio_base not set so no gpiolib support"); |
581 | 606 | ||
582 | ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING, | 607 | ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING, |
583 | "UCB1x00", ucb); | 608 | mid->name, ucb); |
584 | if (ret) { | 609 | if (ret) { |
585 | printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n", | 610 | printk(KERN_ERR "%s: unable to grab irq%d: %d\n", |
586 | ucb->irq, ret); | 611 | mid->name, ucb->irq, ret); |
587 | goto err_gpio; | 612 | goto err_gpio; |
588 | } | 613 | } |
589 | 614 | ||
@@ -705,6 +730,7 @@ static struct mcp_driver ucb1x00_driver = { | |||
705 | .remove = ucb1x00_remove, | 730 | .remove = ucb1x00_remove, |
706 | .suspend = ucb1x00_suspend, | 731 | .suspend = ucb1x00_suspend, |
707 | .resume = ucb1x00_resume, | 732 | .resume = ucb1x00_resume, |
733 | .id_table = ucb1x00_id, | ||
708 | }; | 734 | }; |
709 | 735 | ||
710 | static int __init ucb1x00_init(void) | 736 | 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) | |||
382 | ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; | 382 | ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; |
383 | 383 | ||
384 | idev->name = "Touchscreen panel"; | 384 | idev->name = "Touchscreen panel"; |
385 | idev->id.product = ts->ucb->id; | 385 | idev->id.product = ts->ucb->id->driver_data; |
386 | idev->open = ucb1x00_ts_open; | 386 | idev->open = ucb1x00_ts_open; |
387 | idev->close = ucb1x00_ts_close; | 387 | idev->close = ucb1x00_ts_close; |
388 | 388 | ||