diff options
Diffstat (limited to 'drivers/pwm/pwm-vt8500.c')
-rw-r--r-- | drivers/pwm/pwm-vt8500.c | 87 |
1 files changed, 72 insertions, 15 deletions
diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index f9de9b28e46e..69effd19afc7 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c | |||
@@ -36,6 +36,25 @@ | |||
36 | */ | 36 | */ |
37 | #define VT8500_NR_PWMS 2 | 37 | #define VT8500_NR_PWMS 2 |
38 | 38 | ||
39 | #define REG_CTRL(pwm) (((pwm) << 4) + 0x00) | ||
40 | #define REG_SCALAR(pwm) (((pwm) << 4) + 0x04) | ||
41 | #define REG_PERIOD(pwm) (((pwm) << 4) + 0x08) | ||
42 | #define REG_DUTY(pwm) (((pwm) << 4) + 0x0C) | ||
43 | #define REG_STATUS 0x40 | ||
44 | |||
45 | #define CTRL_ENABLE BIT(0) | ||
46 | #define CTRL_INVERT BIT(1) | ||
47 | #define CTRL_AUTOLOAD BIT(2) | ||
48 | #define CTRL_STOP_IMM BIT(3) | ||
49 | #define CTRL_LOAD_PRESCALE BIT(4) | ||
50 | #define CTRL_LOAD_PERIOD BIT(5) | ||
51 | |||
52 | #define STATUS_CTRL_UPDATE BIT(0) | ||
53 | #define STATUS_SCALAR_UPDATE BIT(1) | ||
54 | #define STATUS_PERIOD_UPDATE BIT(2) | ||
55 | #define STATUS_DUTY_UPDATE BIT(3) | ||
56 | #define STATUS_ALL_UPDATE 0x0F | ||
57 | |||
39 | struct vt8500_chip { | 58 | struct vt8500_chip { |
40 | struct pwm_chip chip; | 59 | struct pwm_chip chip; |
41 | void __iomem *base; | 60 | void __iomem *base; |
@@ -45,15 +64,17 @@ struct vt8500_chip { | |||
45 | #define to_vt8500_chip(chip) container_of(chip, struct vt8500_chip, chip) | 64 | #define to_vt8500_chip(chip) container_of(chip, struct vt8500_chip, chip) |
46 | 65 | ||
47 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) | 66 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) |
48 | static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask) | 67 | static inline void pwm_busy_wait(struct vt8500_chip *vt8500, int nr, u8 bitmask) |
49 | { | 68 | { |
50 | int loops = msecs_to_loops(10); | 69 | int loops = msecs_to_loops(10); |
51 | while ((readb(reg) & bitmask) && --loops) | 70 | u32 mask = bitmask << (nr << 8); |
71 | |||
72 | while ((readl(vt8500->base + REG_STATUS) & mask) && --loops) | ||
52 | cpu_relax(); | 73 | cpu_relax(); |
53 | 74 | ||
54 | if (unlikely(!loops)) | 75 | if (unlikely(!loops)) |
55 | pr_warn("Waiting for status bits 0x%x to clear timed out\n", | 76 | dev_warn(vt8500->chip.dev, "Waiting for status bits 0x%x to clear timed out\n", |
56 | bitmask); | 77 | mask); |
57 | } | 78 | } |
58 | 79 | ||
59 | static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | 80 | static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, |
@@ -63,6 +84,7 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
63 | unsigned long long c; | 84 | unsigned long long c; |
64 | unsigned long period_cycles, prescale, pv, dc; | 85 | unsigned long period_cycles, prescale, pv, dc; |
65 | int err; | 86 | int err; |
87 | u32 val; | ||
66 | 88 | ||
67 | err = clk_enable(vt8500->clk); | 89 | err = clk_enable(vt8500->clk); |
68 | if (err < 0) { | 90 | if (err < 0) { |
@@ -91,14 +113,19 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
91 | do_div(c, period_ns); | 113 | do_div(c, period_ns); |
92 | dc = c; | 114 | dc = c; |
93 | 115 | ||
94 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 1)); | 116 | writel(prescale, vt8500->base + REG_SCALAR(pwm->hwpwm)); |
95 | writel(prescale, vt8500->base + 0x4 + (pwm->hwpwm << 4)); | 117 | pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_SCALAR_UPDATE); |
96 | 118 | ||
97 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 2)); | 119 | writel(pv, vt8500->base + REG_PERIOD(pwm->hwpwm)); |
98 | writel(pv, vt8500->base + 0x8 + (pwm->hwpwm << 4)); | 120 | pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_PERIOD_UPDATE); |
99 | 121 | ||
100 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 3)); | 122 | writel(dc, vt8500->base + REG_DUTY(pwm->hwpwm)); |
101 | writel(dc, vt8500->base + 0xc + (pwm->hwpwm << 4)); | 123 | pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_DUTY_UPDATE); |
124 | |||
125 | val = readl(vt8500->base + REG_CTRL(pwm->hwpwm)); | ||
126 | val |= CTRL_AUTOLOAD; | ||
127 | writel(val, vt8500->base + REG_CTRL(pwm->hwpwm)); | ||
128 | pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE); | ||
102 | 129 | ||
103 | clk_disable(vt8500->clk); | 130 | clk_disable(vt8500->clk); |
104 | return 0; | 131 | return 0; |
@@ -106,8 +133,9 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | |||
106 | 133 | ||
107 | static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | 134 | static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) |
108 | { | 135 | { |
109 | int err; | ||
110 | struct vt8500_chip *vt8500 = to_vt8500_chip(chip); | 136 | struct vt8500_chip *vt8500 = to_vt8500_chip(chip); |
137 | int err; | ||
138 | u32 val; | ||
111 | 139 | ||
112 | err = clk_enable(vt8500->clk); | 140 | err = clk_enable(vt8500->clk); |
113 | if (err < 0) { | 141 | if (err < 0) { |
@@ -115,25 +143,52 @@ static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | |||
115 | return err; | 143 | return err; |
116 | } | 144 | } |
117 | 145 | ||
118 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0)); | 146 | val = readl(vt8500->base + REG_CTRL(pwm->hwpwm)); |
119 | writel(5, vt8500->base + (pwm->hwpwm << 4)); | 147 | val |= CTRL_ENABLE; |
148 | writel(val, vt8500->base + REG_CTRL(pwm->hwpwm)); | ||
149 | pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE); | ||
150 | |||
120 | return 0; | 151 | return 0; |
121 | } | 152 | } |
122 | 153 | ||
123 | static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | 154 | static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) |
124 | { | 155 | { |
125 | struct vt8500_chip *vt8500 = to_vt8500_chip(chip); | 156 | struct vt8500_chip *vt8500 = to_vt8500_chip(chip); |
157 | u32 val; | ||
126 | 158 | ||
127 | pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0)); | 159 | val = readl(vt8500->base + REG_CTRL(pwm->hwpwm)); |
128 | writel(0, vt8500->base + (pwm->hwpwm << 4)); | 160 | val &= ~CTRL_ENABLE; |
161 | writel(val, vt8500->base + REG_CTRL(pwm->hwpwm)); | ||
162 | pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE); | ||
129 | 163 | ||
130 | clk_disable(vt8500->clk); | 164 | clk_disable(vt8500->clk); |
131 | } | 165 | } |
132 | 166 | ||
167 | static int vt8500_pwm_set_polarity(struct pwm_chip *chip, | ||
168 | struct pwm_device *pwm, | ||
169 | enum pwm_polarity polarity) | ||
170 | { | ||
171 | struct vt8500_chip *vt8500 = to_vt8500_chip(chip); | ||
172 | u32 val; | ||
173 | |||
174 | val = readl(vt8500->base + REG_CTRL(pwm->hwpwm)); | ||
175 | |||
176 | if (polarity == PWM_POLARITY_INVERSED) | ||
177 | val |= CTRL_INVERT; | ||
178 | else | ||
179 | val &= ~CTRL_INVERT; | ||
180 | |||
181 | writel(val, vt8500->base + REG_CTRL(pwm->hwpwm)); | ||
182 | pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
133 | static struct pwm_ops vt8500_pwm_ops = { | 187 | static struct pwm_ops vt8500_pwm_ops = { |
134 | .enable = vt8500_pwm_enable, | 188 | .enable = vt8500_pwm_enable, |
135 | .disable = vt8500_pwm_disable, | 189 | .disable = vt8500_pwm_disable, |
136 | .config = vt8500_pwm_config, | 190 | .config = vt8500_pwm_config, |
191 | .set_polarity = vt8500_pwm_set_polarity, | ||
137 | .owner = THIS_MODULE, | 192 | .owner = THIS_MODULE, |
138 | }; | 193 | }; |
139 | 194 | ||
@@ -163,6 +218,8 @@ static int vt8500_pwm_probe(struct platform_device *pdev) | |||
163 | 218 | ||
164 | chip->chip.dev = &pdev->dev; | 219 | chip->chip.dev = &pdev->dev; |
165 | chip->chip.ops = &vt8500_pwm_ops; | 220 | chip->chip.ops = &vt8500_pwm_ops; |
221 | chip->chip.of_xlate = of_pwm_xlate_with_flags; | ||
222 | chip->chip.of_pwm_n_cells = 3; | ||
166 | chip->chip.base = -1; | 223 | chip->chip.base = -1; |
167 | chip->chip.npwm = VT8500_NR_PWMS; | 224 | chip->chip.npwm = VT8500_NR_PWMS; |
168 | 225 | ||