• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright 2014 Bart Tanghe <bart.tanghe@thomasmore.be>
3   *
4   * This program is free software; you can redistribute it and/or modify
5   * it under the terms of the GNU General Public License as published by
6   * the Free Software Foundation; version 2.
7   */
8  
9  #include <linux/clk.h>
10  #include <linux/err.h>
11  #include <linux/io.h>
12  #include <linux/module.h>
13  #include <linux/of.h>
14  #include <linux/platform_device.h>
15  #include <linux/pwm.h>
16  
17  #define PWM_CONTROL		0x000
18  #define PWM_CONTROL_SHIFT(x)	((x) * 8)
19  #define PWM_CONTROL_MASK	0xff
20  #define PWM_MODE		0x80		/* set timer in PWM mode */
21  #define PWM_ENABLE		(1 << 0)
22  #define PWM_POLARITY		(1 << 4)
23  
24  #define PERIOD(x)		(((x) * 0x10) + 0x10)
25  #define DUTY(x)			(((x) * 0x10) + 0x14)
26  
27  #define MIN_PERIOD		108		/* 9.2 MHz max. PWM clock */
28  
29  struct bcm2835_pwm {
30  	struct pwm_chip chip;
31  	struct device *dev;
32  	void __iomem *base;
33  	struct clk *clk;
34  };
35  
to_bcm2835_pwm(struct pwm_chip * chip)36  static inline struct bcm2835_pwm *to_bcm2835_pwm(struct pwm_chip *chip)
37  {
38  	return container_of(chip, struct bcm2835_pwm, chip);
39  }
40  
bcm2835_pwm_request(struct pwm_chip * chip,struct pwm_device * pwm)41  static int bcm2835_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
42  {
43  	struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
44  	u32 value;
45  
46  	value = readl(pc->base + PWM_CONTROL);
47  	value &= ~(PWM_CONTROL_MASK << PWM_CONTROL_SHIFT(pwm->hwpwm));
48  	value |= (PWM_MODE << PWM_CONTROL_SHIFT(pwm->hwpwm));
49  	writel(value, pc->base + PWM_CONTROL);
50  
51  	return 0;
52  }
53  
bcm2835_pwm_free(struct pwm_chip * chip,struct pwm_device * pwm)54  static void bcm2835_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
55  {
56  	struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
57  	u32 value;
58  
59  	value = readl(pc->base + PWM_CONTROL);
60  	value &= ~(PWM_CONTROL_MASK << PWM_CONTROL_SHIFT(pwm->hwpwm));
61  	writel(value, pc->base + PWM_CONTROL);
62  }
63  
bcm2835_pwm_config(struct pwm_chip * chip,struct pwm_device * pwm,int duty_ns,int period_ns)64  static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
65  			      int duty_ns, int period_ns)
66  {
67  	struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
68  	unsigned long rate = clk_get_rate(pc->clk);
69  	unsigned long scaler;
70  
71  	if (!rate) {
72  		dev_err(pc->dev, "failed to get clock rate\n");
73  		return -EINVAL;
74  	}
75  
76  	scaler = NSEC_PER_SEC / rate;
77  
78  	if (period_ns <= MIN_PERIOD) {
79  		dev_err(pc->dev, "period %d not supported, minimum %d\n",
80  			period_ns, MIN_PERIOD);
81  		return -EINVAL;
82  	}
83  
84  	writel(duty_ns / scaler, pc->base + DUTY(pwm->hwpwm));
85  	writel(period_ns / scaler, pc->base + PERIOD(pwm->hwpwm));
86  
87  	return 0;
88  }
89  
bcm2835_pwm_enable(struct pwm_chip * chip,struct pwm_device * pwm)90  static int bcm2835_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
91  {
92  	struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
93  	u32 value;
94  
95  	value = readl(pc->base + PWM_CONTROL);
96  	value |= PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm);
97  	writel(value, pc->base + PWM_CONTROL);
98  
99  	return 0;
100  }
101  
bcm2835_pwm_disable(struct pwm_chip * chip,struct pwm_device * pwm)102  static void bcm2835_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
103  {
104  	struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
105  	u32 value;
106  
107  	value = readl(pc->base + PWM_CONTROL);
108  	value &= ~(PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm));
109  	writel(value, pc->base + PWM_CONTROL);
110  }
111  
bcm2835_set_polarity(struct pwm_chip * chip,struct pwm_device * pwm,enum pwm_polarity polarity)112  static int bcm2835_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
113  				enum pwm_polarity polarity)
114  {
115  	struct bcm2835_pwm *pc = to_bcm2835_pwm(chip);
116  	u32 value;
117  
118  	value = readl(pc->base + PWM_CONTROL);
119  
120  	if (polarity == PWM_POLARITY_NORMAL)
121  		value &= ~(PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm));
122  	else
123  		value |= PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm);
124  
125  	writel(value, pc->base + PWM_CONTROL);
126  
127  	return 0;
128  }
129  
130  static const struct pwm_ops bcm2835_pwm_ops = {
131  	.request = bcm2835_pwm_request,
132  	.free = bcm2835_pwm_free,
133  	.config = bcm2835_pwm_config,
134  	.enable = bcm2835_pwm_enable,
135  	.disable = bcm2835_pwm_disable,
136  	.set_polarity = bcm2835_set_polarity,
137  	.owner = THIS_MODULE,
138  };
139  
bcm2835_pwm_probe(struct platform_device * pdev)140  static int bcm2835_pwm_probe(struct platform_device *pdev)
141  {
142  	struct bcm2835_pwm *pc;
143  	struct resource *res;
144  	int ret;
145  
146  	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL);
147  	if (!pc)
148  		return -ENOMEM;
149  
150  	pc->dev = &pdev->dev;
151  
152  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
153  	pc->base = devm_ioremap_resource(&pdev->dev, res);
154  	if (IS_ERR(pc->base))
155  		return PTR_ERR(pc->base);
156  
157  	pc->clk = devm_clk_get(&pdev->dev, NULL);
158  	if (IS_ERR(pc->clk)) {
159  		dev_err(&pdev->dev, "clock not found: %ld\n", PTR_ERR(pc->clk));
160  		return PTR_ERR(pc->clk);
161  	}
162  
163  	ret = clk_prepare_enable(pc->clk);
164  	if (ret)
165  		return ret;
166  
167  	pc->chip.dev = &pdev->dev;
168  	pc->chip.ops = &bcm2835_pwm_ops;
169  	pc->chip.npwm = 2;
170  	pc->chip.of_xlate = of_pwm_xlate_with_flags;
171  	pc->chip.of_pwm_n_cells = 3;
172  
173  	platform_set_drvdata(pdev, pc);
174  
175  	ret = pwmchip_add(&pc->chip);
176  	if (ret < 0)
177  		goto add_fail;
178  
179  	return 0;
180  
181  add_fail:
182  	clk_disable_unprepare(pc->clk);
183  	return ret;
184  }
185  
bcm2835_pwm_remove(struct platform_device * pdev)186  static int bcm2835_pwm_remove(struct platform_device *pdev)
187  {
188  	struct bcm2835_pwm *pc = platform_get_drvdata(pdev);
189  
190  	clk_disable_unprepare(pc->clk);
191  
192  	return pwmchip_remove(&pc->chip);
193  }
194  
195  static const struct of_device_id bcm2835_pwm_of_match[] = {
196  	{ .compatible = "brcm,bcm2835-pwm", },
197  	{ /* sentinel */ }
198  };
199  MODULE_DEVICE_TABLE(of, bcm2835_pwm_of_match);
200  
201  static struct platform_driver bcm2835_pwm_driver = {
202  	.driver = {
203  		.name = "bcm2835-pwm",
204  		.of_match_table = bcm2835_pwm_of_match,
205  	},
206  	.probe = bcm2835_pwm_probe,
207  	.remove = bcm2835_pwm_remove,
208  };
209  module_platform_driver(bcm2835_pwm_driver);
210  
211  MODULE_AUTHOR("Bart Tanghe <bart.tanghe@thomasmore.be>");
212  MODULE_DESCRIPTION("Broadcom BCM2835 PWM driver");
213  MODULE_LICENSE("GPL v2");
214