1/* The industrial I/O periodic RTC trigger driver 2 * 3 * Copyright (c) 2008 Jonathan Cameron 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published by 7 * the Free Software Foundation. 8 * 9 * This is a heavily rewritten version of the periodic timer system in 10 * earlier version of industrialio. It supplies the same functionality 11 * but via a trigger rather than a specific periodic timer system. 12 */ 13 14#include <linux/platform_device.h> 15#include <linux/kernel.h> 16#include <linux/module.h> 17#include <linux/slab.h> 18#include <linux/rtc.h> 19#include <linux/iio/iio.h> 20#include <linux/iio/trigger.h> 21 22static LIST_HEAD(iio_prtc_trigger_list); 23static DEFINE_MUTEX(iio_prtc_trigger_list_lock); 24 25struct iio_prtc_trigger_info { 26 struct rtc_device *rtc; 27 unsigned int frequency; 28 struct rtc_task task; 29 bool state; 30}; 31 32static int iio_trig_periodic_rtc_set_state(struct iio_trigger *trig, bool state) 33{ 34 struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig); 35 int ret; 36 37 if (trig_info->frequency == 0 && state) 38 return -EINVAL; 39 dev_dbg(&trig_info->rtc->dev, "trigger frequency is %u\n", 40 trig_info->frequency); 41 ret = rtc_irq_set_state(trig_info->rtc, &trig_info->task, state); 42 if (ret == 0) 43 trig_info->state = state; 44 45 return ret; 46} 47 48static ssize_t iio_trig_periodic_read_freq(struct device *dev, 49 struct device_attribute *attr, 50 char *buf) 51{ 52 struct iio_trigger *trig = to_iio_trigger(dev); 53 struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig); 54 55 return sprintf(buf, "%u\n", trig_info->frequency); 56} 57 58static ssize_t iio_trig_periodic_write_freq(struct device *dev, 59 struct device_attribute *attr, 60 const char *buf, 61 size_t len) 62{ 63 struct iio_trigger *trig = to_iio_trigger(dev); 64 struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig); 65 unsigned int val; 66 int ret; 67 68 ret = kstrtouint(buf, 10, &val); 69 if (ret) 70 goto error_ret; 71 72 if (val > 0) { 73 ret = rtc_irq_set_freq(trig_info->rtc, &trig_info->task, val); 74 if (ret == 0 && trig_info->state && trig_info->frequency == 0) 75 ret = rtc_irq_set_state(trig_info->rtc, 76 &trig_info->task, 1); 77 } else 78 ret = rtc_irq_set_state(trig_info->rtc, &trig_info->task, 0); 79 if (ret) 80 goto error_ret; 81 82 trig_info->frequency = val; 83 84 return len; 85 86error_ret: 87 return ret; 88} 89 90static DEVICE_ATTR(frequency, S_IRUGO | S_IWUSR, 91 iio_trig_periodic_read_freq, 92 iio_trig_periodic_write_freq); 93 94static struct attribute *iio_trig_prtc_attrs[] = { 95 &dev_attr_frequency.attr, 96 NULL, 97}; 98 99static const struct attribute_group iio_trig_prtc_attr_group = { 100 .attrs = iio_trig_prtc_attrs, 101}; 102 103static const struct attribute_group *iio_trig_prtc_attr_groups[] = { 104 &iio_trig_prtc_attr_group, 105 NULL 106}; 107 108static void iio_prtc_trigger_poll(void *private_data) 109{ 110 iio_trigger_poll(private_data); 111} 112 113static const struct iio_trigger_ops iio_prtc_trigger_ops = { 114 .owner = THIS_MODULE, 115 .set_trigger_state = &iio_trig_periodic_rtc_set_state, 116}; 117 118static int iio_trig_periodic_rtc_probe(struct platform_device *dev) 119{ 120 char **pdata = dev->dev.platform_data; 121 struct iio_prtc_trigger_info *trig_info; 122 struct iio_trigger *trig, *trig2; 123 124 int i, ret; 125 126 for (i = 0;; i++) { 127 if (!pdata[i]) 128 break; 129 trig = iio_trigger_alloc("periodic%s", pdata[i]); 130 if (!trig) { 131 ret = -ENOMEM; 132 goto error_free_completed_registrations; 133 } 134 list_add(&trig->alloc_list, &iio_prtc_trigger_list); 135 136 trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL); 137 if (!trig_info) { 138 ret = -ENOMEM; 139 goto error_put_trigger_and_remove_from_list; 140 } 141 iio_trigger_set_drvdata(trig, trig_info); 142 trig->ops = &iio_prtc_trigger_ops; 143 /* RTC access */ 144 trig_info->rtc = rtc_class_open(pdata[i]); 145 if (!trig_info->rtc) { 146 ret = -EINVAL; 147 goto error_free_trig_info; 148 } 149 trig_info->task.func = iio_prtc_trigger_poll; 150 trig_info->task.private_data = trig; 151 ret = rtc_irq_register(trig_info->rtc, &trig_info->task); 152 if (ret) 153 goto error_close_rtc; 154 trig->dev.groups = iio_trig_prtc_attr_groups; 155 ret = iio_trigger_register(trig); 156 if (ret) 157 goto error_unregister_rtc_irq; 158 } 159 return 0; 160error_unregister_rtc_irq: 161 rtc_irq_unregister(trig_info->rtc, &trig_info->task); 162error_close_rtc: 163 rtc_class_close(trig_info->rtc); 164error_free_trig_info: 165 kfree(trig_info); 166error_put_trigger_and_remove_from_list: 167 list_del(&trig->alloc_list); 168 iio_trigger_put(trig); 169error_free_completed_registrations: 170 list_for_each_entry_safe(trig, 171 trig2, 172 &iio_prtc_trigger_list, 173 alloc_list) { 174 trig_info = iio_trigger_get_drvdata(trig); 175 rtc_irq_unregister(trig_info->rtc, &trig_info->task); 176 rtc_class_close(trig_info->rtc); 177 kfree(trig_info); 178 iio_trigger_unregister(trig); 179 } 180 return ret; 181} 182 183static int iio_trig_periodic_rtc_remove(struct platform_device *dev) 184{ 185 struct iio_trigger *trig, *trig2; 186 struct iio_prtc_trigger_info *trig_info; 187 188 mutex_lock(&iio_prtc_trigger_list_lock); 189 list_for_each_entry_safe(trig, 190 trig2, 191 &iio_prtc_trigger_list, 192 alloc_list) { 193 trig_info = iio_trigger_get_drvdata(trig); 194 rtc_irq_unregister(trig_info->rtc, &trig_info->task); 195 rtc_class_close(trig_info->rtc); 196 kfree(trig_info); 197 iio_trigger_unregister(trig); 198 } 199 mutex_unlock(&iio_prtc_trigger_list_lock); 200 return 0; 201} 202 203static struct platform_driver iio_trig_periodic_rtc_driver = { 204 .probe = iio_trig_periodic_rtc_probe, 205 .remove = iio_trig_periodic_rtc_remove, 206 .driver = { 207 .name = "iio_prtc_trigger", 208 }, 209}; 210 211module_platform_driver(iio_trig_periodic_rtc_driver); 212 213MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); 214MODULE_DESCRIPTION("Periodic realtime clock trigger for the iio subsystem"); 215MODULE_LICENSE("GPL v2"); 216