Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

pwm: berlin: Add suspend/resume support

This patch adds suspend-to-RAM support to the Berlin PWM driver.

Signed-off-by: Jisheng Zhang <jszhang@marvell.com>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>

authored by

Jisheng Zhang and committed by
Thierry Reding
bbf0722c 45c0ce84

+84
+84
drivers/pwm/pwm-berlin.c
··· 16 16 #include <linux/module.h> 17 17 #include <linux/platform_device.h> 18 18 #include <linux/pwm.h> 19 + #include <linux/slab.h> 19 20 20 21 #define BERLIN_PWM_EN 0x0 21 22 #define BERLIN_PWM_ENABLE BIT(0) ··· 27 26 #define BERLIN_PWM_DUTY 0x8 28 27 #define BERLIN_PWM_TCNT 0xc 29 28 #define BERLIN_PWM_MAX_TCNT 65535 29 + 30 + struct berlin_pwm_channel { 31 + u32 enable; 32 + u32 ctrl; 33 + u32 duty; 34 + u32 tcnt; 35 + }; 30 36 31 37 struct berlin_pwm_chip { 32 38 struct pwm_chip chip; ··· 61 53 unsigned long offset) 62 54 { 63 55 writel_relaxed(value, chip->base + channel * 0x10 + offset); 56 + } 57 + 58 + static int berlin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) 59 + { 60 + struct berlin_pwm_channel *channel; 61 + 62 + channel = kzalloc(sizeof(*channel), GFP_KERNEL); 63 + if (!channel) 64 + return -ENOMEM; 65 + 66 + return pwm_set_chip_data(pwm, channel); 67 + } 68 + 69 + static void berlin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) 70 + { 71 + struct berlin_pwm_channel *channel = pwm_get_chip_data(pwm); 72 + 73 + pwm_set_chip_data(pwm, NULL); 74 + kfree(channel); 64 75 } 65 76 66 77 static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, ··· 164 137 } 165 138 166 139 static const struct pwm_ops berlin_pwm_ops = { 140 + .request = berlin_pwm_request, 141 + .free = berlin_pwm_free, 167 142 .config = berlin_pwm_config, 168 143 .set_polarity = berlin_pwm_set_polarity, 169 144 .enable = berlin_pwm_enable, ··· 233 204 return ret; 234 205 } 235 206 207 + #ifdef CONFIG_PM_SLEEP 208 + static int berlin_pwm_suspend(struct device *dev) 209 + { 210 + struct berlin_pwm_chip *pwm = dev_get_drvdata(dev); 211 + unsigned int i; 212 + 213 + for (i = 0; i < pwm->chip.npwm; i++) { 214 + struct berlin_pwm_channel *channel; 215 + 216 + channel = pwm_get_chip_data(&pwm->chip.pwms[i]); 217 + if (!channel) 218 + continue; 219 + 220 + channel->enable = berlin_pwm_readl(pwm, i, BERLIN_PWM_ENABLE); 221 + channel->ctrl = berlin_pwm_readl(pwm, i, BERLIN_PWM_CONTROL); 222 + channel->duty = berlin_pwm_readl(pwm, i, BERLIN_PWM_DUTY); 223 + channel->tcnt = berlin_pwm_readl(pwm, i, BERLIN_PWM_TCNT); 224 + } 225 + 226 + clk_disable_unprepare(pwm->clk); 227 + 228 + return 0; 229 + } 230 + 231 + static int berlin_pwm_resume(struct device *dev) 232 + { 233 + struct berlin_pwm_chip *pwm = dev_get_drvdata(dev); 234 + unsigned int i; 235 + int ret; 236 + 237 + ret = clk_prepare_enable(pwm->clk); 238 + if (ret) 239 + return ret; 240 + 241 + for (i = 0; i < pwm->chip.npwm; i++) { 242 + struct berlin_pwm_channel *channel; 243 + 244 + channel = pwm_get_chip_data(&pwm->chip.pwms[i]); 245 + if (!channel) 246 + continue; 247 + 248 + berlin_pwm_writel(pwm, i, channel->ctrl, BERLIN_PWM_CONTROL); 249 + berlin_pwm_writel(pwm, i, channel->duty, BERLIN_PWM_DUTY); 250 + berlin_pwm_writel(pwm, i, channel->tcnt, BERLIN_PWM_TCNT); 251 + berlin_pwm_writel(pwm, i, channel->enable, BERLIN_PWM_ENABLE); 252 + } 253 + 254 + return 0; 255 + } 256 + #endif 257 + 258 + static SIMPLE_DEV_PM_OPS(berlin_pwm_pm_ops, berlin_pwm_suspend, 259 + berlin_pwm_resume); 260 + 236 261 static struct platform_driver berlin_pwm_driver = { 237 262 .probe = berlin_pwm_probe, 238 263 .remove = berlin_pwm_remove, 239 264 .driver = { 240 265 .name = "berlin-pwm", 241 266 .of_match_table = berlin_pwm_match, 267 + .pm = &berlin_pwm_pm_ops, 242 268 }, 243 269 }; 244 270 module_platform_driver(berlin_pwm_driver);