1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /* The industrial I/O core
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (c) 2008 Jonathan Cameron
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Based on elements of hwmon and input subsystems.
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #define pr_fmt(fmt) "iio-core: " fmt
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/idr.h>
14*4882a593Smuzhiyun #include <linux/kdev_t.h>
15*4882a593Smuzhiyun #include <linux/err.h>
16*4882a593Smuzhiyun #include <linux/device.h>
17*4882a593Smuzhiyun #include <linux/fs.h>
18*4882a593Smuzhiyun #include <linux/poll.h>
19*4882a593Smuzhiyun #include <linux/property.h>
20*4882a593Smuzhiyun #include <linux/sched.h>
21*4882a593Smuzhiyun #include <linux/wait.h>
22*4882a593Smuzhiyun #include <linux/cdev.h>
23*4882a593Smuzhiyun #include <linux/slab.h>
24*4882a593Smuzhiyun #include <linux/anon_inodes.h>
25*4882a593Smuzhiyun #include <linux/debugfs.h>
26*4882a593Smuzhiyun #include <linux/mutex.h>
27*4882a593Smuzhiyun #include <linux/iio/iio.h>
28*4882a593Smuzhiyun #include <linux/iio/iio-opaque.h>
29*4882a593Smuzhiyun #include "iio_core.h"
30*4882a593Smuzhiyun #include "iio_core_trigger.h"
31*4882a593Smuzhiyun #include <linux/iio/sysfs.h>
32*4882a593Smuzhiyun #include <linux/iio/events.h>
33*4882a593Smuzhiyun #include <linux/iio/buffer.h>
34*4882a593Smuzhiyun #include <linux/iio/buffer_impl.h>
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun /* IDA to assign each registered device a unique id */
37*4882a593Smuzhiyun static DEFINE_IDA(iio_ida);
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun static dev_t iio_devt;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #define IIO_DEV_MAX 256
42*4882a593Smuzhiyun struct bus_type iio_bus_type = {
43*4882a593Smuzhiyun .name = "iio",
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun EXPORT_SYMBOL(iio_bus_type);
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun static struct dentry *iio_debugfs_dentry;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun static const char * const iio_direction[] = {
50*4882a593Smuzhiyun [0] = "in",
51*4882a593Smuzhiyun [1] = "out",
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun static const char * const iio_chan_type_name_spec[] = {
55*4882a593Smuzhiyun [IIO_VOLTAGE] = "voltage",
56*4882a593Smuzhiyun [IIO_CURRENT] = "current",
57*4882a593Smuzhiyun [IIO_POWER] = "power",
58*4882a593Smuzhiyun [IIO_ACCEL] = "accel",
59*4882a593Smuzhiyun [IIO_ANGL_VEL] = "anglvel",
60*4882a593Smuzhiyun [IIO_MAGN] = "magn",
61*4882a593Smuzhiyun [IIO_LIGHT] = "illuminance",
62*4882a593Smuzhiyun [IIO_INTENSITY] = "intensity",
63*4882a593Smuzhiyun [IIO_PROXIMITY] = "proximity",
64*4882a593Smuzhiyun [IIO_TEMP] = "temp",
65*4882a593Smuzhiyun [IIO_INCLI] = "incli",
66*4882a593Smuzhiyun [IIO_ROT] = "rot",
67*4882a593Smuzhiyun [IIO_ANGL] = "angl",
68*4882a593Smuzhiyun [IIO_TIMESTAMP] = "timestamp",
69*4882a593Smuzhiyun [IIO_CAPACITANCE] = "capacitance",
70*4882a593Smuzhiyun [IIO_ALTVOLTAGE] = "altvoltage",
71*4882a593Smuzhiyun [IIO_CCT] = "cct",
72*4882a593Smuzhiyun [IIO_PRESSURE] = "pressure",
73*4882a593Smuzhiyun [IIO_HUMIDITYRELATIVE] = "humidityrelative",
74*4882a593Smuzhiyun [IIO_ACTIVITY] = "activity",
75*4882a593Smuzhiyun [IIO_STEPS] = "steps",
76*4882a593Smuzhiyun [IIO_ENERGY] = "energy",
77*4882a593Smuzhiyun [IIO_DISTANCE] = "distance",
78*4882a593Smuzhiyun [IIO_VELOCITY] = "velocity",
79*4882a593Smuzhiyun [IIO_CONCENTRATION] = "concentration",
80*4882a593Smuzhiyun [IIO_RESISTANCE] = "resistance",
81*4882a593Smuzhiyun [IIO_PH] = "ph",
82*4882a593Smuzhiyun [IIO_UVINDEX] = "uvindex",
83*4882a593Smuzhiyun [IIO_ELECTRICALCONDUCTIVITY] = "electricalconductivity",
84*4882a593Smuzhiyun [IIO_COUNT] = "count",
85*4882a593Smuzhiyun [IIO_INDEX] = "index",
86*4882a593Smuzhiyun [IIO_GRAVITY] = "gravity",
87*4882a593Smuzhiyun [IIO_POSITIONRELATIVE] = "positionrelative",
88*4882a593Smuzhiyun [IIO_PHASE] = "phase",
89*4882a593Smuzhiyun [IIO_MASSCONCENTRATION] = "massconcentration",
90*4882a593Smuzhiyun #ifdef CONFIG_NO_GKI
91*4882a593Smuzhiyun [IIO_SIGN_MOTION] = "signmotion",
92*4882a593Smuzhiyun [IIO_STEP_DETECTOR] = "stepdetector",
93*4882a593Smuzhiyun [IIO_STEP_COUNTER] = "stepcounter",
94*4882a593Smuzhiyun [IIO_TILT] = "tilt",
95*4882a593Smuzhiyun [IIO_TAP] = "tap",
96*4882a593Smuzhiyun [IIO_TAP_TAP] = "taptap",
97*4882a593Smuzhiyun [IIO_WRIST_TILT_GESTURE] = "wristtiltgesture",
98*4882a593Smuzhiyun [IIO_GESTURE] = "gesture",
99*4882a593Smuzhiyun #endif
100*4882a593Smuzhiyun };
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun static const char * const iio_modifier_names[] = {
103*4882a593Smuzhiyun [IIO_MOD_X] = "x",
104*4882a593Smuzhiyun [IIO_MOD_Y] = "y",
105*4882a593Smuzhiyun [IIO_MOD_Z] = "z",
106*4882a593Smuzhiyun [IIO_MOD_X_AND_Y] = "x&y",
107*4882a593Smuzhiyun [IIO_MOD_X_AND_Z] = "x&z",
108*4882a593Smuzhiyun [IIO_MOD_Y_AND_Z] = "y&z",
109*4882a593Smuzhiyun [IIO_MOD_X_AND_Y_AND_Z] = "x&y&z",
110*4882a593Smuzhiyun [IIO_MOD_X_OR_Y] = "x|y",
111*4882a593Smuzhiyun [IIO_MOD_X_OR_Z] = "x|z",
112*4882a593Smuzhiyun [IIO_MOD_Y_OR_Z] = "y|z",
113*4882a593Smuzhiyun [IIO_MOD_X_OR_Y_OR_Z] = "x|y|z",
114*4882a593Smuzhiyun [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)",
115*4882a593Smuzhiyun [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2",
116*4882a593Smuzhiyun [IIO_MOD_LIGHT_BOTH] = "both",
117*4882a593Smuzhiyun [IIO_MOD_LIGHT_IR] = "ir",
118*4882a593Smuzhiyun [IIO_MOD_LIGHT_CLEAR] = "clear",
119*4882a593Smuzhiyun [IIO_MOD_LIGHT_RED] = "red",
120*4882a593Smuzhiyun [IIO_MOD_LIGHT_GREEN] = "green",
121*4882a593Smuzhiyun [IIO_MOD_LIGHT_BLUE] = "blue",
122*4882a593Smuzhiyun [IIO_MOD_LIGHT_UV] = "uv",
123*4882a593Smuzhiyun [IIO_MOD_LIGHT_DUV] = "duv",
124*4882a593Smuzhiyun [IIO_MOD_QUATERNION] = "quaternion",
125*4882a593Smuzhiyun [IIO_MOD_TEMP_AMBIENT] = "ambient",
126*4882a593Smuzhiyun [IIO_MOD_TEMP_OBJECT] = "object",
127*4882a593Smuzhiyun [IIO_MOD_NORTH_MAGN] = "from_north_magnetic",
128*4882a593Smuzhiyun [IIO_MOD_NORTH_TRUE] = "from_north_true",
129*4882a593Smuzhiyun [IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp",
130*4882a593Smuzhiyun [IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp",
131*4882a593Smuzhiyun [IIO_MOD_RUNNING] = "running",
132*4882a593Smuzhiyun [IIO_MOD_JOGGING] = "jogging",
133*4882a593Smuzhiyun [IIO_MOD_WALKING] = "walking",
134*4882a593Smuzhiyun [IIO_MOD_STILL] = "still",
135*4882a593Smuzhiyun [IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
136*4882a593Smuzhiyun [IIO_MOD_I] = "i",
137*4882a593Smuzhiyun [IIO_MOD_Q] = "q",
138*4882a593Smuzhiyun [IIO_MOD_CO2] = "co2",
139*4882a593Smuzhiyun [IIO_MOD_VOC] = "voc",
140*4882a593Smuzhiyun [IIO_MOD_PM1] = "pm1",
141*4882a593Smuzhiyun [IIO_MOD_PM2P5] = "pm2p5",
142*4882a593Smuzhiyun [IIO_MOD_PM4] = "pm4",
143*4882a593Smuzhiyun [IIO_MOD_PM10] = "pm10",
144*4882a593Smuzhiyun [IIO_MOD_ETHANOL] = "ethanol",
145*4882a593Smuzhiyun [IIO_MOD_H2] = "h2",
146*4882a593Smuzhiyun [IIO_MOD_O2] = "o2",
147*4882a593Smuzhiyun };
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun /* relies on pairs of these shared then separate */
150*4882a593Smuzhiyun static const char * const iio_chan_info_postfix[] = {
151*4882a593Smuzhiyun [IIO_CHAN_INFO_RAW] = "raw",
152*4882a593Smuzhiyun [IIO_CHAN_INFO_PROCESSED] = "input",
153*4882a593Smuzhiyun [IIO_CHAN_INFO_SCALE] = "scale",
154*4882a593Smuzhiyun [IIO_CHAN_INFO_OFFSET] = "offset",
155*4882a593Smuzhiyun [IIO_CHAN_INFO_CALIBSCALE] = "calibscale",
156*4882a593Smuzhiyun [IIO_CHAN_INFO_CALIBBIAS] = "calibbias",
157*4882a593Smuzhiyun [IIO_CHAN_INFO_PEAK] = "peak_raw",
158*4882a593Smuzhiyun [IIO_CHAN_INFO_PEAK_SCALE] = "peak_scale",
159*4882a593Smuzhiyun [IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW] = "quadrature_correction_raw",
160*4882a593Smuzhiyun [IIO_CHAN_INFO_AVERAGE_RAW] = "mean_raw",
161*4882a593Smuzhiyun [IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY]
162*4882a593Smuzhiyun = "filter_low_pass_3db_frequency",
163*4882a593Smuzhiyun [IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY]
164*4882a593Smuzhiyun = "filter_high_pass_3db_frequency",
165*4882a593Smuzhiyun [IIO_CHAN_INFO_SAMP_FREQ] = "sampling_frequency",
166*4882a593Smuzhiyun [IIO_CHAN_INFO_FREQUENCY] = "frequency",
167*4882a593Smuzhiyun [IIO_CHAN_INFO_PHASE] = "phase",
168*4882a593Smuzhiyun [IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain",
169*4882a593Smuzhiyun [IIO_CHAN_INFO_HYSTERESIS] = "hysteresis",
170*4882a593Smuzhiyun [IIO_CHAN_INFO_INT_TIME] = "integration_time",
171*4882a593Smuzhiyun [IIO_CHAN_INFO_ENABLE] = "en",
172*4882a593Smuzhiyun [IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight",
173*4882a593Smuzhiyun [IIO_CHAN_INFO_CALIBWEIGHT] = "calibweight",
174*4882a593Smuzhiyun [IIO_CHAN_INFO_DEBOUNCE_COUNT] = "debounce_count",
175*4882a593Smuzhiyun [IIO_CHAN_INFO_DEBOUNCE_TIME] = "debounce_time",
176*4882a593Smuzhiyun [IIO_CHAN_INFO_CALIBEMISSIVITY] = "calibemissivity",
177*4882a593Smuzhiyun [IIO_CHAN_INFO_OVERSAMPLING_RATIO] = "oversampling_ratio",
178*4882a593Smuzhiyun [IIO_CHAN_INFO_THERMOCOUPLE_TYPE] = "thermocouple_type",
179*4882a593Smuzhiyun [IIO_CHAN_INFO_CALIBAMBIENT] = "calibambient",
180*4882a593Smuzhiyun };
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun #if defined(CONFIG_DEBUG_FS)
183*4882a593Smuzhiyun /*
184*4882a593Smuzhiyun * There's also a CONFIG_DEBUG_FS guard in include/linux/iio/iio.h for
185*4882a593Smuzhiyun * iio_get_debugfs_dentry() to make it inline if CONFIG_DEBUG_FS is undefined
186*4882a593Smuzhiyun */
iio_get_debugfs_dentry(struct iio_dev * indio_dev)187*4882a593Smuzhiyun struct dentry *iio_get_debugfs_dentry(struct iio_dev *indio_dev)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
190*4882a593Smuzhiyun return iio_dev_opaque->debugfs_dentry;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(iio_get_debugfs_dentry);
193*4882a593Smuzhiyun #endif
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun /**
196*4882a593Smuzhiyun * iio_find_channel_from_si() - get channel from its scan index
197*4882a593Smuzhiyun * @indio_dev: device
198*4882a593Smuzhiyun * @si: scan index to match
199*4882a593Smuzhiyun */
200*4882a593Smuzhiyun const struct iio_chan_spec
iio_find_channel_from_si(struct iio_dev * indio_dev,int si)201*4882a593Smuzhiyun *iio_find_channel_from_si(struct iio_dev *indio_dev, int si)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun int i;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun for (i = 0; i < indio_dev->num_channels; i++)
206*4882a593Smuzhiyun if (indio_dev->channels[i].scan_index == si)
207*4882a593Smuzhiyun return &indio_dev->channels[i];
208*4882a593Smuzhiyun return NULL;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun /* This turns up an awful lot */
iio_read_const_attr(struct device * dev,struct device_attribute * attr,char * buf)212*4882a593Smuzhiyun ssize_t iio_read_const_attr(struct device *dev,
213*4882a593Smuzhiyun struct device_attribute *attr,
214*4882a593Smuzhiyun char *buf)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun return sprintf(buf, "%s\n", to_iio_const_attr(attr)->string);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun EXPORT_SYMBOL(iio_read_const_attr);
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun /**
221*4882a593Smuzhiyun * iio_device_set_clock() - Set current timestamping clock for the device
222*4882a593Smuzhiyun * @indio_dev: IIO device structure containing the device
223*4882a593Smuzhiyun * @clock_id: timestamping clock posix identifier to set.
224*4882a593Smuzhiyun */
iio_device_set_clock(struct iio_dev * indio_dev,clockid_t clock_id)225*4882a593Smuzhiyun int iio_device_set_clock(struct iio_dev *indio_dev, clockid_t clock_id)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun int ret;
228*4882a593Smuzhiyun struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
229*4882a593Smuzhiyun const struct iio_event_interface *ev_int = iio_dev_opaque->event_interface;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun ret = mutex_lock_interruptible(&indio_dev->mlock);
232*4882a593Smuzhiyun if (ret)
233*4882a593Smuzhiyun return ret;
234*4882a593Smuzhiyun if ((ev_int && iio_event_enabled(ev_int)) ||
235*4882a593Smuzhiyun iio_buffer_enabled(indio_dev)) {
236*4882a593Smuzhiyun mutex_unlock(&indio_dev->mlock);
237*4882a593Smuzhiyun return -EBUSY;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun indio_dev->clock_id = clock_id;
240*4882a593Smuzhiyun mutex_unlock(&indio_dev->mlock);
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun return 0;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun EXPORT_SYMBOL(iio_device_set_clock);
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /**
247*4882a593Smuzhiyun * iio_get_time_ns() - utility function to get a time stamp for events etc
248*4882a593Smuzhiyun * @indio_dev: device
249*4882a593Smuzhiyun */
iio_get_time_ns(const struct iio_dev * indio_dev)250*4882a593Smuzhiyun s64 iio_get_time_ns(const struct iio_dev *indio_dev)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun struct timespec64 tp;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun switch (iio_device_get_clock(indio_dev)) {
255*4882a593Smuzhiyun case CLOCK_REALTIME:
256*4882a593Smuzhiyun return ktime_get_real_ns();
257*4882a593Smuzhiyun case CLOCK_MONOTONIC:
258*4882a593Smuzhiyun return ktime_get_ns();
259*4882a593Smuzhiyun case CLOCK_MONOTONIC_RAW:
260*4882a593Smuzhiyun return ktime_get_raw_ns();
261*4882a593Smuzhiyun case CLOCK_REALTIME_COARSE:
262*4882a593Smuzhiyun return ktime_to_ns(ktime_get_coarse_real());
263*4882a593Smuzhiyun case CLOCK_MONOTONIC_COARSE:
264*4882a593Smuzhiyun ktime_get_coarse_ts64(&tp);
265*4882a593Smuzhiyun return timespec64_to_ns(&tp);
266*4882a593Smuzhiyun case CLOCK_BOOTTIME:
267*4882a593Smuzhiyun return ktime_get_boottime_ns();
268*4882a593Smuzhiyun case CLOCK_TAI:
269*4882a593Smuzhiyun return ktime_get_clocktai_ns();
270*4882a593Smuzhiyun default:
271*4882a593Smuzhiyun BUG();
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun EXPORT_SYMBOL(iio_get_time_ns);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /**
277*4882a593Smuzhiyun * iio_get_time_res() - utility function to get time stamp clock resolution in
278*4882a593Smuzhiyun * nano seconds.
279*4882a593Smuzhiyun * @indio_dev: device
280*4882a593Smuzhiyun */
iio_get_time_res(const struct iio_dev * indio_dev)281*4882a593Smuzhiyun unsigned int iio_get_time_res(const struct iio_dev *indio_dev)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun switch (iio_device_get_clock(indio_dev)) {
284*4882a593Smuzhiyun case CLOCK_REALTIME:
285*4882a593Smuzhiyun case CLOCK_MONOTONIC:
286*4882a593Smuzhiyun case CLOCK_MONOTONIC_RAW:
287*4882a593Smuzhiyun case CLOCK_BOOTTIME:
288*4882a593Smuzhiyun case CLOCK_TAI:
289*4882a593Smuzhiyun return hrtimer_resolution;
290*4882a593Smuzhiyun case CLOCK_REALTIME_COARSE:
291*4882a593Smuzhiyun case CLOCK_MONOTONIC_COARSE:
292*4882a593Smuzhiyun return LOW_RES_NSEC;
293*4882a593Smuzhiyun default:
294*4882a593Smuzhiyun BUG();
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun EXPORT_SYMBOL(iio_get_time_res);
298*4882a593Smuzhiyun
iio_init(void)299*4882a593Smuzhiyun static int __init iio_init(void)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun int ret;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun /* Register sysfs bus */
304*4882a593Smuzhiyun ret = bus_register(&iio_bus_type);
305*4882a593Smuzhiyun if (ret < 0) {
306*4882a593Smuzhiyun pr_err("could not register bus type\n");
307*4882a593Smuzhiyun goto error_nothing;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun ret = alloc_chrdev_region(&iio_devt, 0, IIO_DEV_MAX, "iio");
311*4882a593Smuzhiyun if (ret < 0) {
312*4882a593Smuzhiyun pr_err("failed to allocate char dev region\n");
313*4882a593Smuzhiyun goto error_unregister_bus_type;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun iio_debugfs_dentry = debugfs_create_dir("iio", NULL);
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun return 0;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun error_unregister_bus_type:
321*4882a593Smuzhiyun bus_unregister(&iio_bus_type);
322*4882a593Smuzhiyun error_nothing:
323*4882a593Smuzhiyun return ret;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
iio_exit(void)326*4882a593Smuzhiyun static void __exit iio_exit(void)
327*4882a593Smuzhiyun {
328*4882a593Smuzhiyun if (iio_devt)
329*4882a593Smuzhiyun unregister_chrdev_region(iio_devt, IIO_DEV_MAX);
330*4882a593Smuzhiyun bus_unregister(&iio_bus_type);
331*4882a593Smuzhiyun debugfs_remove(iio_debugfs_dentry);
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun #if defined(CONFIG_DEBUG_FS)
iio_debugfs_read_reg(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)335*4882a593Smuzhiyun static ssize_t iio_debugfs_read_reg(struct file *file, char __user *userbuf,
336*4882a593Smuzhiyun size_t count, loff_t *ppos)
337*4882a593Smuzhiyun {
338*4882a593Smuzhiyun struct iio_dev *indio_dev = file->private_data;
339*4882a593Smuzhiyun struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
340*4882a593Smuzhiyun unsigned val = 0;
341*4882a593Smuzhiyun int ret;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun if (*ppos > 0)
344*4882a593Smuzhiyun return simple_read_from_buffer(userbuf, count, ppos,
345*4882a593Smuzhiyun iio_dev_opaque->read_buf,
346*4882a593Smuzhiyun iio_dev_opaque->read_buf_len);
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun ret = indio_dev->info->debugfs_reg_access(indio_dev,
349*4882a593Smuzhiyun iio_dev_opaque->cached_reg_addr,
350*4882a593Smuzhiyun 0, &val);
351*4882a593Smuzhiyun if (ret) {
352*4882a593Smuzhiyun dev_err(indio_dev->dev.parent, "%s: read failed\n", __func__);
353*4882a593Smuzhiyun return ret;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun iio_dev_opaque->read_buf_len = snprintf(iio_dev_opaque->read_buf,
357*4882a593Smuzhiyun sizeof(iio_dev_opaque->read_buf),
358*4882a593Smuzhiyun "0x%X\n", val);
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun return simple_read_from_buffer(userbuf, count, ppos,
361*4882a593Smuzhiyun iio_dev_opaque->read_buf,
362*4882a593Smuzhiyun iio_dev_opaque->read_buf_len);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
iio_debugfs_write_reg(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)365*4882a593Smuzhiyun static ssize_t iio_debugfs_write_reg(struct file *file,
366*4882a593Smuzhiyun const char __user *userbuf, size_t count, loff_t *ppos)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun struct iio_dev *indio_dev = file->private_data;
369*4882a593Smuzhiyun struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
370*4882a593Smuzhiyun unsigned reg, val;
371*4882a593Smuzhiyun char buf[80];
372*4882a593Smuzhiyun int ret;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun count = min_t(size_t, count, (sizeof(buf)-1));
375*4882a593Smuzhiyun if (copy_from_user(buf, userbuf, count))
376*4882a593Smuzhiyun return -EFAULT;
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun buf[count] = 0;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun ret = sscanf(buf, "%i %i", ®, &val);
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun switch (ret) {
383*4882a593Smuzhiyun case 1:
384*4882a593Smuzhiyun iio_dev_opaque->cached_reg_addr = reg;
385*4882a593Smuzhiyun break;
386*4882a593Smuzhiyun case 2:
387*4882a593Smuzhiyun iio_dev_opaque->cached_reg_addr = reg;
388*4882a593Smuzhiyun ret = indio_dev->info->debugfs_reg_access(indio_dev, reg,
389*4882a593Smuzhiyun val, NULL);
390*4882a593Smuzhiyun if (ret) {
391*4882a593Smuzhiyun dev_err(indio_dev->dev.parent, "%s: write failed\n",
392*4882a593Smuzhiyun __func__);
393*4882a593Smuzhiyun return ret;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun break;
396*4882a593Smuzhiyun default:
397*4882a593Smuzhiyun return -EINVAL;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun return count;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun static const struct file_operations iio_debugfs_reg_fops = {
404*4882a593Smuzhiyun .open = simple_open,
405*4882a593Smuzhiyun .read = iio_debugfs_read_reg,
406*4882a593Smuzhiyun .write = iio_debugfs_write_reg,
407*4882a593Smuzhiyun };
408*4882a593Smuzhiyun
iio_device_unregister_debugfs(struct iio_dev * indio_dev)409*4882a593Smuzhiyun static void iio_device_unregister_debugfs(struct iio_dev *indio_dev)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
412*4882a593Smuzhiyun debugfs_remove_recursive(iio_dev_opaque->debugfs_dentry);
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
iio_device_register_debugfs(struct iio_dev * indio_dev)415*4882a593Smuzhiyun static void iio_device_register_debugfs(struct iio_dev *indio_dev)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun struct iio_dev_opaque *iio_dev_opaque;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun if (indio_dev->info->debugfs_reg_access == NULL)
420*4882a593Smuzhiyun return;
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun if (!iio_debugfs_dentry)
423*4882a593Smuzhiyun return;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun iio_dev_opaque = to_iio_dev_opaque(indio_dev);
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun iio_dev_opaque->debugfs_dentry =
428*4882a593Smuzhiyun debugfs_create_dir(dev_name(&indio_dev->dev),
429*4882a593Smuzhiyun iio_debugfs_dentry);
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun debugfs_create_file("direct_reg_access", 0644,
432*4882a593Smuzhiyun iio_dev_opaque->debugfs_dentry, indio_dev,
433*4882a593Smuzhiyun &iio_debugfs_reg_fops);
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun #else
iio_device_register_debugfs(struct iio_dev * indio_dev)436*4882a593Smuzhiyun static void iio_device_register_debugfs(struct iio_dev *indio_dev)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
iio_device_unregister_debugfs(struct iio_dev * indio_dev)440*4882a593Smuzhiyun static void iio_device_unregister_debugfs(struct iio_dev *indio_dev)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun #endif /* CONFIG_DEBUG_FS */
444*4882a593Smuzhiyun
iio_read_channel_ext_info(struct device * dev,struct device_attribute * attr,char * buf)445*4882a593Smuzhiyun static ssize_t iio_read_channel_ext_info(struct device *dev,
446*4882a593Smuzhiyun struct device_attribute *attr,
447*4882a593Smuzhiyun char *buf)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun struct iio_dev *indio_dev = dev_to_iio_dev(dev);
450*4882a593Smuzhiyun struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
451*4882a593Smuzhiyun const struct iio_chan_spec_ext_info *ext_info;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun ext_info = &this_attr->c->ext_info[this_attr->address];
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun return ext_info->read(indio_dev, ext_info->private, this_attr->c, buf);
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
iio_write_channel_ext_info(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)458*4882a593Smuzhiyun static ssize_t iio_write_channel_ext_info(struct device *dev,
459*4882a593Smuzhiyun struct device_attribute *attr,
460*4882a593Smuzhiyun const char *buf,
461*4882a593Smuzhiyun size_t len)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun struct iio_dev *indio_dev = dev_to_iio_dev(dev);
464*4882a593Smuzhiyun struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
465*4882a593Smuzhiyun const struct iio_chan_spec_ext_info *ext_info;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun ext_info = &this_attr->c->ext_info[this_attr->address];
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun return ext_info->write(indio_dev, ext_info->private,
470*4882a593Smuzhiyun this_attr->c, buf, len);
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
iio_enum_available_read(struct iio_dev * indio_dev,uintptr_t priv,const struct iio_chan_spec * chan,char * buf)473*4882a593Smuzhiyun ssize_t iio_enum_available_read(struct iio_dev *indio_dev,
474*4882a593Smuzhiyun uintptr_t priv, const struct iio_chan_spec *chan, char *buf)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun const struct iio_enum *e = (const struct iio_enum *)priv;
477*4882a593Smuzhiyun unsigned int i;
478*4882a593Smuzhiyun size_t len = 0;
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun if (!e->num_items)
481*4882a593Smuzhiyun return 0;
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun for (i = 0; i < e->num_items; ++i)
484*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len, "%s ", e->items[i]);
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun /* replace last space with a newline */
487*4882a593Smuzhiyun buf[len - 1] = '\n';
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun return len;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(iio_enum_available_read);
492*4882a593Smuzhiyun
iio_enum_read(struct iio_dev * indio_dev,uintptr_t priv,const struct iio_chan_spec * chan,char * buf)493*4882a593Smuzhiyun ssize_t iio_enum_read(struct iio_dev *indio_dev,
494*4882a593Smuzhiyun uintptr_t priv, const struct iio_chan_spec *chan, char *buf)
495*4882a593Smuzhiyun {
496*4882a593Smuzhiyun const struct iio_enum *e = (const struct iio_enum *)priv;
497*4882a593Smuzhiyun int i;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun if (!e->get)
500*4882a593Smuzhiyun return -EINVAL;
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun i = e->get(indio_dev, chan);
503*4882a593Smuzhiyun if (i < 0)
504*4882a593Smuzhiyun return i;
505*4882a593Smuzhiyun else if (i >= e->num_items)
506*4882a593Smuzhiyun return -EINVAL;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%s\n", e->items[i]);
509*4882a593Smuzhiyun }
510*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(iio_enum_read);
511*4882a593Smuzhiyun
iio_enum_write(struct iio_dev * indio_dev,uintptr_t priv,const struct iio_chan_spec * chan,const char * buf,size_t len)512*4882a593Smuzhiyun ssize_t iio_enum_write(struct iio_dev *indio_dev,
513*4882a593Smuzhiyun uintptr_t priv, const struct iio_chan_spec *chan, const char *buf,
514*4882a593Smuzhiyun size_t len)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun const struct iio_enum *e = (const struct iio_enum *)priv;
517*4882a593Smuzhiyun int ret;
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun if (!e->set)
520*4882a593Smuzhiyun return -EINVAL;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun ret = __sysfs_match_string(e->items, e->num_items, buf);
523*4882a593Smuzhiyun if (ret < 0)
524*4882a593Smuzhiyun return ret;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun ret = e->set(indio_dev, chan, ret);
527*4882a593Smuzhiyun return ret ? ret : len;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(iio_enum_write);
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun static const struct iio_mount_matrix iio_mount_idmatrix = {
532*4882a593Smuzhiyun .rotation = {
533*4882a593Smuzhiyun "1", "0", "0",
534*4882a593Smuzhiyun "0", "1", "0",
535*4882a593Smuzhiyun "0", "0", "1"
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun };
538*4882a593Smuzhiyun
iio_setup_mount_idmatrix(const struct device * dev,struct iio_mount_matrix * matrix)539*4882a593Smuzhiyun static int iio_setup_mount_idmatrix(const struct device *dev,
540*4882a593Smuzhiyun struct iio_mount_matrix *matrix)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun *matrix = iio_mount_idmatrix;
543*4882a593Smuzhiyun dev_info(dev, "mounting matrix not found: using identity...\n");
544*4882a593Smuzhiyun return 0;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
iio_show_mount_matrix(struct iio_dev * indio_dev,uintptr_t priv,const struct iio_chan_spec * chan,char * buf)547*4882a593Smuzhiyun ssize_t iio_show_mount_matrix(struct iio_dev *indio_dev, uintptr_t priv,
548*4882a593Smuzhiyun const struct iio_chan_spec *chan, char *buf)
549*4882a593Smuzhiyun {
550*4882a593Smuzhiyun const struct iio_mount_matrix *mtx = ((iio_get_mount_matrix_t *)
551*4882a593Smuzhiyun priv)(indio_dev, chan);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun if (IS_ERR(mtx))
554*4882a593Smuzhiyun return PTR_ERR(mtx);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun if (!mtx)
557*4882a593Smuzhiyun mtx = &iio_mount_idmatrix;
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%s, %s, %s; %s, %s, %s; %s, %s, %s\n",
560*4882a593Smuzhiyun mtx->rotation[0], mtx->rotation[1], mtx->rotation[2],
561*4882a593Smuzhiyun mtx->rotation[3], mtx->rotation[4], mtx->rotation[5],
562*4882a593Smuzhiyun mtx->rotation[6], mtx->rotation[7], mtx->rotation[8]);
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(iio_show_mount_matrix);
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun /**
567*4882a593Smuzhiyun * iio_read_mount_matrix() - retrieve iio device mounting matrix from
568*4882a593Smuzhiyun * device "mount-matrix" property
569*4882a593Smuzhiyun * @dev: device the mounting matrix property is assigned to
570*4882a593Smuzhiyun * @propname: device specific mounting matrix property name
571*4882a593Smuzhiyun * @matrix: where to store retrieved matrix
572*4882a593Smuzhiyun *
573*4882a593Smuzhiyun * If device is assigned no mounting matrix property, a default 3x3 identity
574*4882a593Smuzhiyun * matrix will be filled in.
575*4882a593Smuzhiyun *
576*4882a593Smuzhiyun * Return: 0 if success, or a negative error code on failure.
577*4882a593Smuzhiyun */
iio_read_mount_matrix(struct device * dev,const char * propname,struct iio_mount_matrix * matrix)578*4882a593Smuzhiyun int iio_read_mount_matrix(struct device *dev, const char *propname,
579*4882a593Smuzhiyun struct iio_mount_matrix *matrix)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun size_t len = ARRAY_SIZE(iio_mount_idmatrix.rotation);
582*4882a593Smuzhiyun int err;
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun err = device_property_read_string_array(dev, propname,
585*4882a593Smuzhiyun matrix->rotation, len);
586*4882a593Smuzhiyun if (err == len)
587*4882a593Smuzhiyun return 0;
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun if (err >= 0)
590*4882a593Smuzhiyun /* Invalid number of matrix entries. */
591*4882a593Smuzhiyun return -EINVAL;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun if (err != -EINVAL)
594*4882a593Smuzhiyun /* Invalid matrix declaration format. */
595*4882a593Smuzhiyun return err;
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun /* Matrix was not declared at all: fallback to identity. */
598*4882a593Smuzhiyun return iio_setup_mount_idmatrix(dev, matrix);
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun EXPORT_SYMBOL(iio_read_mount_matrix);
601*4882a593Smuzhiyun
__iio_format_value(char * buf,size_t len,unsigned int type,int size,const int * vals)602*4882a593Smuzhiyun static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type,
603*4882a593Smuzhiyun int size, const int *vals)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun unsigned long long tmp;
606*4882a593Smuzhiyun int tmp0, tmp1;
607*4882a593Smuzhiyun bool scale_db = false;
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun switch (type) {
610*4882a593Smuzhiyun case IIO_VAL_INT:
611*4882a593Smuzhiyun return scnprintf(buf, len, "%d", vals[0]);
612*4882a593Smuzhiyun case IIO_VAL_INT_PLUS_MICRO_DB:
613*4882a593Smuzhiyun scale_db = true;
614*4882a593Smuzhiyun fallthrough;
615*4882a593Smuzhiyun case IIO_VAL_INT_PLUS_MICRO:
616*4882a593Smuzhiyun if (vals[1] < 0)
617*4882a593Smuzhiyun return scnprintf(buf, len, "-%d.%06u%s", abs(vals[0]),
618*4882a593Smuzhiyun -vals[1], scale_db ? " dB" : "");
619*4882a593Smuzhiyun else
620*4882a593Smuzhiyun return scnprintf(buf, len, "%d.%06u%s", vals[0], vals[1],
621*4882a593Smuzhiyun scale_db ? " dB" : "");
622*4882a593Smuzhiyun case IIO_VAL_INT_PLUS_NANO:
623*4882a593Smuzhiyun if (vals[1] < 0)
624*4882a593Smuzhiyun return scnprintf(buf, len, "-%d.%09u", abs(vals[0]),
625*4882a593Smuzhiyun -vals[1]);
626*4882a593Smuzhiyun else
627*4882a593Smuzhiyun return scnprintf(buf, len, "%d.%09u", vals[0], vals[1]);
628*4882a593Smuzhiyun case IIO_VAL_FRACTIONAL:
629*4882a593Smuzhiyun tmp = div_s64((s64)vals[0] * 1000000000LL, vals[1]);
630*4882a593Smuzhiyun tmp1 = vals[1];
631*4882a593Smuzhiyun tmp0 = (int)div_s64_rem(tmp, 1000000000, &tmp1);
632*4882a593Smuzhiyun return scnprintf(buf, len, "%d.%09u", tmp0, abs(tmp1));
633*4882a593Smuzhiyun case IIO_VAL_FRACTIONAL_LOG2:
634*4882a593Smuzhiyun tmp = shift_right((s64)vals[0] * 1000000000LL, vals[1]);
635*4882a593Smuzhiyun tmp0 = (int)div_s64_rem(tmp, 1000000000LL, &tmp1);
636*4882a593Smuzhiyun return scnprintf(buf, len, "%d.%09u", tmp0, abs(tmp1));
637*4882a593Smuzhiyun case IIO_VAL_INT_MULTIPLE:
638*4882a593Smuzhiyun {
639*4882a593Smuzhiyun int i;
640*4882a593Smuzhiyun int l = 0;
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun for (i = 0; i < size; ++i) {
643*4882a593Smuzhiyun l += scnprintf(&buf[l], len - l, "%d ", vals[i]);
644*4882a593Smuzhiyun if (l >= len)
645*4882a593Smuzhiyun break;
646*4882a593Smuzhiyun }
647*4882a593Smuzhiyun return l;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun case IIO_VAL_CHAR:
650*4882a593Smuzhiyun return scnprintf(buf, len, "%c", (char)vals[0]);
651*4882a593Smuzhiyun default:
652*4882a593Smuzhiyun return 0;
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun /**
657*4882a593Smuzhiyun * iio_format_value() - Formats a IIO value into its string representation
658*4882a593Smuzhiyun * @buf: The buffer to which the formatted value gets written
659*4882a593Smuzhiyun * which is assumed to be big enough (i.e. PAGE_SIZE).
660*4882a593Smuzhiyun * @type: One of the IIO_VAL_* constants. This decides how the val
661*4882a593Smuzhiyun * and val2 parameters are formatted.
662*4882a593Smuzhiyun * @size: Number of IIO value entries contained in vals
663*4882a593Smuzhiyun * @vals: Pointer to the values, exact meaning depends on the
664*4882a593Smuzhiyun * type parameter.
665*4882a593Smuzhiyun *
666*4882a593Smuzhiyun * Return: 0 by default, a negative number on failure or the
667*4882a593Smuzhiyun * total number of characters written for a type that belongs
668*4882a593Smuzhiyun * to the IIO_VAL_* constant.
669*4882a593Smuzhiyun */
iio_format_value(char * buf,unsigned int type,int size,int * vals)670*4882a593Smuzhiyun ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
671*4882a593Smuzhiyun {
672*4882a593Smuzhiyun ssize_t len;
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun len = __iio_format_value(buf, PAGE_SIZE, type, size, vals);
675*4882a593Smuzhiyun if (len >= PAGE_SIZE - 1)
676*4882a593Smuzhiyun return -EFBIG;
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun return len + sprintf(buf + len, "\n");
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(iio_format_value);
681*4882a593Smuzhiyun
iio_read_channel_info(struct device * dev,struct device_attribute * attr,char * buf)682*4882a593Smuzhiyun static ssize_t iio_read_channel_info(struct device *dev,
683*4882a593Smuzhiyun struct device_attribute *attr,
684*4882a593Smuzhiyun char *buf)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun struct iio_dev *indio_dev = dev_to_iio_dev(dev);
687*4882a593Smuzhiyun struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
688*4882a593Smuzhiyun int vals[INDIO_MAX_RAW_ELEMENTS];
689*4882a593Smuzhiyun int ret;
690*4882a593Smuzhiyun int val_len = 2;
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun if (indio_dev->info->read_raw_multi)
693*4882a593Smuzhiyun ret = indio_dev->info->read_raw_multi(indio_dev, this_attr->c,
694*4882a593Smuzhiyun INDIO_MAX_RAW_ELEMENTS,
695*4882a593Smuzhiyun vals, &val_len,
696*4882a593Smuzhiyun this_attr->address);
697*4882a593Smuzhiyun else
698*4882a593Smuzhiyun ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
699*4882a593Smuzhiyun &vals[0], &vals[1], this_attr->address);
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun if (ret < 0)
702*4882a593Smuzhiyun return ret;
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun return iio_format_value(buf, ret, val_len, vals);
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun
iio_format_avail_list(char * buf,const int * vals,int type,int length)707*4882a593Smuzhiyun static ssize_t iio_format_avail_list(char *buf, const int *vals,
708*4882a593Smuzhiyun int type, int length)
709*4882a593Smuzhiyun {
710*4882a593Smuzhiyun int i;
711*4882a593Smuzhiyun ssize_t len = 0;
712*4882a593Smuzhiyun
713*4882a593Smuzhiyun switch (type) {
714*4882a593Smuzhiyun case IIO_VAL_INT:
715*4882a593Smuzhiyun for (i = 0; i < length; i++) {
716*4882a593Smuzhiyun len += __iio_format_value(buf + len, PAGE_SIZE - len,
717*4882a593Smuzhiyun type, 1, &vals[i]);
718*4882a593Smuzhiyun if (len >= PAGE_SIZE)
719*4882a593Smuzhiyun return -EFBIG;
720*4882a593Smuzhiyun if (i < length - 1)
721*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len,
722*4882a593Smuzhiyun " ");
723*4882a593Smuzhiyun else
724*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len,
725*4882a593Smuzhiyun "\n");
726*4882a593Smuzhiyun if (len >= PAGE_SIZE)
727*4882a593Smuzhiyun return -EFBIG;
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun break;
730*4882a593Smuzhiyun default:
731*4882a593Smuzhiyun for (i = 0; i < length / 2; i++) {
732*4882a593Smuzhiyun len += __iio_format_value(buf + len, PAGE_SIZE - len,
733*4882a593Smuzhiyun type, 2, &vals[i * 2]);
734*4882a593Smuzhiyun if (len >= PAGE_SIZE)
735*4882a593Smuzhiyun return -EFBIG;
736*4882a593Smuzhiyun if (i < length / 2 - 1)
737*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len,
738*4882a593Smuzhiyun " ");
739*4882a593Smuzhiyun else
740*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len,
741*4882a593Smuzhiyun "\n");
742*4882a593Smuzhiyun if (len >= PAGE_SIZE)
743*4882a593Smuzhiyun return -EFBIG;
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun return len;
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun
iio_format_avail_range(char * buf,const int * vals,int type)750*4882a593Smuzhiyun static ssize_t iio_format_avail_range(char *buf, const int *vals, int type)
751*4882a593Smuzhiyun {
752*4882a593Smuzhiyun int i;
753*4882a593Smuzhiyun ssize_t len;
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun len = snprintf(buf, PAGE_SIZE, "[");
756*4882a593Smuzhiyun switch (type) {
757*4882a593Smuzhiyun case IIO_VAL_INT:
758*4882a593Smuzhiyun for (i = 0; i < 3; i++) {
759*4882a593Smuzhiyun len += __iio_format_value(buf + len, PAGE_SIZE - len,
760*4882a593Smuzhiyun type, 1, &vals[i]);
761*4882a593Smuzhiyun if (len >= PAGE_SIZE)
762*4882a593Smuzhiyun return -EFBIG;
763*4882a593Smuzhiyun if (i < 2)
764*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len,
765*4882a593Smuzhiyun " ");
766*4882a593Smuzhiyun else
767*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len,
768*4882a593Smuzhiyun "]\n");
769*4882a593Smuzhiyun if (len >= PAGE_SIZE)
770*4882a593Smuzhiyun return -EFBIG;
771*4882a593Smuzhiyun }
772*4882a593Smuzhiyun break;
773*4882a593Smuzhiyun default:
774*4882a593Smuzhiyun for (i = 0; i < 3; i++) {
775*4882a593Smuzhiyun len += __iio_format_value(buf + len, PAGE_SIZE - len,
776*4882a593Smuzhiyun type, 2, &vals[i * 2]);
777*4882a593Smuzhiyun if (len >= PAGE_SIZE)
778*4882a593Smuzhiyun return -EFBIG;
779*4882a593Smuzhiyun if (i < 2)
780*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len,
781*4882a593Smuzhiyun " ");
782*4882a593Smuzhiyun else
783*4882a593Smuzhiyun len += scnprintf(buf + len, PAGE_SIZE - len,
784*4882a593Smuzhiyun "]\n");
785*4882a593Smuzhiyun if (len >= PAGE_SIZE)
786*4882a593Smuzhiyun return -EFBIG;
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun return len;
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun
iio_read_channel_info_avail(struct device * dev,struct device_attribute * attr,char * buf)793*4882a593Smuzhiyun static ssize_t iio_read_channel_info_avail(struct device *dev,
794*4882a593Smuzhiyun struct device_attribute *attr,
795*4882a593Smuzhiyun char *buf)
796*4882a593Smuzhiyun {
797*4882a593Smuzhiyun struct iio_dev *indio_dev = dev_to_iio_dev(dev);
798*4882a593Smuzhiyun struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
799*4882a593Smuzhiyun const int *vals;
800*4882a593Smuzhiyun int ret;
801*4882a593Smuzhiyun int length;
802*4882a593Smuzhiyun int type;
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun ret = indio_dev->info->read_avail(indio_dev, this_attr->c,
805*4882a593Smuzhiyun &vals, &type, &length,
806*4882a593Smuzhiyun this_attr->address);
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun if (ret < 0)
809*4882a593Smuzhiyun return ret;
810*4882a593Smuzhiyun switch (ret) {
811*4882a593Smuzhiyun case IIO_AVAIL_LIST:
812*4882a593Smuzhiyun return iio_format_avail_list(buf, vals, type, length);
813*4882a593Smuzhiyun case IIO_AVAIL_RANGE:
814*4882a593Smuzhiyun return iio_format_avail_range(buf, vals, type);
815*4882a593Smuzhiyun default:
816*4882a593Smuzhiyun return -EINVAL;
817*4882a593Smuzhiyun }
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun /**
821*4882a593Smuzhiyun * __iio_str_to_fixpoint() - Parse a fixed-point number from a string
822*4882a593Smuzhiyun * @str: The string to parse
823*4882a593Smuzhiyun * @fract_mult: Multiplier for the first decimal place, should be a power of 10
824*4882a593Smuzhiyun * @integer: The integer part of the number
825*4882a593Smuzhiyun * @fract: The fractional part of the number
826*4882a593Smuzhiyun * @scale_db: True if this should parse as dB
827*4882a593Smuzhiyun *
828*4882a593Smuzhiyun * Returns 0 on success, or a negative error code if the string could not be
829*4882a593Smuzhiyun * parsed.
830*4882a593Smuzhiyun */
__iio_str_to_fixpoint(const char * str,int fract_mult,int * integer,int * fract,bool scale_db)831*4882a593Smuzhiyun static int __iio_str_to_fixpoint(const char *str, int fract_mult,
832*4882a593Smuzhiyun int *integer, int *fract, bool scale_db)
833*4882a593Smuzhiyun {
834*4882a593Smuzhiyun int i = 0, f = 0;
835*4882a593Smuzhiyun bool integer_part = true, negative = false;
836*4882a593Smuzhiyun
837*4882a593Smuzhiyun if (fract_mult == 0) {
838*4882a593Smuzhiyun *fract = 0;
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun return kstrtoint(str, 0, integer);
841*4882a593Smuzhiyun }
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun if (str[0] == '-') {
844*4882a593Smuzhiyun negative = true;
845*4882a593Smuzhiyun str++;
846*4882a593Smuzhiyun } else if (str[0] == '+') {
847*4882a593Smuzhiyun str++;
848*4882a593Smuzhiyun }
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun while (*str) {
851*4882a593Smuzhiyun if ('0' <= *str && *str <= '9') {
852*4882a593Smuzhiyun if (integer_part) {
853*4882a593Smuzhiyun i = i * 10 + *str - '0';
854*4882a593Smuzhiyun } else {
855*4882a593Smuzhiyun f += fract_mult * (*str - '0');
856*4882a593Smuzhiyun fract_mult /= 10;
857*4882a593Smuzhiyun }
858*4882a593Smuzhiyun } else if (*str == '\n') {
859*4882a593Smuzhiyun if (*(str + 1) == '\0')
860*4882a593Smuzhiyun break;
861*4882a593Smuzhiyun else
862*4882a593Smuzhiyun return -EINVAL;
863*4882a593Smuzhiyun } else if (!strncmp(str, " dB", sizeof(" dB") - 1) && scale_db) {
864*4882a593Smuzhiyun /* Ignore the dB suffix */
865*4882a593Smuzhiyun str += sizeof(" dB") - 1;
866*4882a593Smuzhiyun continue;
867*4882a593Smuzhiyun } else if (!strncmp(str, "dB", sizeof("dB") - 1) && scale_db) {
868*4882a593Smuzhiyun /* Ignore the dB suffix */
869*4882a593Smuzhiyun str += sizeof("dB") - 1;
870*4882a593Smuzhiyun continue;
871*4882a593Smuzhiyun } else if (*str == '.' && integer_part) {
872*4882a593Smuzhiyun integer_part = false;
873*4882a593Smuzhiyun } else {
874*4882a593Smuzhiyun return -EINVAL;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun str++;
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun if (negative) {
880*4882a593Smuzhiyun if (i)
881*4882a593Smuzhiyun i = -i;
882*4882a593Smuzhiyun else
883*4882a593Smuzhiyun f = -f;
884*4882a593Smuzhiyun }
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun *integer = i;
887*4882a593Smuzhiyun *fract = f;
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun return 0;
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun /**
893*4882a593Smuzhiyun * iio_str_to_fixpoint() - Parse a fixed-point number from a string
894*4882a593Smuzhiyun * @str: The string to parse
895*4882a593Smuzhiyun * @fract_mult: Multiplier for the first decimal place, should be a power of 10
896*4882a593Smuzhiyun * @integer: The integer part of the number
897*4882a593Smuzhiyun * @fract: The fractional part of the number
898*4882a593Smuzhiyun *
899*4882a593Smuzhiyun * Returns 0 on success, or a negative error code if the string could not be
900*4882a593Smuzhiyun * parsed.
901*4882a593Smuzhiyun */
iio_str_to_fixpoint(const char * str,int fract_mult,int * integer,int * fract)902*4882a593Smuzhiyun int iio_str_to_fixpoint(const char *str, int fract_mult,
903*4882a593Smuzhiyun int *integer, int *fract)
904*4882a593Smuzhiyun {
905*4882a593Smuzhiyun return __iio_str_to_fixpoint(str, fract_mult, integer, fract, false);
906*4882a593Smuzhiyun }
907*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(iio_str_to_fixpoint);
908*4882a593Smuzhiyun
iio_write_channel_info(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)909*4882a593Smuzhiyun static ssize_t iio_write_channel_info(struct device *dev,
910*4882a593Smuzhiyun struct device_attribute *attr,
911*4882a593Smuzhiyun const char *buf,
912*4882a593Smuzhiyun size_t len)
913*4882a593Smuzhiyun {
914*4882a593Smuzhiyun struct iio_dev *indio_dev = dev_to_iio_dev(dev);
915*4882a593Smuzhiyun struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
916*4882a593Smuzhiyun int ret, fract_mult = 100000;
917*4882a593Smuzhiyun int integer, fract = 0;
918*4882a593Smuzhiyun bool is_char = false;
919*4882a593Smuzhiyun bool scale_db = false;
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun /* Assumes decimal - precision based on number of digits */
922*4882a593Smuzhiyun if (!indio_dev->info->write_raw)
923*4882a593Smuzhiyun return -EINVAL;
924*4882a593Smuzhiyun
925*4882a593Smuzhiyun if (indio_dev->info->write_raw_get_fmt)
926*4882a593Smuzhiyun switch (indio_dev->info->write_raw_get_fmt(indio_dev,
927*4882a593Smuzhiyun this_attr->c, this_attr->address)) {
928*4882a593Smuzhiyun case IIO_VAL_INT:
929*4882a593Smuzhiyun fract_mult = 0;
930*4882a593Smuzhiyun break;
931*4882a593Smuzhiyun case IIO_VAL_INT_PLUS_MICRO_DB:
932*4882a593Smuzhiyun scale_db = true;
933*4882a593Smuzhiyun fallthrough;
934*4882a593Smuzhiyun case IIO_VAL_INT_PLUS_MICRO:
935*4882a593Smuzhiyun fract_mult = 100000;
936*4882a593Smuzhiyun break;
937*4882a593Smuzhiyun case IIO_VAL_INT_PLUS_NANO:
938*4882a593Smuzhiyun fract_mult = 100000000;
939*4882a593Smuzhiyun break;
940*4882a593Smuzhiyun case IIO_VAL_CHAR:
941*4882a593Smuzhiyun is_char = true;
942*4882a593Smuzhiyun break;
943*4882a593Smuzhiyun default:
944*4882a593Smuzhiyun return -EINVAL;
945*4882a593Smuzhiyun }
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun if (is_char) {
948*4882a593Smuzhiyun char ch;
949*4882a593Smuzhiyun
950*4882a593Smuzhiyun if (sscanf(buf, "%c", &ch) != 1)
951*4882a593Smuzhiyun return -EINVAL;
952*4882a593Smuzhiyun integer = ch;
953*4882a593Smuzhiyun } else {
954*4882a593Smuzhiyun ret = __iio_str_to_fixpoint(buf, fract_mult, &integer, &fract,
955*4882a593Smuzhiyun scale_db);
956*4882a593Smuzhiyun if (ret)
957*4882a593Smuzhiyun return ret;
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun ret = indio_dev->info->write_raw(indio_dev, this_attr->c,
961*4882a593Smuzhiyun integer, fract, this_attr->address);
962*4882a593Smuzhiyun if (ret)
963*4882a593Smuzhiyun return ret;
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun return len;
966*4882a593Smuzhiyun }
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun static
__iio_device_attr_init(struct device_attribute * dev_attr,const char * postfix,struct iio_chan_spec const * chan,ssize_t (* readfunc)(struct device * dev,struct device_attribute * attr,char * buf),ssize_t (* writefunc)(struct device * dev,struct device_attribute * attr,const char * buf,size_t len),enum iio_shared_by shared_by)969*4882a593Smuzhiyun int __iio_device_attr_init(struct device_attribute *dev_attr,
970*4882a593Smuzhiyun const char *postfix,
971*4882a593Smuzhiyun struct iio_chan_spec const *chan,
972*4882a593Smuzhiyun ssize_t (*readfunc)(struct device *dev,
973*4882a593Smuzhiyun struct device_attribute *attr,
974*4882a593Smuzhiyun char *buf),
975*4882a593Smuzhiyun ssize_t (*writefunc)(struct device *dev,
976*4882a593Smuzhiyun struct device_attribute *attr,
977*4882a593Smuzhiyun const char *buf,
978*4882a593Smuzhiyun size_t len),
979*4882a593Smuzhiyun enum iio_shared_by shared_by)
980*4882a593Smuzhiyun {
981*4882a593Smuzhiyun int ret = 0;
982*4882a593Smuzhiyun char *name = NULL;
983*4882a593Smuzhiyun char *full_postfix;
984*4882a593Smuzhiyun sysfs_attr_init(&dev_attr->attr);
985*4882a593Smuzhiyun
986*4882a593Smuzhiyun /* Build up postfix of <extend_name>_<modifier>_postfix */
987*4882a593Smuzhiyun if (chan->modified && (shared_by == IIO_SEPARATE)) {
988*4882a593Smuzhiyun if (chan->extend_name)
989*4882a593Smuzhiyun full_postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
990*4882a593Smuzhiyun iio_modifier_names[chan
991*4882a593Smuzhiyun ->channel2],
992*4882a593Smuzhiyun chan->extend_name,
993*4882a593Smuzhiyun postfix);
994*4882a593Smuzhiyun else
995*4882a593Smuzhiyun full_postfix = kasprintf(GFP_KERNEL, "%s_%s",
996*4882a593Smuzhiyun iio_modifier_names[chan
997*4882a593Smuzhiyun ->channel2],
998*4882a593Smuzhiyun postfix);
999*4882a593Smuzhiyun } else {
1000*4882a593Smuzhiyun if (chan->extend_name == NULL || shared_by != IIO_SEPARATE)
1001*4882a593Smuzhiyun full_postfix = kstrdup(postfix, GFP_KERNEL);
1002*4882a593Smuzhiyun else
1003*4882a593Smuzhiyun full_postfix = kasprintf(GFP_KERNEL,
1004*4882a593Smuzhiyun "%s_%s",
1005*4882a593Smuzhiyun chan->extend_name,
1006*4882a593Smuzhiyun postfix);
1007*4882a593Smuzhiyun }
1008*4882a593Smuzhiyun if (full_postfix == NULL)
1009*4882a593Smuzhiyun return -ENOMEM;
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun if (chan->differential) { /* Differential can not have modifier */
1012*4882a593Smuzhiyun switch (shared_by) {
1013*4882a593Smuzhiyun case IIO_SHARED_BY_ALL:
1014*4882a593Smuzhiyun name = kasprintf(GFP_KERNEL, "%s", full_postfix);
1015*4882a593Smuzhiyun break;
1016*4882a593Smuzhiyun case IIO_SHARED_BY_DIR:
1017*4882a593Smuzhiyun name = kasprintf(GFP_KERNEL, "%s_%s",
1018*4882a593Smuzhiyun iio_direction[chan->output],
1019*4882a593Smuzhiyun full_postfix);
1020*4882a593Smuzhiyun break;
1021*4882a593Smuzhiyun case IIO_SHARED_BY_TYPE:
1022*4882a593Smuzhiyun name = kasprintf(GFP_KERNEL, "%s_%s-%s_%s",
1023*4882a593Smuzhiyun iio_direction[chan->output],
1024*4882a593Smuzhiyun iio_chan_type_name_spec[chan->type],
1025*4882a593Smuzhiyun iio_chan_type_name_spec[chan->type],
1026*4882a593Smuzhiyun full_postfix);
1027*4882a593Smuzhiyun break;
1028*4882a593Smuzhiyun case IIO_SEPARATE:
1029*4882a593Smuzhiyun if (!chan->indexed) {
1030*4882a593Smuzhiyun WARN(1, "Differential channels must be indexed\n");
1031*4882a593Smuzhiyun ret = -EINVAL;
1032*4882a593Smuzhiyun goto error_free_full_postfix;
1033*4882a593Smuzhiyun }
1034*4882a593Smuzhiyun name = kasprintf(GFP_KERNEL,
1035*4882a593Smuzhiyun "%s_%s%d-%s%d_%s",
1036*4882a593Smuzhiyun iio_direction[chan->output],
1037*4882a593Smuzhiyun iio_chan_type_name_spec[chan->type],
1038*4882a593Smuzhiyun chan->channel,
1039*4882a593Smuzhiyun iio_chan_type_name_spec[chan->type],
1040*4882a593Smuzhiyun chan->channel2,
1041*4882a593Smuzhiyun full_postfix);
1042*4882a593Smuzhiyun break;
1043*4882a593Smuzhiyun }
1044*4882a593Smuzhiyun } else { /* Single ended */
1045*4882a593Smuzhiyun switch (shared_by) {
1046*4882a593Smuzhiyun case IIO_SHARED_BY_ALL:
1047*4882a593Smuzhiyun name = kasprintf(GFP_KERNEL, "%s", full_postfix);
1048*4882a593Smuzhiyun break;
1049*4882a593Smuzhiyun case IIO_SHARED_BY_DIR:
1050*4882a593Smuzhiyun name = kasprintf(GFP_KERNEL, "%s_%s",
1051*4882a593Smuzhiyun iio_direction[chan->output],
1052*4882a593Smuzhiyun full_postfix);
1053*4882a593Smuzhiyun break;
1054*4882a593Smuzhiyun case IIO_SHARED_BY_TYPE:
1055*4882a593Smuzhiyun name = kasprintf(GFP_KERNEL, "%s_%s_%s",
1056*4882a593Smuzhiyun iio_direction[chan->output],
1057*4882a593Smuzhiyun iio_chan_type_name_spec[chan->type],
1058*4882a593Smuzhiyun full_postfix);
1059*4882a593Smuzhiyun break;
1060*4882a593Smuzhiyun
1061*4882a593Smuzhiyun case IIO_SEPARATE:
1062*4882a593Smuzhiyun if (chan->indexed)
1063*4882a593Smuzhiyun name = kasprintf(GFP_KERNEL, "%s_%s%d_%s",
1064*4882a593Smuzhiyun iio_direction[chan->output],
1065*4882a593Smuzhiyun iio_chan_type_name_spec[chan->type],
1066*4882a593Smuzhiyun chan->channel,
1067*4882a593Smuzhiyun full_postfix);
1068*4882a593Smuzhiyun else
1069*4882a593Smuzhiyun name = kasprintf(GFP_KERNEL, "%s_%s_%s",
1070*4882a593Smuzhiyun iio_direction[chan->output],
1071*4882a593Smuzhiyun iio_chan_type_name_spec[chan->type],
1072*4882a593Smuzhiyun full_postfix);
1073*4882a593Smuzhiyun break;
1074*4882a593Smuzhiyun }
1075*4882a593Smuzhiyun }
1076*4882a593Smuzhiyun if (name == NULL) {
1077*4882a593Smuzhiyun ret = -ENOMEM;
1078*4882a593Smuzhiyun goto error_free_full_postfix;
1079*4882a593Smuzhiyun }
1080*4882a593Smuzhiyun dev_attr->attr.name = name;
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun if (readfunc) {
1083*4882a593Smuzhiyun dev_attr->attr.mode |= S_IRUGO;
1084*4882a593Smuzhiyun dev_attr->show = readfunc;
1085*4882a593Smuzhiyun }
1086*4882a593Smuzhiyun
1087*4882a593Smuzhiyun if (writefunc) {
1088*4882a593Smuzhiyun dev_attr->attr.mode |= S_IWUSR;
1089*4882a593Smuzhiyun dev_attr->store = writefunc;
1090*4882a593Smuzhiyun }
1091*4882a593Smuzhiyun
1092*4882a593Smuzhiyun error_free_full_postfix:
1093*4882a593Smuzhiyun kfree(full_postfix);
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun return ret;
1096*4882a593Smuzhiyun }
1097*4882a593Smuzhiyun
__iio_device_attr_deinit(struct device_attribute * dev_attr)1098*4882a593Smuzhiyun static void __iio_device_attr_deinit(struct device_attribute *dev_attr)
1099*4882a593Smuzhiyun {
1100*4882a593Smuzhiyun kfree(dev_attr->attr.name);
1101*4882a593Smuzhiyun }
1102*4882a593Smuzhiyun
__iio_add_chan_devattr(const char * postfix,struct iio_chan_spec const * chan,ssize_t (* readfunc)(struct device * dev,struct device_attribute * attr,char * buf),ssize_t (* writefunc)(struct device * dev,struct device_attribute * attr,const char * buf,size_t len),u64 mask,enum iio_shared_by shared_by,struct device * dev,struct list_head * attr_list)1103*4882a593Smuzhiyun int __iio_add_chan_devattr(const char *postfix,
1104*4882a593Smuzhiyun struct iio_chan_spec const *chan,
1105*4882a593Smuzhiyun ssize_t (*readfunc)(struct device *dev,
1106*4882a593Smuzhiyun struct device_attribute *attr,
1107*4882a593Smuzhiyun char *buf),
1108*4882a593Smuzhiyun ssize_t (*writefunc)(struct device *dev,
1109*4882a593Smuzhiyun struct device_attribute *attr,
1110*4882a593Smuzhiyun const char *buf,
1111*4882a593Smuzhiyun size_t len),
1112*4882a593Smuzhiyun u64 mask,
1113*4882a593Smuzhiyun enum iio_shared_by shared_by,
1114*4882a593Smuzhiyun struct device *dev,
1115*4882a593Smuzhiyun struct list_head *attr_list)
1116*4882a593Smuzhiyun {
1117*4882a593Smuzhiyun int ret;
1118*4882a593Smuzhiyun struct iio_dev_attr *iio_attr, *t;
1119*4882a593Smuzhiyun
1120*4882a593Smuzhiyun iio_attr = kzalloc(sizeof(*iio_attr), GFP_KERNEL);
1121*4882a593Smuzhiyun if (iio_attr == NULL)
1122*4882a593Smuzhiyun return -ENOMEM;
1123*4882a593Smuzhiyun ret = __iio_device_attr_init(&iio_attr->dev_attr,
1124*4882a593Smuzhiyun postfix, chan,
1125*4882a593Smuzhiyun readfunc, writefunc, shared_by);
1126*4882a593Smuzhiyun if (ret)
1127*4882a593Smuzhiyun goto error_iio_dev_attr_free;
1128*4882a593Smuzhiyun iio_attr->c = chan;
1129*4882a593Smuzhiyun iio_attr->address = mask;
1130*4882a593Smuzhiyun list_for_each_entry(t, attr_list, l)
1131*4882a593Smuzhiyun if (strcmp(t->dev_attr.attr.name,
1132*4882a593Smuzhiyun iio_attr->dev_attr.attr.name) == 0) {
1133*4882a593Smuzhiyun if (shared_by == IIO_SEPARATE)
1134*4882a593Smuzhiyun dev_err(dev, "tried to double register : %s\n",
1135*4882a593Smuzhiyun t->dev_attr.attr.name);
1136*4882a593Smuzhiyun ret = -EBUSY;
1137*4882a593Smuzhiyun goto error_device_attr_deinit;
1138*4882a593Smuzhiyun }
1139*4882a593Smuzhiyun list_add(&iio_attr->l, attr_list);
1140*4882a593Smuzhiyun
1141*4882a593Smuzhiyun return 0;
1142*4882a593Smuzhiyun
1143*4882a593Smuzhiyun error_device_attr_deinit:
1144*4882a593Smuzhiyun __iio_device_attr_deinit(&iio_attr->dev_attr);
1145*4882a593Smuzhiyun error_iio_dev_attr_free:
1146*4882a593Smuzhiyun kfree(iio_attr);
1147*4882a593Smuzhiyun return ret;
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun
iio_device_add_info_mask_type(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,enum iio_shared_by shared_by,const long * infomask)1150*4882a593Smuzhiyun static int iio_device_add_info_mask_type(struct iio_dev *indio_dev,
1151*4882a593Smuzhiyun struct iio_chan_spec const *chan,
1152*4882a593Smuzhiyun enum iio_shared_by shared_by,
1153*4882a593Smuzhiyun const long *infomask)
1154*4882a593Smuzhiyun {
1155*4882a593Smuzhiyun struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
1156*4882a593Smuzhiyun int i, ret, attrcount = 0;
1157*4882a593Smuzhiyun
1158*4882a593Smuzhiyun for_each_set_bit(i, infomask, sizeof(*infomask)*8) {
1159*4882a593Smuzhiyun if (i >= ARRAY_SIZE(iio_chan_info_postfix))
1160*4882a593Smuzhiyun return -EINVAL;
1161*4882a593Smuzhiyun ret = __iio_add_chan_devattr(iio_chan_info_postfix[i],
1162*4882a593Smuzhiyun chan,
1163*4882a593Smuzhiyun &iio_read_channel_info,
1164*4882a593Smuzhiyun &iio_write_channel_info,
1165*4882a593Smuzhiyun i,
1166*4882a593Smuzhiyun shared_by,
1167*4882a593Smuzhiyun &indio_dev->dev,
1168*4882a593Smuzhiyun &iio_dev_opaque->channel_attr_list);
1169*4882a593Smuzhiyun if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE))
1170*4882a593Smuzhiyun continue;
1171*4882a593Smuzhiyun else if (ret < 0)
1172*4882a593Smuzhiyun return ret;
1173*4882a593Smuzhiyun attrcount++;
1174*4882a593Smuzhiyun }
1175*4882a593Smuzhiyun
1176*4882a593Smuzhiyun return attrcount;
1177*4882a593Smuzhiyun }
1178*4882a593Smuzhiyun
iio_device_add_info_mask_type_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,enum iio_shared_by shared_by,const long * infomask)1179*4882a593Smuzhiyun static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev,
1180*4882a593Smuzhiyun struct iio_chan_spec const *chan,
1181*4882a593Smuzhiyun enum iio_shared_by shared_by,
1182*4882a593Smuzhiyun const long *infomask)
1183*4882a593Smuzhiyun {
1184*4882a593Smuzhiyun struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
1185*4882a593Smuzhiyun int i, ret, attrcount = 0;
1186*4882a593Smuzhiyun char *avail_postfix;
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun for_each_set_bit(i, infomask, sizeof(*infomask) * 8) {
1189*4882a593Smuzhiyun if (i >= ARRAY_SIZE(iio_chan_info_postfix))
1190*4882a593Smuzhiyun return -EINVAL;
1191*4882a593Smuzhiyun avail_postfix = kasprintf(GFP_KERNEL,
1192*4882a593Smuzhiyun "%s_available",
1193*4882a593Smuzhiyun iio_chan_info_postfix[i]);
1194*4882a593Smuzhiyun if (!avail_postfix)
1195*4882a593Smuzhiyun return -ENOMEM;
1196*4882a593Smuzhiyun
1197*4882a593Smuzhiyun ret = __iio_add_chan_devattr(avail_postfix,
1198*4882a593Smuzhiyun chan,
1199*4882a593Smuzhiyun &iio_read_channel_info_avail,
1200*4882a593Smuzhiyun NULL,
1201*4882a593Smuzhiyun i,
1202*4882a593Smuzhiyun shared_by,
1203*4882a593Smuzhiyun &indio_dev->dev,
1204*4882a593Smuzhiyun &iio_dev_opaque->channel_attr_list);
1205*4882a593Smuzhiyun kfree(avail_postfix);
1206*4882a593Smuzhiyun if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE))
1207*4882a593Smuzhiyun continue;
1208*4882a593Smuzhiyun else if (ret < 0)
1209*4882a593Smuzhiyun return ret;
1210*4882a593Smuzhiyun attrcount++;
1211*4882a593Smuzhiyun }
1212*4882a593Smuzhiyun
1213*4882a593Smuzhiyun return attrcount;
1214*4882a593Smuzhiyun }
1215*4882a593Smuzhiyun
iio_device_add_channel_sysfs(struct iio_dev * indio_dev,struct iio_chan_spec const * chan)1216*4882a593Smuzhiyun static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
1217*4882a593Smuzhiyun struct iio_chan_spec const *chan)
1218*4882a593Smuzhiyun {
1219*4882a593Smuzhiyun struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
1220*4882a593Smuzhiyun int ret, attrcount = 0;
1221*4882a593Smuzhiyun const struct iio_chan_spec_ext_info *ext_info;
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun if (chan->channel < 0)
1224*4882a593Smuzhiyun return 0;
1225*4882a593Smuzhiyun ret = iio_device_add_info_mask_type(indio_dev, chan,
1226*4882a593Smuzhiyun IIO_SEPARATE,
1227*4882a593Smuzhiyun &chan->info_mask_separate);
1228*4882a593Smuzhiyun if (ret < 0)
1229*4882a593Smuzhiyun return ret;
1230*4882a593Smuzhiyun attrcount += ret;
1231*4882a593Smuzhiyun
1232*4882a593Smuzhiyun ret = iio_device_add_info_mask_type_avail(indio_dev, chan,
1233*4882a593Smuzhiyun IIO_SEPARATE,
1234*4882a593Smuzhiyun &chan->
1235*4882a593Smuzhiyun info_mask_separate_available);
1236*4882a593Smuzhiyun if (ret < 0)
1237*4882a593Smuzhiyun return ret;
1238*4882a593Smuzhiyun attrcount += ret;
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun ret = iio_device_add_info_mask_type(indio_dev, chan,
1241*4882a593Smuzhiyun IIO_SHARED_BY_TYPE,
1242*4882a593Smuzhiyun &chan->info_mask_shared_by_type);
1243*4882a593Smuzhiyun if (ret < 0)
1244*4882a593Smuzhiyun return ret;
1245*4882a593Smuzhiyun attrcount += ret;
1246*4882a593Smuzhiyun
1247*4882a593Smuzhiyun ret = iio_device_add_info_mask_type_avail(indio_dev, chan,
1248*4882a593Smuzhiyun IIO_SHARED_BY_TYPE,
1249*4882a593Smuzhiyun &chan->
1250*4882a593Smuzhiyun info_mask_shared_by_type_available);
1251*4882a593Smuzhiyun if (ret < 0)
1252*4882a593Smuzhiyun return ret;
1253*4882a593Smuzhiyun attrcount += ret;
1254*4882a593Smuzhiyun
1255*4882a593Smuzhiyun ret = iio_device_add_info_mask_type(indio_dev, chan,
1256*4882a593Smuzhiyun IIO_SHARED_BY_DIR,
1257*4882a593Smuzhiyun &chan->info_mask_shared_by_dir);
1258*4882a593Smuzhiyun if (ret < 0)
1259*4882a593Smuzhiyun return ret;
1260*4882a593Smuzhiyun attrcount += ret;
1261*4882a593Smuzhiyun
1262*4882a593Smuzhiyun ret = iio_device_add_info_mask_type_avail(indio_dev, chan,
1263*4882a593Smuzhiyun IIO_SHARED_BY_DIR,
1264*4882a593Smuzhiyun &chan->info_mask_shared_by_dir_available);
1265*4882a593Smuzhiyun if (ret < 0)
1266*4882a593Smuzhiyun return ret;
1267*4882a593Smuzhiyun attrcount += ret;
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun ret = iio_device_add_info_mask_type(indio_dev, chan,
1270*4882a593Smuzhiyun IIO_SHARED_BY_ALL,
1271*4882a593Smuzhiyun &chan->info_mask_shared_by_all);
1272*4882a593Smuzhiyun if (ret < 0)
1273*4882a593Smuzhiyun return ret;
1274*4882a593Smuzhiyun attrcount += ret;
1275*4882a593Smuzhiyun
1276*4882a593Smuzhiyun ret = iio_device_add_info_mask_type_avail(indio_dev, chan,
1277*4882a593Smuzhiyun IIO_SHARED_BY_ALL,
1278*4882a593Smuzhiyun &chan->info_mask_shared_by_all_available);
1279*4882a593Smuzhiyun if (ret < 0)
1280*4882a593Smuzhiyun return ret;
1281*4882a593Smuzhiyun attrcount += ret;
1282*4882a593Smuzhiyun
1283*4882a593Smuzhiyun if (chan->ext_info) {
1284*4882a593Smuzhiyun unsigned int i = 0;
1285*4882a593Smuzhiyun for (ext_info = chan->ext_info; ext_info->name; ext_info++) {
1286*4882a593Smuzhiyun ret = __iio_add_chan_devattr(ext_info->name,
1287*4882a593Smuzhiyun chan,
1288*4882a593Smuzhiyun ext_info->read ?
1289*4882a593Smuzhiyun &iio_read_channel_ext_info : NULL,
1290*4882a593Smuzhiyun ext_info->write ?
1291*4882a593Smuzhiyun &iio_write_channel_ext_info : NULL,
1292*4882a593Smuzhiyun i,
1293*4882a593Smuzhiyun ext_info->shared,
1294*4882a593Smuzhiyun &indio_dev->dev,
1295*4882a593Smuzhiyun &iio_dev_opaque->channel_attr_list);
1296*4882a593Smuzhiyun i++;
1297*4882a593Smuzhiyun if (ret == -EBUSY && ext_info->shared)
1298*4882a593Smuzhiyun continue;
1299*4882a593Smuzhiyun
1300*4882a593Smuzhiyun if (ret)
1301*4882a593Smuzhiyun return ret;
1302*4882a593Smuzhiyun
1303*4882a593Smuzhiyun attrcount++;
1304*4882a593Smuzhiyun }
1305*4882a593Smuzhiyun }
1306*4882a593Smuzhiyun
1307*4882a593Smuzhiyun return attrcount;
1308*4882a593Smuzhiyun }
1309*4882a593Smuzhiyun
1310*4882a593Smuzhiyun /**
1311*4882a593Smuzhiyun * iio_free_chan_devattr_list() - Free a list of IIO device attributes
1312*4882a593Smuzhiyun * @attr_list: List of IIO device attributes
1313*4882a593Smuzhiyun *
1314*4882a593Smuzhiyun * This function frees the memory allocated for each of the IIO device
1315*4882a593Smuzhiyun * attributes in the list.
1316*4882a593Smuzhiyun */
iio_free_chan_devattr_list(struct list_head * attr_list)1317*4882a593Smuzhiyun void iio_free_chan_devattr_list(struct list_head *attr_list)
1318*4882a593Smuzhiyun {
1319*4882a593Smuzhiyun struct iio_dev_attr *p, *n;
1320*4882a593Smuzhiyun
1321*4882a593Smuzhiyun list_for_each_entry_safe(p, n, attr_list, l) {
1322*4882a593Smuzhiyun kfree(p->dev_attr.attr.name);
1323*4882a593Smuzhiyun list_del(&p->l);
1324*4882a593Smuzhiyun kfree(p);
1325*4882a593Smuzhiyun }
1326*4882a593Smuzhiyun }
1327*4882a593Smuzhiyun
iio_show_dev_name(struct device * dev,struct device_attribute * attr,char * buf)1328*4882a593Smuzhiyun static ssize_t iio_show_dev_name(struct device *dev,
1329*4882a593Smuzhiyun struct device_attribute *attr,
1330*4882a593Smuzhiyun char *buf)
1331*4882a593Smuzhiyun {
1332*4882a593Smuzhiyun struct iio_dev *indio_dev = dev_to_iio_dev(dev);
1333*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%s\n", indio_dev->name);
1334*4882a593Smuzhiyun }
1335*4882a593Smuzhiyun
1336*4882a593Smuzhiyun static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL);
1337*4882a593Smuzhiyun
iio_show_dev_label(struct device * dev,struct device_attribute * attr,char * buf)1338*4882a593Smuzhiyun static ssize_t iio_show_dev_label(struct device *dev,
1339*4882a593Smuzhiyun struct device_attribute *attr,
1340*4882a593Smuzhiyun char *buf)
1341*4882a593Smuzhiyun {
1342*4882a593Smuzhiyun struct iio_dev *indio_dev = dev_to_iio_dev(dev);
1343*4882a593Smuzhiyun return snprintf(buf, PAGE_SIZE, "%s\n", indio_dev->label);
1344*4882a593Smuzhiyun }
1345*4882a593Smuzhiyun
1346*4882a593Smuzhiyun static DEVICE_ATTR(label, S_IRUGO, iio_show_dev_label, NULL);
1347*4882a593Smuzhiyun
iio_show_timestamp_clock(struct device * dev,struct device_attribute * attr,char * buf)1348*4882a593Smuzhiyun static ssize_t iio_show_timestamp_clock(struct device *dev,
1349*4882a593Smuzhiyun struct device_attribute *attr,
1350*4882a593Smuzhiyun char *buf)
1351*4882a593Smuzhiyun {
1352*4882a593Smuzhiyun const struct iio_dev *indio_dev = dev_to_iio_dev(dev);
1353*4882a593Smuzhiyun const clockid_t clk = iio_device_get_clock(indio_dev);
1354*4882a593Smuzhiyun const char *name;
1355*4882a593Smuzhiyun ssize_t sz;
1356*4882a593Smuzhiyun
1357*4882a593Smuzhiyun switch (clk) {
1358*4882a593Smuzhiyun case CLOCK_REALTIME:
1359*4882a593Smuzhiyun name = "realtime\n";
1360*4882a593Smuzhiyun sz = sizeof("realtime\n");
1361*4882a593Smuzhiyun break;
1362*4882a593Smuzhiyun case CLOCK_MONOTONIC:
1363*4882a593Smuzhiyun name = "monotonic\n";
1364*4882a593Smuzhiyun sz = sizeof("monotonic\n");
1365*4882a593Smuzhiyun break;
1366*4882a593Smuzhiyun case CLOCK_MONOTONIC_RAW:
1367*4882a593Smuzhiyun name = "monotonic_raw\n";
1368*4882a593Smuzhiyun sz = sizeof("monotonic_raw\n");
1369*4882a593Smuzhiyun break;
1370*4882a593Smuzhiyun case CLOCK_REALTIME_COARSE:
1371*4882a593Smuzhiyun name = "realtime_coarse\n";
1372*4882a593Smuzhiyun sz = sizeof("realtime_coarse\n");
1373*4882a593Smuzhiyun break;
1374*4882a593Smuzhiyun case CLOCK_MONOTONIC_COARSE:
1375*4882a593Smuzhiyun name = "monotonic_coarse\n";
1376*4882a593Smuzhiyun sz = sizeof("monotonic_coarse\n");
1377*4882a593Smuzhiyun break;
1378*4882a593Smuzhiyun case CLOCK_BOOTTIME:
1379*4882a593Smuzhiyun name = "boottime\n";
1380*4882a593Smuzhiyun sz = sizeof("boottime\n");
1381*4882a593Smuzhiyun break;
1382*4882a593Smuzhiyun case CLOCK_TAI:
1383*4882a593Smuzhiyun name = "tai\n";
1384*4882a593Smuzhiyun sz = sizeof("tai\n");
1385*4882a593Smuzhiyun break;
1386*4882a593Smuzhiyun default:
1387*4882a593Smuzhiyun BUG();
1388*4882a593Smuzhiyun }
1389*4882a593Smuzhiyun
1390*4882a593Smuzhiyun memcpy(buf, name, sz);
1391*4882a593Smuzhiyun return sz;
1392*4882a593Smuzhiyun }
1393*4882a593Smuzhiyun
iio_store_timestamp_clock(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)1394*4882a593Smuzhiyun static ssize_t iio_store_timestamp_clock(struct device *dev,
1395*4882a593Smuzhiyun struct device_attribute *attr,
1396*4882a593Smuzhiyun const char *buf, size_t len)
1397*4882a593Smuzhiyun {
1398*4882a593Smuzhiyun clockid_t clk;
1399*4882a593Smuzhiyun int ret;
1400*4882a593Smuzhiyun
1401*4882a593Smuzhiyun if (sysfs_streq(buf, "realtime"))
1402*4882a593Smuzhiyun clk = CLOCK_REALTIME;
1403*4882a593Smuzhiyun else if (sysfs_streq(buf, "monotonic"))
1404*4882a593Smuzhiyun clk = CLOCK_MONOTONIC;
1405*4882a593Smuzhiyun else if (sysfs_streq(buf, "monotonic_raw"))
1406*4882a593Smuzhiyun clk = CLOCK_MONOTONIC_RAW;
1407*4882a593Smuzhiyun else if (sysfs_streq(buf, "realtime_coarse"))
1408*4882a593Smuzhiyun clk = CLOCK_REALTIME_COARSE;
1409*4882a593Smuzhiyun else if (sysfs_streq(buf, "monotonic_coarse"))
1410*4882a593Smuzhiyun clk = CLOCK_MONOTONIC_COARSE;
1411*4882a593Smuzhiyun else if (sysfs_streq(buf, "boottime"))
1412*4882a593Smuzhiyun clk = CLOCK_BOOTTIME;
1413*4882a593Smuzhiyun else if (sysfs_streq(buf, "tai"))
1414*4882a593Smuzhiyun clk = CLOCK_TAI;
1415*4882a593Smuzhiyun else
1416*4882a593Smuzhiyun return -EINVAL;
1417*4882a593Smuzhiyun
1418*4882a593Smuzhiyun ret = iio_device_set_clock(dev_to_iio_dev(dev), clk);
1419*4882a593Smuzhiyun if (ret)
1420*4882a593Smuzhiyun return ret;
1421*4882a593Smuzhiyun
1422*4882a593Smuzhiyun return len;
1423*4882a593Smuzhiyun }
1424*4882a593Smuzhiyun
1425*4882a593Smuzhiyun static DEVICE_ATTR(current_timestamp_clock, S_IRUGO | S_IWUSR,
1426*4882a593Smuzhiyun iio_show_timestamp_clock, iio_store_timestamp_clock);
1427*4882a593Smuzhiyun
iio_device_register_sysfs(struct iio_dev * indio_dev)1428*4882a593Smuzhiyun static int iio_device_register_sysfs(struct iio_dev *indio_dev)
1429*4882a593Smuzhiyun {
1430*4882a593Smuzhiyun struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
1431*4882a593Smuzhiyun int i, ret = 0, attrcount, attrn, attrcount_orig = 0;
1432*4882a593Smuzhiyun struct iio_dev_attr *p;
1433*4882a593Smuzhiyun struct attribute **attr, *clk = NULL;
1434*4882a593Smuzhiyun
1435*4882a593Smuzhiyun /* First count elements in any existing group */
1436*4882a593Smuzhiyun if (indio_dev->info->attrs) {
1437*4882a593Smuzhiyun attr = indio_dev->info->attrs->attrs;
1438*4882a593Smuzhiyun while (*attr++ != NULL)
1439*4882a593Smuzhiyun attrcount_orig++;
1440*4882a593Smuzhiyun }
1441*4882a593Smuzhiyun attrcount = attrcount_orig;
1442*4882a593Smuzhiyun /*
1443*4882a593Smuzhiyun * New channel registration method - relies on the fact a group does
1444*4882a593Smuzhiyun * not need to be initialized if its name is NULL.
1445*4882a593Smuzhiyun */
1446*4882a593Smuzhiyun if (indio_dev->channels)
1447*4882a593Smuzhiyun for (i = 0; i < indio_dev->num_channels; i++) {
1448*4882a593Smuzhiyun const struct iio_chan_spec *chan =
1449*4882a593Smuzhiyun &indio_dev->channels[i];
1450*4882a593Smuzhiyun
1451*4882a593Smuzhiyun if (chan->type == IIO_TIMESTAMP)
1452*4882a593Smuzhiyun clk = &dev_attr_current_timestamp_clock.attr;
1453*4882a593Smuzhiyun
1454*4882a593Smuzhiyun ret = iio_device_add_channel_sysfs(indio_dev, chan);
1455*4882a593Smuzhiyun if (ret < 0)
1456*4882a593Smuzhiyun goto error_clear_attrs;
1457*4882a593Smuzhiyun attrcount += ret;
1458*4882a593Smuzhiyun }
1459*4882a593Smuzhiyun
1460*4882a593Smuzhiyun if (iio_dev_opaque->event_interface)
1461*4882a593Smuzhiyun clk = &dev_attr_current_timestamp_clock.attr;
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun if (indio_dev->name)
1464*4882a593Smuzhiyun attrcount++;
1465*4882a593Smuzhiyun if (indio_dev->label)
1466*4882a593Smuzhiyun attrcount++;
1467*4882a593Smuzhiyun if (clk)
1468*4882a593Smuzhiyun attrcount++;
1469*4882a593Smuzhiyun
1470*4882a593Smuzhiyun iio_dev_opaque->chan_attr_group.attrs =
1471*4882a593Smuzhiyun kcalloc(attrcount + 1,
1472*4882a593Smuzhiyun sizeof(iio_dev_opaque->chan_attr_group.attrs[0]),
1473*4882a593Smuzhiyun GFP_KERNEL);
1474*4882a593Smuzhiyun if (iio_dev_opaque->chan_attr_group.attrs == NULL) {
1475*4882a593Smuzhiyun ret = -ENOMEM;
1476*4882a593Smuzhiyun goto error_clear_attrs;
1477*4882a593Smuzhiyun }
1478*4882a593Smuzhiyun /* Copy across original attributes */
1479*4882a593Smuzhiyun if (indio_dev->info->attrs)
1480*4882a593Smuzhiyun memcpy(iio_dev_opaque->chan_attr_group.attrs,
1481*4882a593Smuzhiyun indio_dev->info->attrs->attrs,
1482*4882a593Smuzhiyun sizeof(iio_dev_opaque->chan_attr_group.attrs[0])
1483*4882a593Smuzhiyun *attrcount_orig);
1484*4882a593Smuzhiyun attrn = attrcount_orig;
1485*4882a593Smuzhiyun /* Add all elements from the list. */
1486*4882a593Smuzhiyun list_for_each_entry(p, &iio_dev_opaque->channel_attr_list, l)
1487*4882a593Smuzhiyun iio_dev_opaque->chan_attr_group.attrs[attrn++] = &p->dev_attr.attr;
1488*4882a593Smuzhiyun if (indio_dev->name)
1489*4882a593Smuzhiyun iio_dev_opaque->chan_attr_group.attrs[attrn++] = &dev_attr_name.attr;
1490*4882a593Smuzhiyun if (indio_dev->label)
1491*4882a593Smuzhiyun iio_dev_opaque->chan_attr_group.attrs[attrn++] = &dev_attr_label.attr;
1492*4882a593Smuzhiyun if (clk)
1493*4882a593Smuzhiyun iio_dev_opaque->chan_attr_group.attrs[attrn++] = clk;
1494*4882a593Smuzhiyun
1495*4882a593Smuzhiyun indio_dev->groups[indio_dev->groupcounter++] =
1496*4882a593Smuzhiyun &iio_dev_opaque->chan_attr_group;
1497*4882a593Smuzhiyun
1498*4882a593Smuzhiyun return 0;
1499*4882a593Smuzhiyun
1500*4882a593Smuzhiyun error_clear_attrs:
1501*4882a593Smuzhiyun iio_free_chan_devattr_list(&iio_dev_opaque->channel_attr_list);
1502*4882a593Smuzhiyun
1503*4882a593Smuzhiyun return ret;
1504*4882a593Smuzhiyun }
1505*4882a593Smuzhiyun
iio_device_unregister_sysfs(struct iio_dev * indio_dev)1506*4882a593Smuzhiyun static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
1507*4882a593Smuzhiyun {
1508*4882a593Smuzhiyun struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
1509*4882a593Smuzhiyun
1510*4882a593Smuzhiyun iio_free_chan_devattr_list(&iio_dev_opaque->channel_attr_list);
1511*4882a593Smuzhiyun kfree(iio_dev_opaque->chan_attr_group.attrs);
1512*4882a593Smuzhiyun iio_dev_opaque->chan_attr_group.attrs = NULL;
1513*4882a593Smuzhiyun }
1514*4882a593Smuzhiyun
iio_dev_release(struct device * device)1515*4882a593Smuzhiyun static void iio_dev_release(struct device *device)
1516*4882a593Smuzhiyun {
1517*4882a593Smuzhiyun struct iio_dev *indio_dev = dev_to_iio_dev(device);
1518*4882a593Smuzhiyun struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
1519*4882a593Smuzhiyun
1520*4882a593Smuzhiyun if (indio_dev->modes & INDIO_ALL_TRIGGERED_MODES)
1521*4882a593Smuzhiyun iio_device_unregister_trigger_consumer(indio_dev);
1522*4882a593Smuzhiyun iio_device_unregister_eventset(indio_dev);
1523*4882a593Smuzhiyun iio_device_unregister_sysfs(indio_dev);
1524*4882a593Smuzhiyun
1525*4882a593Smuzhiyun iio_buffer_put(indio_dev->buffer);
1526*4882a593Smuzhiyun
1527*4882a593Smuzhiyun ida_simple_remove(&iio_ida, indio_dev->id);
1528*4882a593Smuzhiyun kfree(iio_dev_opaque);
1529*4882a593Smuzhiyun }
1530*4882a593Smuzhiyun
1531*4882a593Smuzhiyun struct device_type iio_device_type = {
1532*4882a593Smuzhiyun .name = "iio_device",
1533*4882a593Smuzhiyun .release = iio_dev_release,
1534*4882a593Smuzhiyun };
1535*4882a593Smuzhiyun
1536*4882a593Smuzhiyun /**
1537*4882a593Smuzhiyun * iio_device_alloc() - allocate an iio_dev from a driver
1538*4882a593Smuzhiyun * @parent: Parent device.
1539*4882a593Smuzhiyun * @sizeof_priv: Space to allocate for private structure.
1540*4882a593Smuzhiyun **/
iio_device_alloc(struct device * parent,int sizeof_priv)1541*4882a593Smuzhiyun struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv)
1542*4882a593Smuzhiyun {
1543*4882a593Smuzhiyun struct iio_dev_opaque *iio_dev_opaque;
1544*4882a593Smuzhiyun struct iio_dev *dev;
1545*4882a593Smuzhiyun size_t alloc_size;
1546*4882a593Smuzhiyun
1547*4882a593Smuzhiyun alloc_size = sizeof(struct iio_dev_opaque);
1548*4882a593Smuzhiyun if (sizeof_priv) {
1549*4882a593Smuzhiyun alloc_size = ALIGN(alloc_size, IIO_ALIGN);
1550*4882a593Smuzhiyun alloc_size += sizeof_priv;
1551*4882a593Smuzhiyun }
1552*4882a593Smuzhiyun
1553*4882a593Smuzhiyun iio_dev_opaque = kzalloc(alloc_size, GFP_KERNEL);
1554*4882a593Smuzhiyun if (!iio_dev_opaque)
1555*4882a593Smuzhiyun return NULL;
1556*4882a593Smuzhiyun
1557*4882a593Smuzhiyun dev = &iio_dev_opaque->indio_dev;
1558*4882a593Smuzhiyun dev->priv = (char *)iio_dev_opaque +
1559*4882a593Smuzhiyun ALIGN(sizeof(struct iio_dev_opaque), IIO_ALIGN);
1560*4882a593Smuzhiyun
1561*4882a593Smuzhiyun dev->dev.parent = parent;
1562*4882a593Smuzhiyun dev->dev.groups = dev->groups;
1563*4882a593Smuzhiyun dev->dev.type = &iio_device_type;
1564*4882a593Smuzhiyun dev->dev.bus = &iio_bus_type;
1565*4882a593Smuzhiyun device_initialize(&dev->dev);
1566*4882a593Smuzhiyun dev_set_drvdata(&dev->dev, (void *)dev);
1567*4882a593Smuzhiyun mutex_init(&dev->mlock);
1568*4882a593Smuzhiyun mutex_init(&dev->info_exist_lock);
1569*4882a593Smuzhiyun INIT_LIST_HEAD(&iio_dev_opaque->channel_attr_list);
1570*4882a593Smuzhiyun
1571*4882a593Smuzhiyun dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
1572*4882a593Smuzhiyun if (dev->id < 0) {
1573*4882a593Smuzhiyun /* cannot use a dev_err as the name isn't available */
1574*4882a593Smuzhiyun pr_err("failed to get device id\n");
1575*4882a593Smuzhiyun kfree(iio_dev_opaque);
1576*4882a593Smuzhiyun return NULL;
1577*4882a593Smuzhiyun }
1578*4882a593Smuzhiyun dev_set_name(&dev->dev, "iio:device%d", dev->id);
1579*4882a593Smuzhiyun INIT_LIST_HEAD(&iio_dev_opaque->buffer_list);
1580*4882a593Smuzhiyun
1581*4882a593Smuzhiyun return dev;
1582*4882a593Smuzhiyun }
1583*4882a593Smuzhiyun EXPORT_SYMBOL(iio_device_alloc);
1584*4882a593Smuzhiyun
1585*4882a593Smuzhiyun /**
1586*4882a593Smuzhiyun * iio_device_free() - free an iio_dev from a driver
1587*4882a593Smuzhiyun * @dev: the iio_dev associated with the device
1588*4882a593Smuzhiyun **/
iio_device_free(struct iio_dev * dev)1589*4882a593Smuzhiyun void iio_device_free(struct iio_dev *dev)
1590*4882a593Smuzhiyun {
1591*4882a593Smuzhiyun if (dev)
1592*4882a593Smuzhiyun put_device(&dev->dev);
1593*4882a593Smuzhiyun }
1594*4882a593Smuzhiyun EXPORT_SYMBOL(iio_device_free);
1595*4882a593Smuzhiyun
devm_iio_device_release(struct device * dev,void * res)1596*4882a593Smuzhiyun static void devm_iio_device_release(struct device *dev, void *res)
1597*4882a593Smuzhiyun {
1598*4882a593Smuzhiyun iio_device_free(*(struct iio_dev **)res);
1599*4882a593Smuzhiyun }
1600*4882a593Smuzhiyun
1601*4882a593Smuzhiyun /**
1602*4882a593Smuzhiyun * devm_iio_device_alloc - Resource-managed iio_device_alloc()
1603*4882a593Smuzhiyun * @parent: Device to allocate iio_dev for, and parent for this IIO device
1604*4882a593Smuzhiyun * @sizeof_priv: Space to allocate for private structure.
1605*4882a593Smuzhiyun *
1606*4882a593Smuzhiyun * Managed iio_device_alloc. iio_dev allocated with this function is
1607*4882a593Smuzhiyun * automatically freed on driver detach.
1608*4882a593Smuzhiyun *
1609*4882a593Smuzhiyun * RETURNS:
1610*4882a593Smuzhiyun * Pointer to allocated iio_dev on success, NULL on failure.
1611*4882a593Smuzhiyun */
devm_iio_device_alloc(struct device * parent,int sizeof_priv)1612*4882a593Smuzhiyun struct iio_dev *devm_iio_device_alloc(struct device *parent, int sizeof_priv)
1613*4882a593Smuzhiyun {
1614*4882a593Smuzhiyun struct iio_dev **ptr, *iio_dev;
1615*4882a593Smuzhiyun
1616*4882a593Smuzhiyun ptr = devres_alloc(devm_iio_device_release, sizeof(*ptr),
1617*4882a593Smuzhiyun GFP_KERNEL);
1618*4882a593Smuzhiyun if (!ptr)
1619*4882a593Smuzhiyun return NULL;
1620*4882a593Smuzhiyun
1621*4882a593Smuzhiyun iio_dev = iio_device_alloc(parent, sizeof_priv);
1622*4882a593Smuzhiyun if (iio_dev) {
1623*4882a593Smuzhiyun *ptr = iio_dev;
1624*4882a593Smuzhiyun devres_add(parent, ptr);
1625*4882a593Smuzhiyun } else {
1626*4882a593Smuzhiyun devres_free(ptr);
1627*4882a593Smuzhiyun }
1628*4882a593Smuzhiyun
1629*4882a593Smuzhiyun return iio_dev;
1630*4882a593Smuzhiyun }
1631*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(devm_iio_device_alloc);
1632*4882a593Smuzhiyun
1633*4882a593Smuzhiyun /**
1634*4882a593Smuzhiyun * iio_chrdev_open() - chrdev file open for buffer access and ioctls
1635*4882a593Smuzhiyun * @inode: Inode structure for identifying the device in the file system
1636*4882a593Smuzhiyun * @filp: File structure for iio device used to keep and later access
1637*4882a593Smuzhiyun * private data
1638*4882a593Smuzhiyun *
1639*4882a593Smuzhiyun * Return: 0 on success or -EBUSY if the device is already opened
1640*4882a593Smuzhiyun **/
iio_chrdev_open(struct inode * inode,struct file * filp)1641*4882a593Smuzhiyun static int iio_chrdev_open(struct inode *inode, struct file *filp)
1642*4882a593Smuzhiyun {
1643*4882a593Smuzhiyun struct iio_dev *indio_dev = container_of(inode->i_cdev,
1644*4882a593Smuzhiyun struct iio_dev, chrdev);
1645*4882a593Smuzhiyun
1646*4882a593Smuzhiyun if (test_and_set_bit(IIO_BUSY_BIT_POS, &indio_dev->flags))
1647*4882a593Smuzhiyun return -EBUSY;
1648*4882a593Smuzhiyun
1649*4882a593Smuzhiyun iio_device_get(indio_dev);
1650*4882a593Smuzhiyun
1651*4882a593Smuzhiyun filp->private_data = indio_dev;
1652*4882a593Smuzhiyun
1653*4882a593Smuzhiyun return 0;
1654*4882a593Smuzhiyun }
1655*4882a593Smuzhiyun
1656*4882a593Smuzhiyun /**
1657*4882a593Smuzhiyun * iio_chrdev_release() - chrdev file close buffer access and ioctls
1658*4882a593Smuzhiyun * @inode: Inode structure pointer for the char device
1659*4882a593Smuzhiyun * @filp: File structure pointer for the char device
1660*4882a593Smuzhiyun *
1661*4882a593Smuzhiyun * Return: 0 for successful release
1662*4882a593Smuzhiyun */
iio_chrdev_release(struct inode * inode,struct file * filp)1663*4882a593Smuzhiyun static int iio_chrdev_release(struct inode *inode, struct file *filp)
1664*4882a593Smuzhiyun {
1665*4882a593Smuzhiyun struct iio_dev *indio_dev = container_of(inode->i_cdev,
1666*4882a593Smuzhiyun struct iio_dev, chrdev);
1667*4882a593Smuzhiyun clear_bit(IIO_BUSY_BIT_POS, &indio_dev->flags);
1668*4882a593Smuzhiyun iio_device_put(indio_dev);
1669*4882a593Smuzhiyun
1670*4882a593Smuzhiyun return 0;
1671*4882a593Smuzhiyun }
1672*4882a593Smuzhiyun
1673*4882a593Smuzhiyun /* Somewhat of a cross file organization violation - ioctls here are actually
1674*4882a593Smuzhiyun * event related */
iio_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)1675*4882a593Smuzhiyun static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
1676*4882a593Smuzhiyun {
1677*4882a593Smuzhiyun struct iio_dev *indio_dev = filp->private_data;
1678*4882a593Smuzhiyun int __user *ip = (int __user *)arg;
1679*4882a593Smuzhiyun int fd;
1680*4882a593Smuzhiyun
1681*4882a593Smuzhiyun if (!indio_dev->info)
1682*4882a593Smuzhiyun return -ENODEV;
1683*4882a593Smuzhiyun
1684*4882a593Smuzhiyun if (cmd == IIO_GET_EVENT_FD_IOCTL) {
1685*4882a593Smuzhiyun fd = iio_event_getfd(indio_dev);
1686*4882a593Smuzhiyun if (fd < 0)
1687*4882a593Smuzhiyun return fd;
1688*4882a593Smuzhiyun if (copy_to_user(ip, &fd, sizeof(fd)))
1689*4882a593Smuzhiyun return -EFAULT;
1690*4882a593Smuzhiyun return 0;
1691*4882a593Smuzhiyun }
1692*4882a593Smuzhiyun return -EINVAL;
1693*4882a593Smuzhiyun }
1694*4882a593Smuzhiyun
1695*4882a593Smuzhiyun static const struct file_operations iio_buffer_fileops = {
1696*4882a593Smuzhiyun .read = iio_buffer_read_outer_addr,
1697*4882a593Smuzhiyun .release = iio_chrdev_release,
1698*4882a593Smuzhiyun .open = iio_chrdev_open,
1699*4882a593Smuzhiyun .poll = iio_buffer_poll_addr,
1700*4882a593Smuzhiyun .owner = THIS_MODULE,
1701*4882a593Smuzhiyun .llseek = noop_llseek,
1702*4882a593Smuzhiyun .unlocked_ioctl = iio_ioctl,
1703*4882a593Smuzhiyun .compat_ioctl = compat_ptr_ioctl,
1704*4882a593Smuzhiyun };
1705*4882a593Smuzhiyun
iio_check_unique_scan_index(struct iio_dev * indio_dev)1706*4882a593Smuzhiyun static int iio_check_unique_scan_index(struct iio_dev *indio_dev)
1707*4882a593Smuzhiyun {
1708*4882a593Smuzhiyun int i, j;
1709*4882a593Smuzhiyun const struct iio_chan_spec *channels = indio_dev->channels;
1710*4882a593Smuzhiyun
1711*4882a593Smuzhiyun if (!(indio_dev->modes & INDIO_ALL_BUFFER_MODES))
1712*4882a593Smuzhiyun return 0;
1713*4882a593Smuzhiyun
1714*4882a593Smuzhiyun for (i = 0; i < indio_dev->num_channels - 1; i++) {
1715*4882a593Smuzhiyun if (channels[i].scan_index < 0)
1716*4882a593Smuzhiyun continue;
1717*4882a593Smuzhiyun for (j = i + 1; j < indio_dev->num_channels; j++)
1718*4882a593Smuzhiyun if (channels[i].scan_index == channels[j].scan_index) {
1719*4882a593Smuzhiyun dev_err(&indio_dev->dev,
1720*4882a593Smuzhiyun "Duplicate scan index %d\n",
1721*4882a593Smuzhiyun channels[i].scan_index);
1722*4882a593Smuzhiyun return -EINVAL;
1723*4882a593Smuzhiyun }
1724*4882a593Smuzhiyun }
1725*4882a593Smuzhiyun
1726*4882a593Smuzhiyun return 0;
1727*4882a593Smuzhiyun }
1728*4882a593Smuzhiyun
1729*4882a593Smuzhiyun static const struct iio_buffer_setup_ops noop_ring_setup_ops;
1730*4882a593Smuzhiyun
__iio_device_register(struct iio_dev * indio_dev,struct module * this_mod)1731*4882a593Smuzhiyun int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
1732*4882a593Smuzhiyun {
1733*4882a593Smuzhiyun int ret;
1734*4882a593Smuzhiyun
1735*4882a593Smuzhiyun if (!indio_dev->info)
1736*4882a593Smuzhiyun return -EINVAL;
1737*4882a593Smuzhiyun
1738*4882a593Smuzhiyun indio_dev->driver_module = this_mod;
1739*4882a593Smuzhiyun /* If the calling driver did not initialize of_node, do it here */
1740*4882a593Smuzhiyun if (!indio_dev->dev.of_node && indio_dev->dev.parent)
1741*4882a593Smuzhiyun indio_dev->dev.of_node = indio_dev->dev.parent->of_node;
1742*4882a593Smuzhiyun
1743*4882a593Smuzhiyun indio_dev->label = of_get_property(indio_dev->dev.of_node, "label",
1744*4882a593Smuzhiyun NULL);
1745*4882a593Smuzhiyun
1746*4882a593Smuzhiyun ret = iio_check_unique_scan_index(indio_dev);
1747*4882a593Smuzhiyun if (ret < 0)
1748*4882a593Smuzhiyun return ret;
1749*4882a593Smuzhiyun
1750*4882a593Smuzhiyun /* configure elements for the chrdev */
1751*4882a593Smuzhiyun indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
1752*4882a593Smuzhiyun
1753*4882a593Smuzhiyun iio_device_register_debugfs(indio_dev);
1754*4882a593Smuzhiyun
1755*4882a593Smuzhiyun ret = iio_buffer_alloc_sysfs_and_mask(indio_dev);
1756*4882a593Smuzhiyun if (ret) {
1757*4882a593Smuzhiyun dev_err(indio_dev->dev.parent,
1758*4882a593Smuzhiyun "Failed to create buffer sysfs interfaces\n");
1759*4882a593Smuzhiyun goto error_unreg_debugfs;
1760*4882a593Smuzhiyun }
1761*4882a593Smuzhiyun
1762*4882a593Smuzhiyun ret = iio_device_register_sysfs(indio_dev);
1763*4882a593Smuzhiyun if (ret) {
1764*4882a593Smuzhiyun dev_err(indio_dev->dev.parent,
1765*4882a593Smuzhiyun "Failed to register sysfs interfaces\n");
1766*4882a593Smuzhiyun goto error_buffer_free_sysfs;
1767*4882a593Smuzhiyun }
1768*4882a593Smuzhiyun ret = iio_device_register_eventset(indio_dev);
1769*4882a593Smuzhiyun if (ret) {
1770*4882a593Smuzhiyun dev_err(indio_dev->dev.parent,
1771*4882a593Smuzhiyun "Failed to register event set\n");
1772*4882a593Smuzhiyun goto error_free_sysfs;
1773*4882a593Smuzhiyun }
1774*4882a593Smuzhiyun if (indio_dev->modes & INDIO_ALL_TRIGGERED_MODES)
1775*4882a593Smuzhiyun iio_device_register_trigger_consumer(indio_dev);
1776*4882a593Smuzhiyun
1777*4882a593Smuzhiyun if ((indio_dev->modes & INDIO_ALL_BUFFER_MODES) &&
1778*4882a593Smuzhiyun indio_dev->setup_ops == NULL)
1779*4882a593Smuzhiyun indio_dev->setup_ops = &noop_ring_setup_ops;
1780*4882a593Smuzhiyun
1781*4882a593Smuzhiyun cdev_init(&indio_dev->chrdev, &iio_buffer_fileops);
1782*4882a593Smuzhiyun
1783*4882a593Smuzhiyun indio_dev->chrdev.owner = this_mod;
1784*4882a593Smuzhiyun
1785*4882a593Smuzhiyun ret = cdev_device_add(&indio_dev->chrdev, &indio_dev->dev);
1786*4882a593Smuzhiyun if (ret < 0)
1787*4882a593Smuzhiyun goto error_unreg_eventset;
1788*4882a593Smuzhiyun
1789*4882a593Smuzhiyun return 0;
1790*4882a593Smuzhiyun
1791*4882a593Smuzhiyun error_unreg_eventset:
1792*4882a593Smuzhiyun iio_device_unregister_eventset(indio_dev);
1793*4882a593Smuzhiyun error_free_sysfs:
1794*4882a593Smuzhiyun iio_device_unregister_sysfs(indio_dev);
1795*4882a593Smuzhiyun error_buffer_free_sysfs:
1796*4882a593Smuzhiyun iio_buffer_free_sysfs_and_mask(indio_dev);
1797*4882a593Smuzhiyun error_unreg_debugfs:
1798*4882a593Smuzhiyun iio_device_unregister_debugfs(indio_dev);
1799*4882a593Smuzhiyun return ret;
1800*4882a593Smuzhiyun }
1801*4882a593Smuzhiyun EXPORT_SYMBOL(__iio_device_register);
1802*4882a593Smuzhiyun
1803*4882a593Smuzhiyun /**
1804*4882a593Smuzhiyun * iio_device_unregister() - unregister a device from the IIO subsystem
1805*4882a593Smuzhiyun * @indio_dev: Device structure representing the device.
1806*4882a593Smuzhiyun **/
iio_device_unregister(struct iio_dev * indio_dev)1807*4882a593Smuzhiyun void iio_device_unregister(struct iio_dev *indio_dev)
1808*4882a593Smuzhiyun {
1809*4882a593Smuzhiyun cdev_device_del(&indio_dev->chrdev, &indio_dev->dev);
1810*4882a593Smuzhiyun
1811*4882a593Smuzhiyun mutex_lock(&indio_dev->info_exist_lock);
1812*4882a593Smuzhiyun
1813*4882a593Smuzhiyun iio_device_unregister_debugfs(indio_dev);
1814*4882a593Smuzhiyun
1815*4882a593Smuzhiyun iio_disable_all_buffers(indio_dev);
1816*4882a593Smuzhiyun
1817*4882a593Smuzhiyun indio_dev->info = NULL;
1818*4882a593Smuzhiyun
1819*4882a593Smuzhiyun iio_device_wakeup_eventset(indio_dev);
1820*4882a593Smuzhiyun iio_buffer_wakeup_poll(indio_dev);
1821*4882a593Smuzhiyun
1822*4882a593Smuzhiyun mutex_unlock(&indio_dev->info_exist_lock);
1823*4882a593Smuzhiyun
1824*4882a593Smuzhiyun iio_buffer_free_sysfs_and_mask(indio_dev);
1825*4882a593Smuzhiyun }
1826*4882a593Smuzhiyun EXPORT_SYMBOL(iio_device_unregister);
1827*4882a593Smuzhiyun
devm_iio_device_unreg(struct device * dev,void * res)1828*4882a593Smuzhiyun static void devm_iio_device_unreg(struct device *dev, void *res)
1829*4882a593Smuzhiyun {
1830*4882a593Smuzhiyun iio_device_unregister(*(struct iio_dev **)res);
1831*4882a593Smuzhiyun }
1832*4882a593Smuzhiyun
__devm_iio_device_register(struct device * dev,struct iio_dev * indio_dev,struct module * this_mod)1833*4882a593Smuzhiyun int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev,
1834*4882a593Smuzhiyun struct module *this_mod)
1835*4882a593Smuzhiyun {
1836*4882a593Smuzhiyun struct iio_dev **ptr;
1837*4882a593Smuzhiyun int ret;
1838*4882a593Smuzhiyun
1839*4882a593Smuzhiyun ptr = devres_alloc(devm_iio_device_unreg, sizeof(*ptr), GFP_KERNEL);
1840*4882a593Smuzhiyun if (!ptr)
1841*4882a593Smuzhiyun return -ENOMEM;
1842*4882a593Smuzhiyun
1843*4882a593Smuzhiyun *ptr = indio_dev;
1844*4882a593Smuzhiyun ret = __iio_device_register(indio_dev, this_mod);
1845*4882a593Smuzhiyun if (!ret)
1846*4882a593Smuzhiyun devres_add(dev, ptr);
1847*4882a593Smuzhiyun else
1848*4882a593Smuzhiyun devres_free(ptr);
1849*4882a593Smuzhiyun
1850*4882a593Smuzhiyun return ret;
1851*4882a593Smuzhiyun }
1852*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(__devm_iio_device_register);
1853*4882a593Smuzhiyun
1854*4882a593Smuzhiyun /**
1855*4882a593Smuzhiyun * iio_device_claim_direct_mode - Keep device in direct mode
1856*4882a593Smuzhiyun * @indio_dev: the iio_dev associated with the device
1857*4882a593Smuzhiyun *
1858*4882a593Smuzhiyun * If the device is in direct mode it is guaranteed to stay
1859*4882a593Smuzhiyun * that way until iio_device_release_direct_mode() is called.
1860*4882a593Smuzhiyun *
1861*4882a593Smuzhiyun * Use with iio_device_release_direct_mode()
1862*4882a593Smuzhiyun *
1863*4882a593Smuzhiyun * Returns: 0 on success, -EBUSY on failure
1864*4882a593Smuzhiyun */
iio_device_claim_direct_mode(struct iio_dev * indio_dev)1865*4882a593Smuzhiyun int iio_device_claim_direct_mode(struct iio_dev *indio_dev)
1866*4882a593Smuzhiyun {
1867*4882a593Smuzhiyun mutex_lock(&indio_dev->mlock);
1868*4882a593Smuzhiyun
1869*4882a593Smuzhiyun if (iio_buffer_enabled(indio_dev)) {
1870*4882a593Smuzhiyun mutex_unlock(&indio_dev->mlock);
1871*4882a593Smuzhiyun return -EBUSY;
1872*4882a593Smuzhiyun }
1873*4882a593Smuzhiyun return 0;
1874*4882a593Smuzhiyun }
1875*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(iio_device_claim_direct_mode);
1876*4882a593Smuzhiyun
1877*4882a593Smuzhiyun /**
1878*4882a593Smuzhiyun * iio_device_release_direct_mode - releases claim on direct mode
1879*4882a593Smuzhiyun * @indio_dev: the iio_dev associated with the device
1880*4882a593Smuzhiyun *
1881*4882a593Smuzhiyun * Release the claim. Device is no longer guaranteed to stay
1882*4882a593Smuzhiyun * in direct mode.
1883*4882a593Smuzhiyun *
1884*4882a593Smuzhiyun * Use with iio_device_claim_direct_mode()
1885*4882a593Smuzhiyun */
iio_device_release_direct_mode(struct iio_dev * indio_dev)1886*4882a593Smuzhiyun void iio_device_release_direct_mode(struct iio_dev *indio_dev)
1887*4882a593Smuzhiyun {
1888*4882a593Smuzhiyun mutex_unlock(&indio_dev->mlock);
1889*4882a593Smuzhiyun }
1890*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(iio_device_release_direct_mode);
1891*4882a593Smuzhiyun
1892*4882a593Smuzhiyun subsys_initcall(iio_init);
1893*4882a593Smuzhiyun module_exit(iio_exit);
1894*4882a593Smuzhiyun
1895*4882a593Smuzhiyun MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
1896*4882a593Smuzhiyun MODULE_DESCRIPTION("Industrial I/O core");
1897*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1898