diff options
Diffstat (limited to 'drivers/pwm/pwm-lpss.c')
-rw-r--r-- | drivers/pwm/pwm-lpss.c | 48 |
1 files changed, 27 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 | |||
32 | struct pwm_lpss_chip { | 35 | struct 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 */ |
39 | const struct pwm_lpss_boardinfo pwm_lpss_byt_info = { | 42 | const struct pwm_lpss_boardinfo pwm_lpss_byt_info = { |
40 | .clk_rate = 25000000 | 43 | .clk_rate = 25000000, |
44 | .npwm = 1, | ||
41 | }; | 45 | }; |
42 | EXPORT_SYMBOL_GPL(pwm_lpss_byt_info); | 46 | EXPORT_SYMBOL_GPL(pwm_lpss_byt_info); |
43 | 47 | ||
44 | /* Braswell */ | 48 | /* Braswell */ |
45 | const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = { | 49 | const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = { |
46 | .clk_rate = 19200000 | 50 | .clk_rate = 19200000, |
51 | .npwm = 1, | ||
47 | }; | 52 | }; |
48 | EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info); | 53 | EXPORT_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 | ||
60 | static 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 | |||
67 | static 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 | |||
55 | static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm, | 74 | static 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 | ||
93 | static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm) | 112 | static 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 | ||
104 | static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm) | 118 | static 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 | ||
113 | static const struct pwm_ops pwm_lpss_ops = { | 123 | static 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 | ||
150 | int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) | 161 | int 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 | } |
159 | EXPORT_SYMBOL_GPL(pwm_lpss_remove); | 165 | EXPORT_SYMBOL_GPL(pwm_lpss_remove); |