aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mfd/asic3.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index ad3c59135990..ebe889392b6d 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -25,6 +25,48 @@
25 25
26#include <linux/mfd/asic3.h> 26#include <linux/mfd/asic3.h>
27 27
28enum {
29 ASIC3_CLOCK_SPI,
30 ASIC3_CLOCK_OWM,
31 ASIC3_CLOCK_PWM0,
32 ASIC3_CLOCK_PWM1,
33 ASIC3_CLOCK_LED0,
34 ASIC3_CLOCK_LED1,
35 ASIC3_CLOCK_LED2,
36 ASIC3_CLOCK_SD_HOST,
37 ASIC3_CLOCK_SD_BUS,
38 ASIC3_CLOCK_SMBUS,
39 ASIC3_CLOCK_EX0,
40 ASIC3_CLOCK_EX1,
41};
42
43struct asic3_clk {
44 int enabled;
45 unsigned int cdex;
46 unsigned long rate;
47};
48
49#define INIT_CDEX(_name, _rate) \
50 [ASIC3_CLOCK_##_name] = { \
51 .cdex = CLOCK_CDEX_##_name, \
52 .rate = _rate, \
53 }
54
55struct asic3_clk asic3_clk_init[] __initdata = {
56 INIT_CDEX(SPI, 0),
57 INIT_CDEX(OWM, 5000000),
58 INIT_CDEX(PWM0, 0),
59 INIT_CDEX(PWM1, 0),
60 INIT_CDEX(LED0, 0),
61 INIT_CDEX(LED1, 0),
62 INIT_CDEX(LED2, 0),
63 INIT_CDEX(SD_HOST, 24576000),
64 INIT_CDEX(SD_BUS, 12288000),
65 INIT_CDEX(SMBUS, 0),
66 INIT_CDEX(EX0, 32768),
67 INIT_CDEX(EX1, 24576000),
68};
69
28struct asic3 { 70struct asic3 {
29 void __iomem *mapping; 71 void __iomem *mapping;
30 unsigned int bus_shift; 72 unsigned int bus_shift;
@@ -34,6 +76,8 @@ struct asic3 {
34 u16 irq_bothedge[4]; 76 u16 irq_bothedge[4];
35 struct gpio_chip gpio; 77 struct gpio_chip gpio;
36 struct device *dev; 78 struct device *dev;
79
80 struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)];
37}; 81};
38 82
39static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset); 83static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset);
@@ -540,6 +584,37 @@ static int asic3_gpio_remove(struct platform_device *pdev)
540 return gpiochip_remove(&asic->gpio); 584 return gpiochip_remove(&asic->gpio);
541} 585}
542 586
587static int asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk)
588{
589 unsigned long flags;
590 u32 cdex;
591
592 spin_lock_irqsave(&asic->lock, flags);
593 if (clk->enabled++ == 0) {
594 cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX));
595 cdex |= clk->cdex;
596 asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex);
597 }
598 spin_unlock_irqrestore(&asic->lock, flags);
599
600 return 0;
601}
602
603static void asic3_clk_disable(struct asic3 *asic, struct asic3_clk *clk)
604{
605 unsigned long flags;
606 u32 cdex;
607
608 WARN_ON(clk->enabled == 0);
609
610 spin_lock_irqsave(&asic->lock, flags);
611 if (--clk->enabled == 0) {
612 cdex = asic3_read_register(asic, ASIC3_OFFSET(CLOCK, CDEX));
613 cdex &= ~clk->cdex;
614 asic3_write_register(asic, ASIC3_OFFSET(CLOCK, CDEX), cdex);
615 }
616 spin_unlock_irqrestore(&asic->lock, flags);
617}
543 618
544/* Core */ 619/* Core */
545static int __init asic3_probe(struct platform_device *pdev) 620static int __init asic3_probe(struct platform_device *pdev)
@@ -605,6 +680,11 @@ static int __init asic3_probe(struct platform_device *pdev)
605 goto out_irq; 680 goto out_irq;
606 } 681 }
607 682
683 /* Making a per-device copy is only needed for the
684 * theoretical case of multiple ASIC3s on one board:
685 */
686 memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init));
687
608 dev_info(asic->dev, "ASIC3 Core driver\n"); 688 dev_info(asic->dev, "ASIC3 Core driver\n");
609 689
610 return 0; 690 return 0;