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; |
