diff options
-rw-r--r-- | drivers/mfd/asic3.c | 80 |
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 | ||
28 | enum { | ||
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 | |||
43 | struct 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 | |||
55 | struct 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 | |||
28 | struct asic3 { | 70 | struct 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 | ||
39 | static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset); | 83 | static 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 | ||
587 | static 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 | |||
603 | static 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 */ |
545 | static int __init asic3_probe(struct platform_device *pdev) | 620 | static 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; |