iio-trig-hrtimer.c (5219B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * The industrial I/O periodic hrtimer trigger driver 4 * 5 * Copyright (C) Intuitive Aerial AB 6 * Written by Marten Svanfeldt, marten@intuitiveaerial.com 7 * Copyright (C) 2012, Analog Devices Inc. 8 * Author: Lars-Peter Clausen <lars@metafoo.de> 9 * Copyright (C) 2015, Intel Corporation 10 */ 11#include <linux/kernel.h> 12#include <linux/slab.h> 13#include <linux/hrtimer.h> 14 15#include <linux/iio/iio.h> 16#include <linux/iio/trigger.h> 17#include <linux/iio/sw_trigger.h> 18 19/* Defined locally, not in time64.h yet. */ 20#define PSEC_PER_SEC 1000000000000LL 21 22/* default sampling frequency - 100Hz */ 23#define HRTIMER_DEFAULT_SAMPLING_FREQUENCY 100 24 25struct iio_hrtimer_info { 26 struct iio_sw_trigger swt; 27 struct hrtimer timer; 28 int sampling_frequency[2]; 29 ktime_t period; 30}; 31 32static const struct config_item_type iio_hrtimer_type = { 33 .ct_owner = THIS_MODULE, 34}; 35 36static 37ssize_t iio_hrtimer_show_sampling_frequency(struct device *dev, 38 struct device_attribute *attr, 39 char *buf) 40{ 41 struct iio_trigger *trig = to_iio_trigger(dev); 42 struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig); 43 44 return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 45 ARRAY_SIZE(info->sampling_frequency), 46 info->sampling_frequency); 47} 48 49static 50ssize_t iio_hrtimer_store_sampling_frequency(struct device *dev, 51 struct device_attribute *attr, 52 const char *buf, size_t len) 53{ 54 struct iio_trigger *trig = to_iio_trigger(dev); 55 struct iio_hrtimer_info *info = iio_trigger_get_drvdata(trig); 56 unsigned long long val; 57 u64 period; 58 int integer, fract, ret; 59 60 ret = iio_str_to_fixpoint(buf, 100, &integer, &fract); 61 if (ret) 62 return ret; 63 if (integer < 0 || fract < 0) 64 return -ERANGE; 65 66 val = fract + 1000ULL * integer; /* mHz */ 67 68 if (!val || val > UINT_MAX) 69 return -EINVAL; 70 71 info->sampling_frequency[0] = integer; /* Hz */ 72 info->sampling_frequency[1] = fract * 1000; /* uHz */ 73 period = PSEC_PER_SEC; 74 do_div(period, val); 75 info->period = period; /* nS */ 76 77 return len; 78} 79 80static DEVICE_ATTR(sampling_frequency, S_IRUGO | S_IWUSR, 81 iio_hrtimer_show_sampling_frequency, 82 iio_hrtimer_store_sampling_frequency); 83 84static struct attribute *iio_hrtimer_attrs[] = { 85 &dev_attr_sampling_frequency.attr, 86 NULL 87}; 88 89static const struct attribute_group iio_hrtimer_attr_group = { 90 .attrs = iio_hrtimer_attrs, 91}; 92 93static const struct attribute_group *iio_hrtimer_attr_groups[] = { 94 &iio_hrtimer_attr_group, 95 NULL 96}; 97 98static enum hrtimer_restart iio_hrtimer_trig_handler(struct hrtimer *timer) 99{ 100 struct iio_hrtimer_info *info; 101 102 info = container_of(timer, struct iio_hrtimer_info, timer); 103 104 hrtimer_forward_now(timer, info->period); 105 iio_trigger_poll(info->swt.trigger); 106 107 return HRTIMER_RESTART; 108} 109 110static int iio_trig_hrtimer_set_state(struct iio_trigger *trig, bool state) 111{ 112 struct iio_hrtimer_info *trig_info; 113 114 trig_info = iio_trigger_get_drvdata(trig); 115 116 if (state) 117 hrtimer_start(&trig_info->timer, trig_info->period, 118 HRTIMER_MODE_REL_HARD); 119 else 120 hrtimer_cancel(&trig_info->timer); 121 122 return 0; 123} 124 125static const struct iio_trigger_ops iio_hrtimer_trigger_ops = { 126 .set_trigger_state = iio_trig_hrtimer_set_state, 127}; 128 129static struct iio_sw_trigger *iio_trig_hrtimer_probe(const char *name) 130{ 131 struct iio_hrtimer_info *trig_info; 132 int ret; 133 134 trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL); 135 if (!trig_info) 136 return ERR_PTR(-ENOMEM); 137 138 trig_info->swt.trigger = iio_trigger_alloc(NULL, "%s", name); 139 if (!trig_info->swt.trigger) { 140 ret = -ENOMEM; 141 goto err_free_trig_info; 142 } 143 144 iio_trigger_set_drvdata(trig_info->swt.trigger, trig_info); 145 trig_info->swt.trigger->ops = &iio_hrtimer_trigger_ops; 146 trig_info->swt.trigger->dev.groups = iio_hrtimer_attr_groups; 147 148 hrtimer_init(&trig_info->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); 149 trig_info->timer.function = iio_hrtimer_trig_handler; 150 151 trig_info->sampling_frequency[0] = HRTIMER_DEFAULT_SAMPLING_FREQUENCY; 152 trig_info->period = NSEC_PER_SEC / trig_info->sampling_frequency[0]; 153 154 ret = iio_trigger_register(trig_info->swt.trigger); 155 if (ret) 156 goto err_free_trigger; 157 158 iio_swt_group_init_type_name(&trig_info->swt, name, &iio_hrtimer_type); 159 return &trig_info->swt; 160err_free_trigger: 161 iio_trigger_free(trig_info->swt.trigger); 162err_free_trig_info: 163 kfree(trig_info); 164 165 return ERR_PTR(ret); 166} 167 168static int iio_trig_hrtimer_remove(struct iio_sw_trigger *swt) 169{ 170 struct iio_hrtimer_info *trig_info; 171 172 trig_info = iio_trigger_get_drvdata(swt->trigger); 173 174 iio_trigger_unregister(swt->trigger); 175 176 /* cancel the timer after unreg to make sure no one rearms it */ 177 hrtimer_cancel(&trig_info->timer); 178 iio_trigger_free(swt->trigger); 179 kfree(trig_info); 180 181 return 0; 182} 183 184static const struct iio_sw_trigger_ops iio_trig_hrtimer_ops = { 185 .probe = iio_trig_hrtimer_probe, 186 .remove = iio_trig_hrtimer_remove, 187}; 188 189static struct iio_sw_trigger_type iio_trig_hrtimer = { 190 .name = "hrtimer", 191 .owner = THIS_MODULE, 192 .ops = &iio_trig_hrtimer_ops, 193}; 194 195module_iio_sw_trigger_driver(iio_trig_hrtimer); 196 197MODULE_AUTHOR("Marten Svanfeldt <marten@intuitiveaerial.com>"); 198MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>"); 199MODULE_DESCRIPTION("Periodic hrtimer trigger for the IIO subsystem"); 200MODULE_LICENSE("GPL v2");