1/* 2 * Marvell Berlin PWM driver 3 * 4 * Copyright (C) 2015 Marvell Technology Group Ltd. 5 * 6 * Author: Antoine Tenart <antoine.tenart@free-electrons.com> 7 * 8 * This file is licensed under the terms of the GNU General Public 9 * License version 2. This program is licensed "as is" without any 10 * warranty of any kind, whether express or implied. 11 */ 12 13#include <linux/clk.h> 14#include <linux/io.h> 15#include <linux/kernel.h> 16#include <linux/module.h> 17#include <linux/platform_device.h> 18#include <linux/pwm.h> 19 20#define BERLIN_PWM_EN 0x0 21#define BERLIN_PWM_ENABLE BIT(0) 22#define BERLIN_PWM_CONTROL 0x4 23#define BERLIN_PWM_PRESCALE_MASK 0x7 24#define BERLIN_PWM_PRESCALE_MAX 4096 25#define BERLIN_PWM_INVERT_POLARITY BIT(3) 26#define BERLIN_PWM_DUTY 0x8 27#define BERLIN_PWM_TCNT 0xc 28#define BERLIN_PWM_MAX_TCNT 65535 29 30struct berlin_pwm_chip { 31 struct pwm_chip chip; 32 struct clk *clk; 33 void __iomem *base; 34}; 35 36static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip) 37{ 38 return container_of(chip, struct berlin_pwm_chip, chip); 39} 40 41static const u32 prescaler_table[] = { 42 1, 4, 8, 16, 64, 256, 1024, 4096 43}; 44 45static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip, 46 unsigned int channel, unsigned long offset) 47{ 48 return readl_relaxed(chip->base + channel * 0x10 + offset); 49} 50 51static inline void berlin_pwm_writel(struct berlin_pwm_chip *chip, 52 unsigned int channel, u32 value, 53 unsigned long offset) 54{ 55 writel_relaxed(value, chip->base + channel * 0x10 + offset); 56} 57 58static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, 59 int duty_ns, int period_ns) 60{ 61 struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); 62 unsigned int prescale; 63 u32 value, duty, period; 64 u64 cycles, tmp; 65 66 cycles = clk_get_rate(pwm->clk); 67 cycles *= period_ns; 68 do_div(cycles, NSEC_PER_SEC); 69 70 for (prescale = 0; prescale < ARRAY_SIZE(prescaler_table); prescale++) { 71 tmp = cycles; 72 do_div(tmp, prescaler_table[prescale]); 73 74 if (tmp <= BERLIN_PWM_MAX_TCNT) 75 break; 76 } 77 78 if (tmp > BERLIN_PWM_MAX_TCNT) 79 return -ERANGE; 80 81 period = tmp; 82 cycles = tmp * duty_ns; 83 do_div(cycles, period_ns); 84 duty = cycles; 85 86 value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL); 87 value &= ~BERLIN_PWM_PRESCALE_MASK; 88 value |= prescale; 89 berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL); 90 91 berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY); 92 berlin_pwm_writel(pwm, pwm_dev->hwpwm, period, BERLIN_PWM_TCNT); 93 94 return 0; 95} 96 97static int berlin_pwm_set_polarity(struct pwm_chip *chip, 98 struct pwm_device *pwm_dev, 99 enum pwm_polarity polarity) 100{ 101 struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); 102 u32 value; 103 104 value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL); 105 106 if (polarity == PWM_POLARITY_NORMAL) 107 value &= ~BERLIN_PWM_INVERT_POLARITY; 108 else 109 value |= BERLIN_PWM_INVERT_POLARITY; 110 111 berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL); 112 113 return 0; 114} 115 116static int berlin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm_dev) 117{ 118 struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); 119 u32 value; 120 121 value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN); 122 value |= BERLIN_PWM_ENABLE; 123 berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN); 124 125 return 0; 126} 127 128static void berlin_pwm_disable(struct pwm_chip *chip, 129 struct pwm_device *pwm_dev) 130{ 131 struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); 132 u32 value; 133 134 value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN); 135 value &= ~BERLIN_PWM_ENABLE; 136 berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN); 137} 138 139static const struct pwm_ops berlin_pwm_ops = { 140 .config = berlin_pwm_config, 141 .set_polarity = berlin_pwm_set_polarity, 142 .enable = berlin_pwm_enable, 143 .disable = berlin_pwm_disable, 144 .owner = THIS_MODULE, 145}; 146 147static const struct of_device_id berlin_pwm_match[] = { 148 { .compatible = "marvell,berlin-pwm" }, 149 { }, 150}; 151MODULE_DEVICE_TABLE(of, berlin_pwm_match); 152 153static int berlin_pwm_probe(struct platform_device *pdev) 154{ 155 struct berlin_pwm_chip *pwm; 156 struct resource *res; 157 int ret; 158 159 pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); 160 if (!pwm) 161 return -ENOMEM; 162 163 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 164 pwm->base = devm_ioremap_resource(&pdev->dev, res); 165 if (IS_ERR(pwm->base)) 166 return PTR_ERR(pwm->base); 167 168 pwm->clk = devm_clk_get(&pdev->dev, NULL); 169 if (IS_ERR(pwm->clk)) 170 return PTR_ERR(pwm->clk); 171 172 ret = clk_prepare_enable(pwm->clk); 173 if (ret) 174 return ret; 175 176 pwm->chip.dev = &pdev->dev; 177 pwm->chip.ops = &berlin_pwm_ops; 178 pwm->chip.base = -1; 179 pwm->chip.npwm = 4; 180 pwm->chip.can_sleep = true; 181 pwm->chip.of_xlate = of_pwm_xlate_with_flags; 182 pwm->chip.of_pwm_n_cells = 3; 183 184 ret = pwmchip_add(&pwm->chip); 185 if (ret < 0) { 186 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); 187 clk_disable_unprepare(pwm->clk); 188 return ret; 189 } 190 191 platform_set_drvdata(pdev, pwm); 192 193 return 0; 194} 195 196static int berlin_pwm_remove(struct platform_device *pdev) 197{ 198 struct berlin_pwm_chip *pwm = platform_get_drvdata(pdev); 199 int ret; 200 201 ret = pwmchip_remove(&pwm->chip); 202 clk_disable_unprepare(pwm->clk); 203 204 return ret; 205} 206 207static struct platform_driver berlin_pwm_driver = { 208 .probe = berlin_pwm_probe, 209 .remove = berlin_pwm_remove, 210 .driver = { 211 .name = "berlin-pwm", 212 .of_match_table = berlin_pwm_match, 213 }, 214}; 215module_platform_driver(berlin_pwm_driver); 216 217MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>"); 218MODULE_DESCRIPTION("Marvell Berlin PWM driver"); 219MODULE_LICENSE("GPL v2"); 220