aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShobhit Kumar <shobhit.kumar@intel.com>2015-06-26 05:02:08 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2015-07-21 03:22:23 -0400
commita3f37a104bc42f19ceb74e3e06752b6e3a269745 (patch)
tree0f1ce7876eeeab9329d81f68742d80d77fdaaca3
parenta3aa9a93df9fc8a0c54485e4144fdb81591e2175 (diff)
pwm: crc: Add Crystalcove (CRC) PWM driver
The Crystalcove PMIC provides three PWM signals and this driver exports one of them on the BYT platform which is used to control backlight for DSI panel. This is platform device implementation of the drivers/mfd cell device for CRC PMIC. CC: Samuel Ortiz <sameo@linux.intel.com> Cc: Linus Walleij <linus.walleij@linaro.org> Cc: Alexandre Courbot <gnurou@gmail.com> Cc: Thierry Reding <thierry.reding@gmail.com> Cc: Paul Bolle <pebolle@tiscali.nl> Cc: Paul Gortmaker <paul.gortmaker@windriver.com> Tested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Shobhit Kumar <shobhit.kumar@intel.com> Reviewed-by: Varka Bhadram <varkabhadram@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--drivers/pwm/Kconfig7
-rw-r--r--drivers/pwm/Makefile1
-rw-r--r--drivers/pwm/pwm-crc.c143
3 files changed, 151 insertions, 0 deletions
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index b1541f40fd8d..948d9abd27f1 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -111,6 +111,13 @@ config PWM_CLPS711X
111 To compile this driver as a module, choose M here: the module 111 To compile this driver as a module, choose M here: the module
112 will be called pwm-clps711x. 112 will be called pwm-clps711x.
113 113
114config PWM_CRC
115 bool "Intel Crystalcove (CRC) PWM support"
116 depends on X86 && INTEL_SOC_PMIC
117 help
118 Generic PWM framework driver for Crystalcove (CRC) PMIC based PWM
119 control.
120
114config PWM_EP93XX 121config PWM_EP93XX
115 tristate "Cirrus Logic EP93xx PWM support" 122 tristate "Cirrus Logic EP93xx PWM support"
116 depends on ARCH_EP93XX 123 depends on ARCH_EP93XX
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index ec50eb5b5a8f..d186f35a6538 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PWM_BCM_KONA) += pwm-bcm-kona.o
8obj-$(CONFIG_PWM_BCM2835) += pwm-bcm2835.o 8obj-$(CONFIG_PWM_BCM2835) += pwm-bcm2835.o
9obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o 9obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
10obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o 10obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o
11obj-$(CONFIG_PWM_CRC) += pwm-crc.o
11obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o 12obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
12obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o 13obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
13obj-$(CONFIG_PWM_IMG) += pwm-img.o 14obj-$(CONFIG_PWM_IMG) += pwm-img.o
diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c
new file mode 100644
index 000000000000..7101c7020bf4
--- /dev/null
+++ b/drivers/pwm/pwm-crc.c
@@ -0,0 +1,143 @@
1/*
2 * Copyright (C) 2015 Intel Corporation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License version
6 * 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * Author: Shobhit Kumar <shobhit.kumar@intel.com>
14 */
15
16#include <linux/platform_device.h>
17#include <linux/regmap.h>
18#include <linux/mfd/intel_soc_pmic.h>
19#include <linux/pwm.h>
20
21#define PWM0_CLK_DIV 0x4B
22#define PWM_OUTPUT_ENABLE BIT(7)
23#define PWM_DIV_CLK_0 0x00 /* DIVIDECLK = BASECLK */
24#define PWM_DIV_CLK_100 0x63 /* DIVIDECLK = BASECLK/100 */
25#define PWM_DIV_CLK_128 0x7F /* DIVIDECLK = BASECLK/128 */
26
27#define PWM0_DUTY_CYCLE 0x4E
28#define BACKLIGHT_EN 0x51
29
30#define PWM_MAX_LEVEL 0xFF
31
32#define PWM_BASE_CLK 6000000 /* 6 MHz */
33#define PWM_MAX_PERIOD_NS 21333 /* 46.875KHz */
34
35/**
36 * struct crystalcove_pwm - Crystal Cove PWM controller
37 * @chip: the abstract pwm_chip structure.
38 * @regmap: the regmap from the parent device.
39 */
40struct crystalcove_pwm {
41 struct pwm_chip chip;
42 struct regmap *regmap;
43};
44
45static inline struct crystalcove_pwm *to_crc_pwm(struct pwm_chip *pc)
46{
47 return container_of(pc, struct crystalcove_pwm, chip);
48}
49
50static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm)
51{
52 struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
53
54 regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1);
55
56 return 0;
57}
58
59static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm)
60{
61 struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
62
63 regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0);
64}
65
66static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm,
67 int duty_ns, int period_ns)
68{
69 struct crystalcove_pwm *crc_pwm = to_crc_pwm(c);
70 struct device *dev = crc_pwm->chip.dev;
71 int level;
72
73 if (period_ns > PWM_MAX_PERIOD_NS) {
74 dev_err(dev, "un-supported period_ns\n");
75 return -EINVAL;
76 }
77
78 if (pwm->period != period_ns) {
79 int clk_div;
80
81 /* changing the clk divisor, need to disable fisrt */
82 crc_pwm_disable(c, pwm);
83 clk_div = PWM_BASE_CLK * period_ns / NSEC_PER_SEC;
84
85 regmap_write(crc_pwm->regmap, PWM0_CLK_DIV,
86 clk_div | PWM_OUTPUT_ENABLE);
87
88 /* enable back */
89 crc_pwm_enable(c, pwm);
90 }
91
92 /* change the pwm duty cycle */
93 level = duty_ns * PWM_MAX_LEVEL / period_ns;
94 regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level);
95
96 return 0;
97}
98
99static const struct pwm_ops crc_pwm_ops = {
100 .config = crc_pwm_config,
101 .enable = crc_pwm_enable,
102 .disable = crc_pwm_disable,
103};
104
105static int crystalcove_pwm_probe(struct platform_device *pdev)
106{
107 struct crystalcove_pwm *pwm;
108 struct device *dev = pdev->dev.parent;
109 struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
110
111 pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
112 if (!pwm)
113 return -ENOMEM;
114
115 pwm->chip.dev = &pdev->dev;
116 pwm->chip.ops = &crc_pwm_ops;
117 pwm->chip.base = -1;
118 pwm->chip.npwm = 1;
119
120 /* get the PMIC regmap */
121 pwm->regmap = pmic->regmap;
122
123 platform_set_drvdata(pdev, pwm);
124
125 return pwmchip_add(&pwm->chip);
126}
127
128static int crystalcove_pwm_remove(struct platform_device *pdev)
129{
130 struct crystalcove_pwm *pwm = platform_get_drvdata(pdev);
131
132 return pwmchip_remove(&pwm->chip);
133}
134
135static struct platform_driver crystalcove_pwm_driver = {
136 .probe = crystalcove_pwm_probe,
137 .remove = crystalcove_pwm_remove,
138 .driver = {
139 .name = "crystal_cove_pwm",
140 },
141};
142
143builtin_platform_driver(crystalcove_pwm_driver);