Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
iio-trig-bfin-timer.c
Go to the documentation of this file.
1 /*
2  * Copyright 2011 Analog Devices Inc.
3  *
4  * Licensed under the GPL-2.
5  *
6  */
7 
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/platform_device.h>
11 #include <linux/slab.h>
12 #include <linux/interrupt.h>
13 #include <linux/irq.h>
14 #include <linux/delay.h>
15 
16 #include <asm/gptimers.h>
17 #include <asm/portmux.h>
18 
19 #include <linux/iio/iio.h>
20 #include <linux/iio/trigger.h>
21 
22 #include "iio-trig-bfin-timer.h"
23 
24 struct bfin_timer {
25  unsigned short id, bit;
26  unsigned long irqbit;
27  int irq;
28  int pin;
29 };
30 
31 /*
32  * this covers all hardware timer configurations on
33  * all Blackfin derivatives out there today
34  */
35 
36 static struct bfin_timer iio_bfin_timer_code[MAX_BLACKFIN_GPTIMERS] = {
40 #if (MAX_BLACKFIN_GPTIMERS > 3)
46 #endif
47 #if (MAX_BLACKFIN_GPTIMERS > 8)
51 #if (MAX_BLACKFIN_GPTIMERS > 11)
53 #endif
54 #endif
55 };
56 
58  struct iio_trigger *trig;
59  struct bfin_timer *t;
60  unsigned timer_num;
62  unsigned int duty;
63  int irq;
64 };
65 
66 static int iio_bfin_tmr_set_state(struct iio_trigger *trig, bool state)
67 {
68  struct bfin_tmr_state *st = trig->private_data;
69 
70  if (get_gptimer_period(st->t->id) == 0)
71  return -EINVAL;
72 
73  if (state)
74  enable_gptimers(st->t->bit);
75  else
76  disable_gptimers(st->t->bit);
77 
78  return 0;
79 }
80 
81 static ssize_t iio_bfin_tmr_frequency_store(struct device *dev,
82  struct device_attribute *attr, const char *buf, size_t count)
83 {
84  struct iio_trigger *trig = to_iio_trigger(dev);
85  struct bfin_tmr_state *st = trig->private_data;
86  unsigned long val;
87  bool enabled;
88  int ret;
89 
90  ret = strict_strtoul(buf, 10, &val);
91  if (ret)
92  goto error_ret;
93 
94  if (val > 100000) {
95  ret = -EINVAL;
96  goto error_ret;
97  }
98 
99  enabled = get_enabled_gptimers() & st->t->bit;
100 
101  if (enabled)
102  disable_gptimers(st->t->bit);
103 
104  if (!val)
105  goto error_ret;
106 
107  val = get_sclk() / val;
108  if (val <= 4 || val <= st->duty) {
109  ret = -EINVAL;
110  goto error_ret;
111  }
112 
113  set_gptimer_period(st->t->id, val);
114  set_gptimer_pwidth(st->t->id, val - st->duty);
115 
116  if (enabled)
117  enable_gptimers(st->t->bit);
118 
119 error_ret:
120  return ret ? ret : count;
121 }
122 
123 static ssize_t iio_bfin_tmr_frequency_show(struct device *dev,
124  struct device_attribute *attr,
125  char *buf)
126 {
127  struct iio_trigger *trig = to_iio_trigger(dev);
128  struct bfin_tmr_state *st = trig->private_data;
129  unsigned int period = get_gptimer_period(st->t->id);
130  unsigned long val;
131 
132  if (period == 0)
133  val = 0;
134  else
135  val = get_sclk() / get_gptimer_period(st->t->id);
136 
137  return sprintf(buf, "%lu\n", val);
138 }
139 
140 static DEVICE_ATTR(frequency, S_IRUGO | S_IWUSR, iio_bfin_tmr_frequency_show,
141  iio_bfin_tmr_frequency_store);
142 
143 static struct attribute *iio_bfin_tmr_trigger_attrs[] = {
144  &dev_attr_frequency.attr,
145  NULL,
146 };
147 
148 static const struct attribute_group iio_bfin_tmr_trigger_attr_group = {
149  .attrs = iio_bfin_tmr_trigger_attrs,
150 };
151 
152 static const struct attribute_group *iio_bfin_tmr_trigger_attr_groups[] = {
153  &iio_bfin_tmr_trigger_attr_group,
154  NULL
155 };
156 
157 static irqreturn_t iio_bfin_tmr_trigger_isr(int irq, void *devid)
158 {
159  struct bfin_tmr_state *st = devid;
160 
161  clear_gptimer_intr(st->t->id);
162  iio_trigger_poll(st->trig, 0);
163 
164  return IRQ_HANDLED;
165 }
166 
167 static int iio_bfin_tmr_get_number(int irq)
168 {
169  int i;
170 
171  for (i = 0; i < MAX_BLACKFIN_GPTIMERS; i++)
172  if (iio_bfin_timer_code[i].irq == irq)
173  return i;
174 
175  return -ENODEV;
176 }
177 
178 static const struct iio_trigger_ops iio_bfin_tmr_trigger_ops = {
179  .owner = THIS_MODULE,
180  .set_trigger_state = iio_bfin_tmr_set_state,
181 };
182 
183 static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
184 {
185  struct iio_bfin_timer_trigger_pdata *pdata = pdev->dev.platform_data;
186  struct bfin_tmr_state *st;
187  unsigned int config;
188  int ret;
189 
190  st = kzalloc(sizeof(*st), GFP_KERNEL);
191  if (st == NULL) {
192  ret = -ENOMEM;
193  goto out;
194  }
195 
196  st->irq = platform_get_irq(pdev, 0);
197  if (!st->irq) {
198  dev_err(&pdev->dev, "No IRQs specified");
199  ret = -ENODEV;
200  goto out1;
201  }
202 
203  ret = iio_bfin_tmr_get_number(st->irq);
204  if (ret < 0)
205  goto out1;
206 
207  st->timer_num = ret;
208  st->t = &iio_bfin_timer_code[st->timer_num];
209 
210  st->trig = iio_trigger_alloc("bfintmr%d", st->timer_num);
211  if (!st->trig) {
212  ret = -ENOMEM;
213  goto out1;
214  }
215 
216  st->trig->private_data = st;
217  st->trig->ops = &iio_bfin_tmr_trigger_ops;
218  st->trig->dev.groups = iio_bfin_tmr_trigger_attr_groups;
219  ret = iio_trigger_register(st->trig);
220  if (ret)
221  goto out2;
222 
223  ret = request_irq(st->irq, iio_bfin_tmr_trigger_isr,
224  0, st->trig->name, st);
225  if (ret) {
226  dev_err(&pdev->dev,
227  "request IRQ-%d failed", st->irq);
228  goto out4;
229  }
230 
231  config = PWM_OUT | PERIOD_CNT | IRQ_ENA;
232 
233  if (pdata && pdata->output_enable) {
234  unsigned long long val;
235 
236  st->output_enable = true;
237 
238  ret = peripheral_request(st->t->pin, st->trig->name);
239  if (ret)
240  goto out_free_irq;
241 
242  val = (unsigned long long)get_sclk() * pdata->duty_ns;
243  do_div(val, NSEC_PER_SEC);
244  st->duty = val;
245 
252  if (pdata->active_low)
253  config |= PULSE_HI;
254  } else {
255  st->duty = 1;
256  config |= OUT_DIS;
257  }
258 
259  set_gptimer_config(st->t->id, config);
260 
261  dev_info(&pdev->dev, "iio trigger Blackfin TMR%d, IRQ-%d",
262  st->timer_num, st->irq);
263  platform_set_drvdata(pdev, st);
264 
265  return 0;
266 out_free_irq:
267  free_irq(st->irq, st);
268 out4:
270 out2:
271  iio_trigger_put(st->trig);
272 out1:
273  kfree(st);
274 out:
275  return ret;
276 }
277 
278 static int __devexit iio_bfin_tmr_trigger_remove(struct platform_device *pdev)
279 {
280  struct bfin_tmr_state *st = platform_get_drvdata(pdev);
281 
282  disable_gptimers(st->t->bit);
283  if (st->output_enable)
284  peripheral_free(st->t->pin);
285  free_irq(st->irq, st);
287  iio_trigger_put(st->trig);
288  kfree(st);
289 
290  return 0;
291 }
292 
293 static struct platform_driver iio_bfin_tmr_trigger_driver = {
294  .driver = {
295  .name = "iio_bfin_tmr_trigger",
296  .owner = THIS_MODULE,
297  },
298  .probe = iio_bfin_tmr_trigger_probe,
299  .remove = __devexit_p(iio_bfin_tmr_trigger_remove),
300 };
301 
302 module_platform_driver(iio_bfin_tmr_trigger_driver);
303 
304 MODULE_AUTHOR("Michael Hennerich <[email protected]>");
305 MODULE_DESCRIPTION("Blackfin system timer based trigger for the iio subsystem");
306 MODULE_LICENSE("GPL v2");
307 MODULE_ALIAS("platform:iio-trig-bfin-timer");