Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

Linux/drivers/staging/iio/trigger/iio-trig-bfin-timer.c

  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] = {
 37         {TIMER0_id,  TIMER0bit,  TIMER_STATUS_TIMIL0,  IRQ_TIMER0, P_TMR0},
 38         {TIMER1_id,  TIMER1bit,  TIMER_STATUS_TIMIL1,  IRQ_TIMER1, P_TMR1},
 39         {TIMER2_id,  TIMER2bit,  TIMER_STATUS_TIMIL2,  IRQ_TIMER2, P_TMR2},
 40 #if (MAX_BLACKFIN_GPTIMERS > 3)
 41         {TIMER3_id,  TIMER3bit,  TIMER_STATUS_TIMIL3,  IRQ_TIMER3, P_TMR3},
 42         {TIMER4_id,  TIMER4bit,  TIMER_STATUS_TIMIL4,  IRQ_TIMER4, P_TMR4},
 43         {TIMER5_id,  TIMER5bit,  TIMER_STATUS_TIMIL5,  IRQ_TIMER5, P_TMR5},
 44         {TIMER6_id,  TIMER6bit,  TIMER_STATUS_TIMIL6,  IRQ_TIMER6, P_TMR6},
 45         {TIMER7_id,  TIMER7bit,  TIMER_STATUS_TIMIL7,  IRQ_TIMER7, P_TMR7},
 46 #endif
 47 #if (MAX_BLACKFIN_GPTIMERS > 8)
 48         {TIMER8_id,  TIMER8bit,  TIMER_STATUS_TIMIL8,  IRQ_TIMER8, P_TMR8},
 49         {TIMER9_id,  TIMER9bit,  TIMER_STATUS_TIMIL9,  IRQ_TIMER9, P_TMR9},
 50         {TIMER10_id, TIMER10bit, TIMER_STATUS_TIMIL10, IRQ_TIMER10, P_TMR10},
 51 #if (MAX_BLACKFIN_GPTIMERS > 11)
 52         {TIMER11_id, TIMER11bit, TIMER_STATUS_TIMIL11, IRQ_TIMER11, P_TMR11},
 53 #endif
 54 #endif
 55 };
 56 
 57 struct bfin_tmr_state {
 58         struct iio_trigger *trig;
 59         struct bfin_timer *t;
 60         unsigned timer_num;
 61         bool output_enable;
 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 = iio_trigger_get_drvdata(trig);
 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 = iio_trigger_get_drvdata(trig);
 86         unsigned int val;
 87         bool enabled;
 88         int ret;
 89 
 90         ret = kstrtouint(buf, 10, &val);
 91         if (ret)
 92                 return ret;
 93 
 94         if (val > 100000)
 95                 return -EINVAL;
 96 
 97         enabled = get_enabled_gptimers() & st->t->bit;
 98 
 99         if (enabled)
100                 disable_gptimers(st->t->bit);
101 
102         if (val == 0)
103                 return count;
104 
105         val = get_sclk() / val;
106         if (val <= 4 || val <= st->duty)
107                 return -EINVAL;
108 
109         set_gptimer_period(st->t->id, val);
110         set_gptimer_pwidth(st->t->id, val - st->duty);
111 
112         if (enabled)
113                 enable_gptimers(st->t->bit);
114 
115         return count;
116 }
117 
118 static ssize_t iio_bfin_tmr_frequency_show(struct device *dev,
119                                  struct device_attribute *attr,
120                                  char *buf)
121 {
122         struct iio_trigger *trig = to_iio_trigger(dev);
123         struct bfin_tmr_state *st = iio_trigger_get_drvdata(trig);
124         unsigned int period = get_gptimer_period(st->t->id);
125         unsigned long val;
126 
127         if (period == 0)
128                 val = 0;
129         else
130                 val = get_sclk() / get_gptimer_period(st->t->id);
131 
132         return sprintf(buf, "%lu\n", val);
133 }
134 
135 static DEVICE_ATTR(frequency, S_IRUGO | S_IWUSR, iio_bfin_tmr_frequency_show,
136                    iio_bfin_tmr_frequency_store);
137 
138 static struct attribute *iio_bfin_tmr_trigger_attrs[] = {
139         &dev_attr_frequency.attr,
140         NULL,
141 };
142 
143 static const struct attribute_group iio_bfin_tmr_trigger_attr_group = {
144         .attrs = iio_bfin_tmr_trigger_attrs,
145 };
146 
147 static const struct attribute_group *iio_bfin_tmr_trigger_attr_groups[] = {
148         &iio_bfin_tmr_trigger_attr_group,
149         NULL
150 };
151 
152 static irqreturn_t iio_bfin_tmr_trigger_isr(int irq, void *devid)
153 {
154         struct bfin_tmr_state *st = devid;
155 
156         clear_gptimer_intr(st->t->id);
157         iio_trigger_poll(st->trig, 0);
158 
159         return IRQ_HANDLED;
160 }
161 
162 static int iio_bfin_tmr_get_number(int irq)
163 {
164         int i;
165 
166         for (i = 0; i < MAX_BLACKFIN_GPTIMERS; i++)
167                 if (iio_bfin_timer_code[i].irq == irq)
168                         return i;
169 
170         return -ENODEV;
171 }
172 
173 static const struct iio_trigger_ops iio_bfin_tmr_trigger_ops = {
174         .owner = THIS_MODULE,
175         .set_trigger_state = iio_bfin_tmr_set_state,
176 };
177 
178 static int iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
179 {
180         struct iio_bfin_timer_trigger_pdata *pdata = pdev->dev.platform_data;
181         struct bfin_tmr_state *st;
182         unsigned int config;
183         int ret;
184 
185         st = kzalloc(sizeof(*st), GFP_KERNEL);
186         if (st == NULL) {
187                 ret = -ENOMEM;
188                 goto out;
189         }
190 
191         st->irq = platform_get_irq(pdev, 0);
192         if (!st->irq) {
193                 dev_err(&pdev->dev, "No IRQs specified");
194                 ret = -ENODEV;
195                 goto out1;
196         }
197 
198         ret = iio_bfin_tmr_get_number(st->irq);
199         if (ret < 0)
200                 goto out1;
201 
202         st->timer_num = ret;
203         st->t = &iio_bfin_timer_code[st->timer_num];
204 
205         st->trig = iio_trigger_alloc("bfintmr%d", st->timer_num);
206         if (!st->trig) {
207                 ret = -ENOMEM;
208                 goto out1;
209         }
210 
211         st->trig->ops = &iio_bfin_tmr_trigger_ops;
212         st->trig->dev.groups = iio_bfin_tmr_trigger_attr_groups;
213         iio_trigger_set_drvdata(st->trig, st);
214         ret = iio_trigger_register(st->trig);
215         if (ret)
216                 goto out2;
217 
218         ret = request_irq(st->irq, iio_bfin_tmr_trigger_isr,
219                           0, st->trig->name, st);
220         if (ret) {
221                 dev_err(&pdev->dev,
222                         "request IRQ-%d failed", st->irq);
223                 goto out4;
224         }
225 
226         config = PWM_OUT | PERIOD_CNT | IRQ_ENA;
227 
228         if (pdata && pdata->output_enable) {
229                 unsigned long long val;
230 
231                 st->output_enable = true;
232 
233                 ret = peripheral_request(st->t->pin, st->trig->name);
234                 if (ret)
235                         goto out_free_irq;
236 
237                 val = (unsigned long long)get_sclk() * pdata->duty_ns;
238                 do_div(val, NSEC_PER_SEC);
239                 st->duty = val;
240 
241                 /**
242                  * The interrupt will be generated at the end of the period,
243                  * since we want the interrupt to be generated at end of the
244                  * pulse we invert both polarity and duty cycle, so that the
245                  * pulse will be generated directly before the interrupt.
246                  */
247                 if (pdata->active_low)
248                         config |= PULSE_HI;
249         } else {
250                 st->duty = 1;
251                 config |= OUT_DIS;
252         }
253 
254         set_gptimer_config(st->t->id, config);
255 
256         dev_info(&pdev->dev, "iio trigger Blackfin TMR%d, IRQ-%d",
257                  st->timer_num, st->irq);
258         platform_set_drvdata(pdev, st);
259 
260         return 0;
261 out_free_irq:
262         free_irq(st->irq, st);
263 out4:
264         iio_trigger_unregister(st->trig);
265 out2:
266         iio_trigger_put(st->trig);
267 out1:
268         kfree(st);
269 out:
270         return ret;
271 }
272 
273 static int iio_bfin_tmr_trigger_remove(struct platform_device *pdev)
274 {
275         struct bfin_tmr_state *st = platform_get_drvdata(pdev);
276 
277         disable_gptimers(st->t->bit);
278         if (st->output_enable)
279                 peripheral_free(st->t->pin);
280         free_irq(st->irq, st);
281         iio_trigger_unregister(st->trig);
282         iio_trigger_put(st->trig);
283         kfree(st);
284 
285         return 0;
286 }
287 
288 static struct platform_driver iio_bfin_tmr_trigger_driver = {
289         .driver = {
290                 .name = "iio_bfin_tmr_trigger",
291                 .owner = THIS_MODULE,
292         },
293         .probe = iio_bfin_tmr_trigger_probe,
294         .remove = iio_bfin_tmr_trigger_remove,
295 };
296 
297 module_platform_driver(iio_bfin_tmr_trigger_driver);
298 
299 MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
300 MODULE_DESCRIPTION("Blackfin system timer based trigger for the iio subsystem");
301 MODULE_LICENSE("GPL v2");
302 MODULE_ALIAS("platform:iio-trig-bfin-timer");
303 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us