Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pwm-bfin.c
Go to the documentation of this file.
1 /*
2  * Blackfin Pulse Width Modulation (PWM) core
3  *
4  * Copyright (c) 2011 Analog Devices Inc.
5  *
6  * Licensed under the GPL-2 or later.
7  */
8 
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 #include <linux/pwm.h>
12 #include <linux/slab.h>
13 
14 #include <asm/gptimers.h>
15 #include <asm/portmux.h>
16 
17 struct bfin_pwm_chip {
18  struct pwm_chip chip;
19 };
20 
21 struct bfin_pwm {
22  unsigned short pin;
23 };
24 
25 static const unsigned short pwm_to_gptimer_per[] = {
28 };
29 
30 static int bfin_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
31 {
32  struct bfin_pwm *priv;
33  int ret;
34 
35  if (pwm->hwpwm >= ARRAY_SIZE(pwm_to_gptimer_per))
36  return -EINVAL;
37 
38  priv = kzalloc(sizeof(*priv), GFP_KERNEL);
39  if (!priv)
40  return -ENOMEM;
41 
42  priv->pin = pwm_to_gptimer_per[pwm->hwpwm];
43 
44  ret = peripheral_request(priv->pin, NULL);
45  if (ret) {
46  kfree(priv);
47  return ret;
48  }
49 
50  pwm_set_chip_data(pwm, priv);
51 
52  return 0;
53 }
54 
55 static void bfin_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
56 {
57  struct bfin_pwm *priv = pwm_get_chip_data(pwm);
58 
59  if (priv) {
60  peripheral_free(priv->pin);
61  kfree(priv);
62  }
63 }
64 
65 static int bfin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
66  int duty_ns, int period_ns)
67 {
68  struct bfin_pwm *priv = pwm_get_chip_data(pwm);
69  unsigned long period, duty;
70  unsigned long long val;
71 
72  val = (unsigned long long)get_sclk() * period_ns;
73  do_div(val, NSEC_PER_SEC);
74  period = val;
75 
76  val = (unsigned long long)period * duty_ns;
77  do_div(val, period_ns);
78  duty = period - val;
79 
80  if (duty >= period)
81  duty = period - 1;
82 
84  set_gptimer_pwidth(priv->pin, duty);
85  set_gptimer_period(priv->pin, period);
86 
87  return 0;
88 }
89 
90 static int bfin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
91 {
92  struct bfin_pwm *priv = pwm_get_chip_data(pwm);
93 
94  enable_gptimer(priv->pin);
95 
96  return 0;
97 }
98 
99 static void bfin_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
100 {
101  struct bfin_pwm *priv = pwm_get_chip_data(pwm);
102 
103  disable_gptimer(priv->pin);
104 }
105 
106 static struct pwm_ops bfin_pwm_ops = {
107  .request = bfin_pwm_request,
108  .free = bfin_pwm_free,
109  .config = bfin_pwm_config,
110  .enable = bfin_pwm_enable,
111  .disable = bfin_pwm_disable,
112  .owner = THIS_MODULE,
113 };
114 
115 static int bfin_pwm_probe(struct platform_device *pdev)
116 {
117  struct bfin_pwm_chip *pwm;
118  int ret;
119 
120  pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
121  if (!pwm) {
122  dev_err(&pdev->dev, "failed to allocate memory\n");
123  return -ENOMEM;
124  }
125 
126  platform_set_drvdata(pdev, pwm);
127 
128  pwm->chip.dev = &pdev->dev;
129  pwm->chip.ops = &bfin_pwm_ops;
130  pwm->chip.base = -1;
131  pwm->chip.npwm = 12;
132 
133  ret = pwmchip_add(&pwm->chip);
134  if (ret < 0) {
135  dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
136  return ret;
137  }
138 
139  return 0;
140 }
141 
142 static int __devexit bfin_pwm_remove(struct platform_device *pdev)
143 {
144  struct bfin_pwm_chip *pwm = platform_get_drvdata(pdev);
145 
146  return pwmchip_remove(&pwm->chip);
147 }
148 
149 static struct platform_driver bfin_pwm_driver = {
150  .driver = {
151  .name = "bfin-pwm",
152  },
153  .probe = bfin_pwm_probe,
154  .remove = __devexit_p(bfin_pwm_remove),
155 };
156 
157 module_platform_driver(bfin_pwm_driver);
158 
159 MODULE_LICENSE("GPL");