summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2015-10-20 09:53:05 -0400
committerThierry Reding <thierry.reding@gmail.com>2015-11-06 08:26:27 -0500
commit4e11f5acb25b0b8eb937c726ade319b988fe3664 (patch)
treeb9fb12fcf6ffc5c7c6f9fca7b58632c934425457
parent912b8439041317a0562609ad892eeab9ba2f0cb2 (diff)
pwm: lpss: Add support for multiple PWMs
New Intel SoCs such as Broxton will have four PWMs per PCI (or ACPI) device. Each PWM has 1k of register space allocated from the parent device. Add support for this. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
-rw-r--r--drivers/pwm/pwm-lpss.c48
-rw-r--r--drivers/pwm/pwm-lpss.h1
2 files changed, 28 insertions, 21 deletions
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index e9798253a16f..e7392bdfdd18 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -29,6 +29,9 @@
29#define PWM_LIMIT (0x8000 + PWM_DIVISION_CORRECTION) 29#define PWM_LIMIT (0x8000 + PWM_DIVISION_CORRECTION)
30#define NSECS_PER_SEC 1000000000UL 30#define NSECS_PER_SEC 1000000000UL
31 31
32/* Size of each PWM register space if multiple */
33#define PWM_SIZE 0x400
34
32struct pwm_lpss_chip { 35struct pwm_lpss_chip {
33 struct pwm_chip chip; 36 struct pwm_chip chip;
34 void __iomem *regs; 37 void __iomem *regs;
@@ -37,13 +40,15 @@ struct pwm_lpss_chip {
37 40
38/* BayTrail */ 41/* BayTrail */
39const struct pwm_lpss_boardinfo pwm_lpss_byt_info = { 42const struct pwm_lpss_boardinfo pwm_lpss_byt_info = {
40 .clk_rate = 25000000 43 .clk_rate = 25000000,
44 .npwm = 1,
41}; 45};
42EXPORT_SYMBOL_GPL(pwm_lpss_byt_info); 46EXPORT_SYMBOL_GPL(pwm_lpss_byt_info);
43 47
44/* Braswell */ 48/* Braswell */
45const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = { 49const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
46 .clk_rate = 19200000 50 .clk_rate = 19200000,
51 .npwm = 1,
47}; 52};
48EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info); 53EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info);
49 54
@@ -52,6 +57,20 @@ static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
52 return container_of(chip, struct pwm_lpss_chip, chip); 57 return container_of(chip, struct pwm_lpss_chip, chip);
53} 58}
54 59
60static inline u32 pwm_lpss_read(const struct pwm_device *pwm)
61{
62 struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip);
63
64 return readl(lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM);
65}
66
67static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value)
68{
69 struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip);
70
71 writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM);
72}
73
55static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, 74static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
56 int duty_ns, int period_ns) 75 int duty_ns, int period_ns)
57{ 76{
@@ -79,38 +98,30 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
79 duty_ns = 1; 98 duty_ns = 1;
80 on_time_div = 255 - (255 * duty_ns / period_ns); 99 on_time_div = 255 - (255 * duty_ns / period_ns);
81 100
82 ctrl = readl(lpwm->regs + PWM); 101 ctrl = pwm_lpss_read(pwm);
83 ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK); 102 ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK);
84 ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT; 103 ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT;
85 ctrl |= on_time_div; 104 ctrl |= on_time_div;
86 /* request PWM to update on next cycle */ 105 /* request PWM to update on next cycle */
87 ctrl |= PWM_SW_UPDATE; 106 ctrl |= PWM_SW_UPDATE;
88 writel(ctrl, lpwm->regs + PWM); 107 pwm_lpss_write(pwm, ctrl);
89 108
90 return 0; 109 return 0;
91} 110}
92 111
93static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm) 112static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm)
94{ 113{
95 struct pwm_lpss_chip *lpwm = to_lpwm(chip); 114 pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
96 u32 ctrl;
97
98 ctrl = readl(lpwm->regs + PWM);
99 writel(ctrl | PWM_ENABLE, lpwm->regs + PWM);
100
101 return 0; 115 return 0;
102} 116}
103 117
104static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm) 118static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm)
105{ 119{
106 struct pwm_lpss_chip *lpwm = to_lpwm(chip); 120 pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
107 u32 ctrl;
108
109 ctrl = readl(lpwm->regs + PWM);
110 writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM);
111} 121}
112 122
113static const struct pwm_ops pwm_lpss_ops = { 123static const struct pwm_ops pwm_lpss_ops = {
124 .free = pwm_lpss_disable,
114 .config = pwm_lpss_config, 125 .config = pwm_lpss_config,
115 .enable = pwm_lpss_enable, 126 .enable = pwm_lpss_enable,
116 .disable = pwm_lpss_disable, 127 .disable = pwm_lpss_disable,
@@ -135,7 +146,7 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
135 lpwm->chip.dev = dev; 146 lpwm->chip.dev = dev;
136 lpwm->chip.ops = &pwm_lpss_ops; 147 lpwm->chip.ops = &pwm_lpss_ops;
137 lpwm->chip.base = -1; 148 lpwm->chip.base = -1;
138 lpwm->chip.npwm = 1; 149 lpwm->chip.npwm = info->npwm;
139 150
140 ret = pwmchip_add(&lpwm->chip); 151 ret = pwmchip_add(&lpwm->chip);
141 if (ret) { 152 if (ret) {
@@ -149,11 +160,6 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe);
149 160
150int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) 161int pwm_lpss_remove(struct pwm_lpss_chip *lpwm)
151{ 162{
152 u32 ctrl;
153
154 ctrl = readl(lpwm->regs + PWM);
155 writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM);
156
157 return pwmchip_remove(&lpwm->chip); 163 return pwmchip_remove(&lpwm->chip);
158} 164}
159EXPORT_SYMBOL_GPL(pwm_lpss_remove); 165EXPORT_SYMBOL_GPL(pwm_lpss_remove);
diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h
index aa041bb1b67d..180438368e0a 100644
--- a/drivers/pwm/pwm-lpss.h
+++ b/drivers/pwm/pwm-lpss.h
@@ -20,6 +20,7 @@ struct pwm_lpss_chip;
20 20
21struct pwm_lpss_boardinfo { 21struct pwm_lpss_boardinfo {
22 unsigned long clk_rate; 22 unsigned long clk_rate;
23 unsigned int npwm;
23}; 24};
24 25
25extern const struct pwm_lpss_boardinfo pwm_lpss_byt_info; 26extern const struct pwm_lpss_boardinfo pwm_lpss_byt_info;