diff options
Diffstat (limited to 'drivers/staging/iio')
78 files changed, 21277 insertions, 0 deletions
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio b/drivers/staging/iio/Documentation/sysfs-bus-iio new file mode 100644 index 00000000000..467c49a4725 --- /dev/null +++ b/drivers/staging/iio/Documentation/sysfs-bus-iio | |||
| @@ -0,0 +1,713 @@ | |||
| 1 | What: /sys/bus/iio/devices/deviceX | ||
| 2 | KernelVersion: 2.6.35 | ||
| 3 | Contact: linux-iio@vger.kernel.org | ||
| 4 | Description: | ||
| 5 | Hardware chip or device accessed by on communication port. | ||
| 6 | Corresponds to a grouping of sensor channels. X is the IIO | ||
| 7 | index of the device. | ||
| 8 | |||
| 9 | What: /sys/bus/iio/devices/device[n]/power_state | ||
| 10 | KernelVersion: 2.6.37 | ||
| 11 | Contact: linux-iio@vger.kernel.org | ||
| 12 | Description: | ||
| 13 | This property gets/sets the device power state. | ||
| 14 | |||
| 15 | What: /sys/bus/iio/devices/triggerX | ||
| 16 | KernelVersion: 2.6.35 | ||
| 17 | Contact: linux-iio@vger.kernel.org | ||
| 18 | Description: | ||
| 19 | An event driven driver of data capture to an in kernel buffer. | ||
| 20 | May be provided by a device driver that also has an IIO device | ||
| 21 | based on hardware generated events (e.g. data ready) or | ||
| 22 | provided by a separate driver for other hardware (e.g. | ||
| 23 | periodic timer, GPIO or high resolution timer). | ||
| 24 | Contains trigger type specific elements. These do not | ||
| 25 | generalize well and hence are not documented in this file. | ||
| 26 | X is the IIO index of the trigger. | ||
| 27 | |||
| 28 | What: /sys/bus/iio/devices/deviceX:buffer | ||
| 29 | KernelVersion: 2.6.35 | ||
| 30 | Contact: linux-iio@vger.kernel.org | ||
| 31 | Description: | ||
| 32 | Link to /sys/class/iio/deviceX/deviceX:buffer. X indicates | ||
| 33 | the device with which this buffer buffer is associated. | ||
| 34 | |||
| 35 | What: /sys/bus/iio/devices/deviceX/name | ||
| 36 | KernelVersion: 2.6.35 | ||
| 37 | Contact: linux-iio@vger.kernel.org | ||
| 38 | Description: | ||
| 39 | Description of the physical chip / device for device X. | ||
| 40 | Typically a part number. | ||
| 41 | |||
| 42 | What: /sys/bus/iio/devices/deviceX/sampling_frequency | ||
| 43 | KernelVersion: 2.6.35 | ||
| 44 | Contact: linux-iio@vger.kernel.org | ||
| 45 | Description: | ||
| 46 | Some devices have internal clocks. This parameter sets the | ||
| 47 | resulting sampling frequency. In many devices this | ||
| 48 | parameter has an effect on input filters etc rather than | ||
| 49 | simply controlling when the input is sampled. As this | ||
| 50 | effects datardy triggers, hardware buffers and the sysfs | ||
| 51 | direct access interfaces, it may be found in any of the | ||
| 52 | relevant directories. If it effects all of the above | ||
| 53 | then it is to be found in the base device directory as here. | ||
| 54 | |||
| 55 | What: /sys/bus/iio/devices/deviceX/sampling_frequency_available | ||
| 56 | KernelVersion: 2.6.35 | ||
| 57 | Contact: linux-iio@vger.kernel.org | ||
| 58 | Description: | ||
| 59 | When the internal sampling clock can only take a small | ||
| 60 | discrete set of values, this file lists those available. | ||
| 61 | |||
| 62 | What: /sys/bus/iio/devices/deviceX/range | ||
| 63 | KernelVersion: 2.6.38 | ||
| 64 | Contact: linux-iio@vger.kernel.org | ||
| 65 | Description: | ||
| 66 | Hardware dependent ADC Full Scale Range in mVolt. | ||
| 67 | |||
| 68 | What: /sys/bus/iio/devices/deviceX/range_available | ||
| 69 | KernelVersion: 2.6.38 | ||
| 70 | Contact: linux-iio@vger.kernel.org | ||
| 71 | Description: | ||
| 72 | Hardware dependent supported vales for ADC Full Scale Range. | ||
| 73 | |||
| 74 | What: /sys/bus/iio/devices/deviceX/oversampling_ratio | ||
| 75 | KernelVersion: 2.6.38 | ||
| 76 | Contact: linux-iio@vger.kernel.org | ||
| 77 | Description: | ||
| 78 | Hardware dependent ADC oversampling. Controls the sampling ratio | ||
| 79 | of the digital filter if available. | ||
| 80 | |||
| 81 | What: /sys/bus/iio/devices/deviceX/oversampling_ratio_available | ||
| 82 | KernelVersion: 2.6.38 | ||
| 83 | Contact: linux-iio@vger.kernel.org | ||
| 84 | Description: | ||
| 85 | Hardware dependent values supported by the oversampling filter. | ||
| 86 | |||
| 87 | What: /sys/bus/iio/devices/deviceX/inY_raw | ||
| 88 | What: /sys/bus/iio/devices/deviceX/inY_supply_raw | ||
| 89 | KernelVersion: 2.6.35 | ||
| 90 | Contact: linux-iio@vger.kernel.org | ||
| 91 | Description: | ||
| 92 | Raw (unscaled no bias removal etc) voltage measurement from | ||
| 93 | channel Y. In special cases where the channel does not | ||
| 94 | correspond to externally available input one of the named | ||
| 95 | versions may be used. The number must always be specified and | ||
| 96 | unique to allow association with event codes. | ||
| 97 | |||
| 98 | What: /sys/bus/iio/devices/deviceX/inY-inZ_raw | ||
| 99 | KernelVersion: 2.6.35 | ||
| 100 | Contact: linux-iio@vger.kernel.org | ||
| 101 | Description: | ||
| 102 | Raw (unscaled) differential voltage measurement equivalent to | ||
| 103 | channel Y - channel Z where these channel numbers apply to the | ||
| 104 | physically equivalent inputs when non differential readings are | ||
| 105 | separately available. In differential only parts, then all that | ||
| 106 | is required is a consistent labeling. | ||
| 107 | |||
| 108 | What: /sys/bus/iio/devices/deviceX/temp_raw | ||
| 109 | What: /sys/bus/iio/devices/deviceX/temp_x_raw | ||
| 110 | What: /sys/bus/iio/devices/deviceX/temp_y_raw | ||
| 111 | What: /sys/bus/iio/devices/deviceX/temp_z_raw | ||
| 112 | KernelVersion: 2.6.35 | ||
| 113 | Contact: linux-iio@vger.kernel.org | ||
| 114 | Description: | ||
| 115 | Raw (unscaled no bias removal etc) temperature measurement. | ||
| 116 | It an axis is specified it generally means that the temperature | ||
| 117 | sensor is associated with one part of a compound device (e.g. | ||
| 118 | a gyroscope axis). | ||
| 119 | |||
| 120 | What: /sys/bus/iio/devices/deviceX/tempX_input | ||
| 121 | KernelVersion: 2.6.38 | ||
| 122 | Contact: linux-iio@vger.kernel.org | ||
| 123 | Description: | ||
| 124 | Scaled temperature measurement in milli degrees Celsius. | ||
| 125 | |||
| 126 | What: /sys/bus/iio/devices/deviceX/accel_x_raw | ||
| 127 | What: /sys/bus/iio/devices/deviceX/accel_y_raw | ||
| 128 | What: /sys/bus/iio/devices/deviceX/accel_z_raw | ||
| 129 | KernelVersion: 2.6.35 | ||
| 130 | Contact: linux-iio@vger.kernel.org | ||
| 131 | Description: | ||
| 132 | Acceleration in direction x, y or z (may be arbitrarily assigned | ||
| 133 | but should match other such assignments on device) | ||
| 134 | channel m (not present if only one accelerometer channel at | ||
| 135 | this orientation). Has all of the equivalent parameters as per | ||
| 136 | inY. Units after application of scale and offset are m/s^2. | ||
| 137 | |||
| 138 | What: /sys/bus/iio/devices/deviceX/gyro_x_raw | ||
| 139 | What: /sys/bus/iio/devices/deviceX/gyro_y_raw | ||
| 140 | What: /sys/bus/iio/devices/deviceX/gyro_z_raw | ||
| 141 | KernelVersion: 2.6.35 | ||
| 142 | Contact: linux-iio@vger.kernel.org | ||
| 143 | Description: | ||
| 144 | Angular velocity about axis x, y or z (may be arbitrarily | ||
| 145 | assigned) Data converted by application of offset then scale to | ||
| 146 | radians per second. Has all the equivalent parameters as | ||
| 147 | per inY. | ||
| 148 | |||
| 149 | What: /sys/bus/iio/devices/deviceX/incli_x_raw | ||
| 150 | What: /sys/bus/iio/devices/deviceX/incli_y_raw | ||
| 151 | What: /sys/bus/iio/devices/deviceX/incli_z_raw | ||
| 152 | KernelVersion: 2.6.35 | ||
| 153 | Contact: linux-iio@vger.kernel.org | ||
| 154 | Description: | ||
| 155 | Inclination raw reading about axis x, y or z (may be | ||
| 156 | arbitrarily assigned). Data converted by application of offset | ||
| 157 | and scale to Degrees. | ||
| 158 | |||
| 159 | What: /sys/bus/iio/devices/deviceX/magn_x_raw | ||
| 160 | What: /sys/bus/iio/devices/deviceX/magn_y_raw | ||
| 161 | What: /sys/bus/iio/devices/deviceX/magn_z_raw | ||
| 162 | KernelVersion: 2.6.35 | ||
| 163 | Contact: linux-iio@vger.kernel.org | ||
| 164 | Description: | ||
| 165 | Magnetic field along axis x, y or z (may be arbitrarily | ||
| 166 | assigned) channel m (not present if only one magnetometer | ||
| 167 | at this orientation). Data converted by application of | ||
| 168 | offset then scale to Gauss. Has all the equivalent modifiers | ||
| 169 | as per inY. | ||
| 170 | |||
| 171 | What: /sys/bus/iio/devices/deviceX/accel_x_peak_raw | ||
| 172 | What: /sys/bus/iio/devices/deviceX/accel_y_peak_raw | ||
| 173 | What: /sys/bus/iio/devices/deviceX/accel_z_peak_raw | ||
| 174 | KernelVersion: 2.6.36 | ||
| 175 | Contact: linux-iio@vger.kernel.org | ||
| 176 | Description: | ||
| 177 | Some devices provide a store of the highest value seen since | ||
| 178 | some reset condition. These attributes allow access to this | ||
| 179 | and are otherwise the direct equivalent of the | ||
| 180 | <type>Y[_name]_raw attributes. | ||
| 181 | |||
| 182 | What: /sys/bus/iio/devices/deviceX/accel_xyz_squared_peak_raw | ||
| 183 | KernelVersion: 2.6.36 | ||
| 184 | Contact: linux-iio@vger.kernel.org | ||
| 185 | Description: | ||
| 186 | A computed peak value based on the sum squared magnitude of | ||
| 187 | the underlying value in the specified directions. | ||
| 188 | |||
| 189 | What: /sys/bus/iio/devices/deviceX/accel_offset | ||
| 190 | What: /sys/bus/iio/devices/deviceX/temp_offset | ||
| 191 | KernelVersion: 2.6.35 | ||
| 192 | Contact: linux-iio@vger.kernel.org | ||
| 193 | Description: | ||
| 194 | If known for a device, offset to be added to <type>[Y]_raw prior | ||
| 195 | to scaling by <type>[Y]_scale in order to obtain value in the | ||
| 196 | <type> units as specified in <type>[y]_raw documentation. | ||
| 197 | Not present if the offset is always 0 or unknown. If Y is not | ||
| 198 | present, then the offset applies to all in channels of <type>. | ||
| 199 | May be writable if a variable offset can be applied on the | ||
| 200 | device. Note that this is different to calibbias which | ||
| 201 | is for devices (or drivers) that apply offsets to compensate | ||
| 202 | for variation between different instances of the part, typically | ||
| 203 | adjusted by using some hardware supported calibration procedure. | ||
| 204 | |||
| 205 | What: /sys/bus/iio/devices/deviceX/inY_scale | ||
| 206 | What: /sys/bus/iio/devices/deviceX/inY_supply_scale | ||
| 207 | What: /sys/bus/iio/devices/deviceX/in_scale | ||
| 208 | What: /sys/bus/iio/devices/deviceX/outY_scale | ||
| 209 | What: /sys/bus/iio/devices/deviceX/accel_scale | ||
| 210 | What: /sys/bus/iio/devices/deviceX/accel_peak_scale | ||
| 211 | What: /sys/bus/iio/devices/deviceX/gyro_scale | ||
| 212 | What: /sys/bus/iio/devices/deviceX/magn_scale | ||
| 213 | What: /sys/bus/iio/devices/deviceX/magn_x_scale | ||
| 214 | What: /sys/bus/iio/devices/deviceX/magn_y_scale | ||
| 215 | What: /sys/bus/iio/devices/deviceX/magn_z_scale | ||
| 216 | KernelVersion: 2.6.35 | ||
| 217 | Contact: linux-iio@vger.kernel.org | ||
| 218 | Description: | ||
| 219 | If known for a device, scale to be applied to <type>Y[_name]_raw | ||
| 220 | post addition of <type>[Y][_name]_offset in order to obtain the | ||
| 221 | measured value in <type> units as specified in | ||
| 222 | <type>[Y][_name]_raw documentation.. If shared across all in | ||
| 223 | channels then Y is not present and the value is called | ||
| 224 | <type>[Y][_name]_scale. The peak modifier means this value | ||
| 225 | is applied to <type>Y[_name]_peak_raw values. | ||
| 226 | |||
| 227 | What: /sys/bus/iio/devices/deviceX/accel_x_calibbias | ||
| 228 | What: /sys/bus/iio/devices/deviceX/accel_y_calibbias | ||
| 229 | What: /sys/bus/iio/devices/deviceX/accel_z_calibbias | ||
| 230 | What: /sys/bus/iio/devices/deviceX/gyro_x_calibbias | ||
| 231 | What: /sys/bus/iio/devices/deviceX/gyro_y_calibbias | ||
| 232 | What: /sys/bus/iio/devices/deviceX/gyro_z_calibbias | ||
| 233 | KernelVersion: 2.6.35 | ||
| 234 | Contact: linux-iio@vger.kernel.org | ||
| 235 | Description: | ||
| 236 | Hardware applied calibration offset. (assumed to fix production | ||
| 237 | inaccuracies). If shared across all channels, <type>_calibbias | ||
| 238 | is used. | ||
| 239 | |||
| 240 | What /sys/bus/iio/devices/deviceX/inY_calibscale | ||
| 241 | What /sys/bus/iio/devices/deviceX/inY_supply_calibscale | ||
| 242 | What /sys/bus/iio/devices/deviceX/in_calibscale | ||
| 243 | What /sys/bus/iio/devices/deviceX/accel_x_calibscale | ||
| 244 | What /sys/bus/iio/devices/deviceX/accel_y_calibscale | ||
| 245 | What /sys/bus/iio/devices/deviceX/accel_z_calibscale | ||
| 246 | What /sys/bus/iio/devices/deviceX/gyro_x_calibscale | ||
| 247 | What /sys/bus/iio/devices/deviceX/gyro_y_calibscale | ||
| 248 | What /sys/bus/iio/devices/deviceX/gyro_z_calibscale | ||
| 249 | KernelVersion: 2.6.35 | ||
| 250 | Contact: linux-iio@vger.kernel.org | ||
| 251 | Description: | ||
| 252 | Hardware applied calibration scale factor. (assumed to fix | ||
| 253 | production inaccuracies). If shared across all channels, | ||
| 254 | <type>_calibscale is used. | ||
| 255 | |||
| 256 | What: /sys/bus/iio/devices/deviceX/accel_scale_available | ||
| 257 | KernelVersion: 2.635 | ||
| 258 | Contact: linux-iio@vger.kernel.org | ||
| 259 | Description: | ||
| 260 | If a discrete set of scale values are available, they | ||
| 261 | are listed in this attribute. | ||
| 262 | |||
| 263 | What: /sys/bus/iio/devices/deviceX/outY_raw | ||
| 264 | KernelVersion: 2.6.37 | ||
| 265 | Contact: linux-iio@vger.kernel.org | ||
| 266 | Description: | ||
| 267 | Raw (unscaled, no bias etc.) output voltage for | ||
| 268 | channel Y. The number must always be specified and | ||
| 269 | unique if the output corresponds to a single channel. | ||
| 270 | |||
| 271 | What: /sys/bus/iio/devices/deviceX/outY&Z_raw | ||
| 272 | KernelVersion: 2.6.37 | ||
| 273 | Contact: linux-iio@vger.kernel.org | ||
| 274 | Description: | ||
| 275 | Raw (unscaled, no bias etc.) output voltage for an aggregate of | ||
| 276 | channel Y, channel Z, etc. This interface is available in cases | ||
| 277 | where a single output sets the value for multiple channels | ||
| 278 | simultaneously. | ||
| 279 | |||
| 280 | What: /sys/bus/iio/devices/deviceX/outY_powerdown_mode | ||
| 281 | What: /sys/bus/iio/devices/deviceX/out_powerdown_mode | ||
| 282 | KernelVersion: 2.6.38 | ||
| 283 | Contact: linux-iio@vger.kernel.org | ||
| 284 | Description: | ||
| 285 | Specifies the output powerdown mode. | ||
| 286 | DAC output stage is disconnected from the amplifier and | ||
| 287 | 1kohm_to_gnd: connected to ground via an 1kOhm resistor | ||
| 288 | 100kohm_to_gnd: connected to ground via an 100kOhm resistor | ||
| 289 | three_state: left floating | ||
| 290 | For a list of available output power down options read | ||
| 291 | outX_powerdown_mode_available. If Y is not present the | ||
| 292 | mode is shared across all outputs. | ||
| 293 | |||
| 294 | What: /sys/bus/iio/devices/deviceX/outY_powerdown_mode_available | ||
| 295 | What: /sys/bus/iio/devices/deviceX/out_powerdown_mode_available | ||
| 296 | KernelVersion: 2.6.38 | ||
| 297 | Contact: linux-iio@vger.kernel.org | ||
| 298 | Description: | ||
| 299 | Lists all available output power down modes. | ||
| 300 | If Y is not present the mode is shared across all outputs. | ||
| 301 | |||
| 302 | What: /sys/bus/iio/devices/deviceX/outY_powerdown | ||
| 303 | What: /sys/bus/iio/devices/deviceX/out_powerdown | ||
| 304 | KernelVersion: 2.6.38 | ||
| 305 | Contact: linux-iio@vger.kernel.org | ||
| 306 | Description: | ||
| 307 | Writing 1 causes output Y to enter the power down mode specified | ||
| 308 | by the corresponding outY_powerdown_mode. Clearing returns to | ||
| 309 | normal operation. Y may be suppressed if all outputs are | ||
| 310 | controlled together. | ||
| 311 | |||
| 312 | What: /sys/bus/iio/devices/deviceX/deviceX:eventY | ||
| 313 | KernelVersion: 2.6.35 | ||
| 314 | Contact: linux-iio@vger.kernel.org | ||
| 315 | Description: | ||
| 316 | Configuration of which hardware generated events are passed up | ||
| 317 | to user-space. | ||
| 318 | |||
| 319 | What: /sys/bus/iio/devices/deviceX:event/dev | ||
| 320 | What: /sys/bus/iio/devices/deviceX:eventY/dev | ||
| 321 | KernelVersion: 2.6.35 | ||
| 322 | Contact: linux-iio@vger.kernel.org | ||
| 323 | Description: | ||
| 324 | major:minor character device numbers for the event line Y of | ||
| 325 | device X. | ||
| 326 | |||
| 327 | What: /sys/.../deviceX:eventY/accel_x_thresh_rising_en | ||
| 328 | What: /sys/.../deviceX:eventY/accel_x_thresh_falling_en | ||
| 329 | What: /sys/.../deviceX:eventY/accel_y_thresh_rising_en | ||
| 330 | What: /sys/.../deviceX:eventY/accel_y_thresh_falling_en | ||
| 331 | What: /sys/.../deviceX:eventY/accel_z_thresh_rising_en | ||
| 332 | What: /sys/.../deviceX:eventY/accel_z_thresh_falling_en | ||
| 333 | What: /sys/.../deviceX:eventY/gyro_x_thresh_rising_en | ||
| 334 | What: /sys/.../deviceX:eventY/gyro_x_thresh_falling_en | ||
| 335 | What: /sys/.../deviceX:eventY/gyro_y_thresh_rising_en | ||
| 336 | What: /sys/.../deviceX:eventY/gyro_y_thresh_falling_en | ||
| 337 | What: /sys/.../deviceX:eventY/gyro_z_thresh_rising_en | ||
| 338 | What: /sys/.../deviceX:eventY/gyro_z_thresh_falling_en | ||
| 339 | What: /sys/.../deviceX:eventY/magn_x_thresh_rising_en | ||
| 340 | What: /sys/.../deviceX:eventY/magn_x_thresh_falling_en | ||
| 341 | What: /sys/.../deviceX:eventY/magn_y_thresh_rising_en | ||
| 342 | What: /sys/.../deviceX:eventY/magn_y_thresh_falling_en | ||
| 343 | What: /sys/.../deviceX:eventY/magn_z_thresh_rising_en | ||
| 344 | What: /sys/.../deviceX:eventY/magn_z_thresh_falling_en | ||
| 345 | What: /sys/.../deviceX:eventY/inZ_supply_thresh_rising_en | ||
| 346 | What: /sys/.../deviceX:eventY/inZ_supply_thresh_falling_en | ||
| 347 | What: /sys/.../deviceX:eventY/inZ_thresh_rising_en | ||
| 348 | What: /sys/.../deviceX:eventY/inZ_thresh_falling_en | ||
| 349 | What: /sys/.../deviceX:eventY/temp_thresh_rising_en | ||
| 350 | What: /sys/.../deviceX:eventY/temp_thresh_falling_en | ||
| 351 | KernelVersion: 2.6.37 | ||
| 352 | Contact: linux-iio@vger.kernel.org | ||
| 353 | Description: | ||
| 354 | Event generated when channel passes a threshold in the specified | ||
| 355 | (_rising|_falling) direction. If the direction is not specified, | ||
| 356 | then either the device will report an event which ever direction | ||
| 357 | a single threshold value is called in (e.g. | ||
| 358 | <type>[Z][_name]_<raw|input>_thresh_value) or | ||
| 359 | <type>[Z][_name]_<raw|input>_thresh_rising_value and | ||
| 360 | <type>[Z][_name]_<raw|input>_thresh_falling_value may take | ||
| 361 | different values, but the device can only enable both thresholds | ||
| 362 | or neither. | ||
| 363 | Note the driver will assume the last p events requested are | ||
| 364 | to be enabled where p is however many it supports (which may | ||
| 365 | vary depending on the exact set requested. So if you want to be | ||
| 366 | sure you have set what you think you have, check the contents of | ||
| 367 | these attributes after everything is configured. Drivers may | ||
| 368 | have to buffer any parameters so that they are consistent when | ||
| 369 | a given event type is enabled a future point (and not those for | ||
| 370 | whatever event was previously enabled). | ||
| 371 | |||
| 372 | What: /sys/.../deviceX:eventY/accel_x_roc_rising_en | ||
| 373 | What: /sys/.../deviceX:eventY/accel_x_roc_falling_en | ||
| 374 | What: /sys/.../deviceX:eventY/accel_y_roc_rising_en | ||
| 375 | What: /sys/.../deviceX:eventY/accel_y_roc_falling_en | ||
| 376 | What: /sys/.../deviceX:eventY/accel_z_roc_rising_en | ||
| 377 | What: /sys/.../deviceX:eventY/accel_z_roc_falling_en | ||
| 378 | What: /sys/.../deviceX:eventY/gyro_x_roc_rising_en | ||
| 379 | What: /sys/.../deviceX:eventY/gyro_x_roc_falling_en | ||
| 380 | What: /sys/.../deviceX:eventY/gyro_y_roc_rising_en | ||
| 381 | What: /sys/.../deviceX:eventY/gyro_y_roc_falling_en | ||
| 382 | What: /sys/.../deviceX:eventY/gyro_z_roc_rising_en | ||
| 383 | What: /sys/.../deviceX:eventY/gyro_z_roc_falling_en | ||
| 384 | What: /sys/.../deviceX:eventY/magn_x_roc_rising_en | ||
| 385 | What: /sys/.../deviceX:eventY/magn_x_roc_falling_en | ||
| 386 | What: /sys/.../deviceX:eventY/magn_y_roc_rising_en | ||
| 387 | What: /sys/.../deviceX:eventY/magn_y_roc_falling_en | ||
| 388 | What: /sys/.../deviceX:eventY/magn_z_roc_rising_en | ||
| 389 | What: /sys/.../deviceX:eventY/magn_z_roc_falling_en | ||
| 390 | What: /sys/.../deviceX:eventY/inZ_supply_roc_rising_en | ||
| 391 | What: /sys/.../deviceX:eventY/inZ_supply_roc_falling_en | ||
| 392 | What: /sys/.../deviceX:eventY/inZ_roc_rising_en | ||
| 393 | What: /sys/.../deviceX:eventY/inZ_roc_falling_en | ||
| 394 | What: /sys/.../deviceX:eventY/temp_roc_rising_en | ||
| 395 | What: /sys/.../deviceX:eventY/temp_roc_falling_en | ||
| 396 | KernelVersion: 2.6.37 | ||
| 397 | Contact: linux-iio@vger.kernel.org | ||
| 398 | Description: | ||
| 399 | Event generated when channel passes a threshold on the rate of | ||
| 400 | change (1st differential) in the specified (_rising|_falling) | ||
| 401 | direction. If the direction is not specified, then either the | ||
| 402 | device will report an event which ever direction a single | ||
| 403 | threshold value is called in (e.g. | ||
| 404 | <type>[Z][_name]_<raw|input>_roc_value) or | ||
| 405 | <type>[Z][_name]_<raw|input>_roc_rising_value and | ||
| 406 | <type>[Z][_name]_<raw|input>_roc_falling_value may take | ||
| 407 | different values, but the device can only enable both rate of | ||
| 408 | change thresholds or neither. | ||
| 409 | Note the driver will assume the last p events requested are | ||
| 410 | to be enabled where p is however many it supports (which may | ||
| 411 | vary depending on the exact set requested. So if you want to be | ||
| 412 | sure you have set what you think you have, check the contents of | ||
| 413 | these attributes after everything is configured. Drivers may | ||
| 414 | have to buffer any parameters so that they are consistent when | ||
| 415 | a given event type is enabled a future point (and not those for | ||
| 416 | whatever event was previously enabled). | ||
| 417 | |||
| 418 | What: /sys/.../deviceX:eventY/accel_x_raw_thresh_rising_value | ||
| 419 | What: /sys/.../deviceX:eventY/accel_x_raw_thresh_falling_value | ||
| 420 | What: /sys/.../deviceX:eventY/accel_y_raw_thresh_rising_value | ||
| 421 | What: /sys/.../deviceX:eventY/accel_y_raw_thresh_falling_value | ||
| 422 | What: /sys/.../deviceX:eventY/accel_z_raw_thresh_rising_value | ||
| 423 | What: /sys/.../deviceX:eventY/accel_z_raw_thresh_falling_value | ||
| 424 | What: /sys/.../deviceX:eventY/gyro_x_raw_thresh_rising_value | ||
| 425 | What: /sys/.../deviceX:eventY/gyro_x_raw_thresh_falling_value | ||
| 426 | What: /sys/.../deviceX:eventY/gyro_y_raw_thresh_rising_value | ||
| 427 | What: /sys/.../deviceX:eventY/gyro_y_raw_thresh_falling_value | ||
| 428 | What: /sys/.../deviceX:eventY/gyro_z_raw_thresh_rising_value | ||
| 429 | What: /sys/.../deviceX:eventY/gyro_z_raw_thresh_falling_value | ||
| 430 | What: /sys/.../deviceX:eventY/magn_x_raw_thresh_rising_value | ||
| 431 | What: /sys/.../deviceX:eventY/magn_x_raw_thresh_falling_value | ||
| 432 | What: /sys/.../deviceX:eventY/magn_y_raw_thresh_rising_value | ||
| 433 | What: /sys/.../deviceX:eventY/magn_y_raw_thresh_falling_value | ||
| 434 | What: /sys/.../deviceX:eventY/magn_z_raw_thresh_rising_value | ||
| 435 | What: /sys/.../deviceX:eventY/magn_z_raw_thresh_falling_value | ||
| 436 | What: /sys/.../deviceX:eventY/inZ_supply_raw_thresh_rising_value | ||
| 437 | What: /sys/.../deviceX:eventY/inZ_supply_raw_thresh_falling_value | ||
| 438 | What: /sys/.../deviceX:eventY/inZ_raw_thresh_falling_value | ||
| 439 | What: /sys/.../deviceX:eventY/inZ_raw_thresh_falling_value | ||
| 440 | What: /sys/.../deviceX:eventY/temp_raw_thresh_falling_value | ||
| 441 | What: /sys/.../deviceX:eventY/temp_raw_thresh_falling_value | ||
| 442 | KernelVersion: 2.6.37 | ||
| 443 | Contact: linux-iio@vger.kernel.org | ||
| 444 | Description: | ||
| 445 | Specifies the value of threshold that the device is comparing | ||
| 446 | against for the events enabled by | ||
| 447 | <type>Z[_name]_thresh[_rising|falling]_en. | ||
| 448 | If separate attributes exist for the two directions, but | ||
| 449 | direction is not specified for this attribute, then a single | ||
| 450 | threshold value applies to both directions. | ||
| 451 | The raw or input element of the name indicates whether the | ||
| 452 | value is in raw device units or in processed units (as _raw | ||
| 453 | and _input do on sysfs direct channel read attributes). | ||
| 454 | |||
| 455 | What: /sys/.../deviceX:eventY/accel_x_raw_roc_rising_value | ||
| 456 | What: /sys/.../deviceX:eventY/accel_x_raw_roc_falling_value | ||
| 457 | What: /sys/.../deviceX:eventY/accel_y_raw_roc_rising_value | ||
| 458 | What: /sys/.../deviceX:eventY/accel_y_raw_roc_falling_value | ||
| 459 | What: /sys/.../deviceX:eventY/accel_z_raw_roc_rising_value | ||
| 460 | What: /sys/.../deviceX:eventY/accel_z_raw_roc_falling_value | ||
| 461 | What: /sys/.../deviceX:eventY/gyro_x_raw_roc_rising_value | ||
| 462 | What: /sys/.../deviceX:eventY/gyro_x_raw_roc_falling_value | ||
| 463 | What: /sys/.../deviceX:eventY/gyro_y_raw_roc_rising_value | ||
| 464 | What: /sys/.../deviceX:eventY/gyro_y_raw_roc_falling_value | ||
| 465 | What: /sys/.../deviceX:eventY/gyro_z_raw_roc_rising_value | ||
| 466 | What: /sys/.../deviceX:eventY/gyro_z_raw_roc_falling_value | ||
| 467 | What: /sys/.../deviceX:eventY/magn_x_raw_roc_rising_value | ||
| 468 | What: /sys/.../deviceX:eventY/magn_x_raw_roc_falling_value | ||
| 469 | What: /sys/.../deviceX:eventY/magn_y_raw_roc_rising_value | ||
| 470 | What: /sys/.../deviceX:eventY/magn_y_raw_roc_falling_value | ||
| 471 | What: /sys/.../deviceX:eventY/magn_z_raw_roc_rising_value | ||
| 472 | What: /sys/.../deviceX:eventY/magn_z_raw_roc_falling_value | ||
| 473 | What: /sys/.../deviceX:eventY/inZ_supply_raw_roc_rising_value | ||
| 474 | What: /sys/.../deviceX:eventY/inZ_supply_raw_roc_falling_value | ||
| 475 | What: /sys/.../deviceX:eventY/inZ_raw_roc_falling_value | ||
| 476 | What: /sys/.../deviceX:eventY/inZ_raw_roc_falling_value | ||
| 477 | What: /sys/.../deviceX:eventY/temp_raw_roc_falling_value | ||
| 478 | What: /sys/.../deviceX:eventY/temp_raw_roc_falling_value | ||
| 479 | KernelVersion: 2.6.37 | ||
| 480 | Contact: linux-iio@vger.kernel.org | ||
| 481 | Description: | ||
| 482 | Specifies the value of rate of change threshold that the | ||
| 483 | device is comparing against for the events enabled by | ||
| 484 | <type>[Z][_name]_roc[_rising|falling]_en. | ||
| 485 | If separate attributes exist for the two directions, | ||
| 486 | but direction is not specified for this attribute, | ||
| 487 | then a single threshold value applies to both directions. | ||
| 488 | The raw or input element of the name indicates whether the | ||
| 489 | value is in raw device units or in processed units (as _raw | ||
| 490 | and _input do on sysfs direct channel read attributes). | ||
| 491 | |||
| 492 | What: /sys/.../deviceX:eventY/accel_x_thresh_rising_period | ||
| 493 | What: /sys/.../deviceX:eventY/accel_x_thresh_falling_period | ||
| 494 | hat: /sys/.../deviceX:eventY/accel_x_roc_rising_period | ||
| 495 | What: /sys/.../deviceX:eventY/accel_x_roc_falling_period | ||
| 496 | What: /sys/.../deviceX:eventY/accel_y_thresh_rising_period | ||
| 497 | What: /sys/.../deviceX:eventY/accel_y_thresh_falling_period | ||
| 498 | What: /sys/.../deviceX:eventY/accel_y_roc_rising_period | ||
| 499 | What: /sys/.../deviceX:eventY/accel_y_roc_falling_period | ||
| 500 | What: /sys/.../deviceX:eventY/accel_z_thresh_rising_period | ||
| 501 | What: /sys/.../deviceX:eventY/accel_z_thresh_falling_period | ||
| 502 | What: /sys/.../deviceX:eventY/accel_z_roc_rising_period | ||
| 503 | What: /sys/.../deviceX:eventY/accel_z_roc_falling_period | ||
| 504 | What: /sys/.../deviceX:eventY/gyro_x_thresh_rising_period | ||
| 505 | What: /sys/.../deviceX:eventY/gyro_x_thresh_falling_period | ||
| 506 | What: /sys/.../deviceX:eventY/gyro_x_roc_rising_period | ||
| 507 | What: /sys/.../deviceX:eventY/gyro_x_roc_falling_period | ||
| 508 | What: /sys/.../deviceX:eventY/gyro_y_thresh_rising_period | ||
| 509 | What: /sys/.../deviceX:eventY/gyro_y_thresh_falling_period | ||
| 510 | What: /sys/.../deviceX:eventY/gyro_y_roc_rising_period | ||
| 511 | What: /sys/.../deviceX:eventY/gyro_y_roc_falling_period | ||
| 512 | What: /sys/.../deviceX:eventY/gyro_z_thresh_rising_period | ||
| 513 | What: /sys/.../deviceX:eventY/gyro_z_thresh_falling_period | ||
| 514 | What: /sys/.../deviceX:eventY/gyro_z_roc_rising_period | ||
| 515 | What: /sys/.../deviceX:eventY/gyro_z_roc_falling_period | ||
| 516 | What: /sys/.../deviceX:eventY/magn_x_thresh_rising_period | ||
| 517 | What: /sys/.../deviceX:eventY/magn_x_thresh_falling_period | ||
| 518 | What: /sys/.../deviceX:eventY/magn_x_roc_rising_period | ||
| 519 | What: /sys/.../deviceX:eventY/magn_x_roc_falling_period | ||
| 520 | What: /sys/.../deviceX:eventY/magn_y_thresh_rising_period | ||
| 521 | What: /sys/.../deviceX:eventY/magn_y_thresh_falling_period | ||
| 522 | What: /sys/.../deviceX:eventY/magn_y_roc_rising_period | ||
| 523 | What: /sys/.../deviceX:eventY/magn_y_roc_falling_period | ||
| 524 | What: /sys/.../deviceX:eventY/magn_z_thresh_rising_period | ||
| 525 | What: /sys/.../deviceX:eventY/magn_z_thresh_falling_period | ||
| 526 | What: /sys/.../deviceX:eventY/magn_z_roc_rising_period | ||
| 527 | What: /sys/.../deviceX:eventY/magn_z_roc_falling_period | ||
| 528 | What: /sys/.../deviceX:eventY/inZ_supply_thresh_rising_period | ||
| 529 | What: /sys/.../deviceX:eventY/inZ_supply_thresh_falling_period | ||
| 530 | What: /sys/.../deviceX:eventY/inz_supply_roc_rising_period | ||
| 531 | What: /sys/.../deviceX:eventY/inZ_supply_roc_falling_period | ||
| 532 | What: /sys/.../deviceX:eventY/inZ_thresh_rising_period | ||
| 533 | What: /sys/.../deviceX:eventY/inZ_thresh_falling_period | ||
| 534 | What: /sys/.../deviceX:eventY/inZ_roc_rising_period | ||
| 535 | What: /sys/.../deviceX:eventY/inZ_roc_falling_period | ||
| 536 | What: /sys/.../deviceX:eventY/temp_thresh_rising_period | ||
| 537 | What: /sys/.../deviceX:eventY/temp_thresh_falling_period | ||
| 538 | What: /sys/.../deviceX:eventY/temp_roc_rising_period | ||
| 539 | What: /sys/.../deviceX:eventY/temp_roc_falling_period | ||
| 540 | What: /sys/.../deviceX:eventY/accel_x&y&z_mag_falling_period | ||
| 541 | KernelVersion: 2.6.37 | ||
| 542 | Contact: linux-iio@vger.kernel.org | ||
| 543 | Description: | ||
| 544 | Period of time (in seconds) for which the condition must be | ||
| 545 | met before an event is generated. If direction is not | ||
| 546 | specified then this period applies to both directions. | ||
| 547 | |||
| 548 | What: /sys/.../deviceX:eventY/accel_mag_en | ||
| 549 | What: /sys/.../deviceX:eventY/accel_mag_rising_en | ||
| 550 | What: /sys/.../deviceX:eventY/accel_mag_falling_en | ||
| 551 | What: /sys/.../deviceX:eventY/accel_x_mag_en | ||
| 552 | What: /sys/.../deviceX:eventY/accel_x_mag_rising_en | ||
| 553 | What: /sys/.../deviceX:eventY/accel_x_mag_falling_en | ||
| 554 | What: /sys/.../deviceX:eventY/accel_y_mag_en | ||
| 555 | What: /sys/.../deviceX:eventY/accel_y_mag_rising_en | ||
| 556 | What: /sys/.../deviceX:eventY/accel_y_mag_falling_en | ||
| 557 | What: /sys/.../deviceX:eventY/accel_z_mag_en | ||
| 558 | What: /sys/.../deviceX:eventY/accel_z_mag_rising_en | ||
| 559 | What: /sys/.../deviceX:eventY/accel_z_mag_falling_en | ||
| 560 | What: /sys/.../deviceX:eventY/accel_x&y&z_mag_rising_en | ||
| 561 | What: /sys/.../deviceX:eventY/accel_x&y&z_mag_falling_en | ||
| 562 | KernelVersion: 2.6.37 | ||
| 563 | Contact: linux-iio@vger.kernel.org | ||
| 564 | Description: | ||
| 565 | Similar to accel_x_thresh[_rising|_falling]_en, but here the | ||
| 566 | magnitude of the channel is compared to the threshold, not its | ||
| 567 | signed value. | ||
| 568 | |||
| 569 | What: /sys/.../accel_raw_mag_value | ||
| 570 | What: /sys/.../accel_x_raw_mag_rising_value | ||
| 571 | What: /sys/.../accel_y_raw_mag_rising_value | ||
| 572 | What: /sys/.../accel_z_raw_mag_rising_value | ||
| 573 | KernelVersion: 2.6.37 | ||
| 574 | Contact: linux-iio@vger.kernel.org | ||
| 575 | Description: | ||
| 576 | The value to which the magnitude of the channel is compared. If | ||
| 577 | number or direction is not specified, applies to all channels of | ||
| 578 | this type. | ||
| 579 | |||
| 580 | What: /sys/bus/iio/devices/deviceX:buffer:event/dev | ||
| 581 | KernelVersion: 2.6.35 | ||
| 582 | Contact: linux-iio@vger.kernel.org | ||
| 583 | Description: | ||
| 584 | Buffer for device X event character device major:minor numbers. | ||
| 585 | |||
| 586 | What: /sys/bus/iio/devices/deviceX:buffer:access/dev | ||
| 587 | KernelVersion: 2.6.35 | ||
| 588 | Contact: linux-iio@vger.kernel.org | ||
| 589 | Description: | ||
| 590 | Buffer for device X access character device major:minor numbers. | ||
| 591 | |||
| 592 | What: /sys/bus/iio/devices/deviceX:buffer/trigger | ||
| 593 | KernelVersion: 2.6.35 | ||
| 594 | Contact: linux-iio@vger.kernel.org | ||
| 595 | Description: | ||
| 596 | The name of the trigger source being used, as per string given | ||
| 597 | in /sys/class/iio/triggerY/name. | ||
| 598 | |||
| 599 | What: /sys/bus/iio/devices/deviceX:buffer/length | ||
| 600 | KernelVersion: 2.6.35 | ||
| 601 | Contact: linux-iio@vger.kernel.org | ||
| 602 | Description: | ||
| 603 | Number of scans contained by the buffer. | ||
| 604 | |||
| 605 | What: /sys/bus/iio/devices/deviceX:buffer/bytes_per_datum | ||
| 606 | KernelVersion: 2.6.37 | ||
| 607 | Contact: linux-iio@vger.kernel.org | ||
| 608 | Description: | ||
| 609 | Bytes per scan. Due to alignment fun, the scan may be larger | ||
| 610 | than implied directly by the scan_element parameters. | ||
| 611 | |||
| 612 | What: /sys/bus/iio/devices/deviceX:buffer/enable | ||
| 613 | KernelVersion: 2.6.35 | ||
| 614 | Contact: linux-iio@vger.kernel.org | ||
| 615 | Description: | ||
| 616 | Actually start the buffer capture up. Will start trigger | ||
| 617 | if first device and appropriate. | ||
| 618 | |||
| 619 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements | ||
| 620 | KernelVersion: 2.6.37 | ||
| 621 | Contact: linux-iio@vger.kernel.org | ||
| 622 | Description: | ||
| 623 | Directory containing interfaces for elements that will be | ||
| 624 | captured for a single triggered sample set in the buffer. | ||
| 625 | |||
| 626 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_x_en | ||
| 627 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_y_en | ||
| 628 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_z_en | ||
| 629 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_x_en | ||
| 630 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_y_en | ||
| 631 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_z_en | ||
| 632 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_x_en | ||
| 633 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_y_en | ||
| 634 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_z_en | ||
| 635 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/timestamp_en | ||
| 636 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY_supply_en | ||
| 637 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY_en | ||
| 638 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY-inZ_en | ||
| 639 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_x_en | ||
| 640 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_y_en | ||
| 641 | KernelVersion: 2.6.37 | ||
| 642 | Contact: linux-iio@vger.kernel.org | ||
| 643 | Description: | ||
| 644 | Scan element control for triggered data capture. | ||
| 645 | |||
| 646 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_type | ||
| 647 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_type | ||
| 648 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_type | ||
| 649 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_type | ||
| 650 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY_type | ||
| 651 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/in-in_type | ||
| 652 | What: /sys/.../deviceX:buffer/scan_elements/inY_supply_type | ||
| 653 | What: /sys/.../deviceX:buffer/scan_elements/timestamp_type | ||
| 654 | KernelVersion: 2.6.37 | ||
| 655 | Contact: linux-iio@vger.kernel.org | ||
| 656 | Description: | ||
| 657 | Description of the scan element data storage within the buffer | ||
| 658 | and hence the form in which it is read from user-space. | ||
| 659 | Form is [s|u]bits/storagebits[>>shift]. s or u specifies if | ||
| 660 | signed (2's complement) or unsigned. bits is the number of bits | ||
| 661 | of data and storagebits is the space (after padding) that it | ||
| 662 | occupies in the buffer. shift if specified, is the shift that | ||
| 663 | needs to be applied prior to masking out unused bits. Some | ||
| 664 | devices put their data in the middle of the transferred elements | ||
| 665 | with additional information on both sides. Note that some | ||
| 666 | devices will have additional information in the unused bits | ||
| 667 | so to get a clean value, the bits value must be used to mask | ||
| 668 | the buffer output value appropriately. The storagebits value | ||
| 669 | also specifies the data alignment. So s48/64>>2 will be a | ||
| 670 | signed 48 bit integer stored in a 64 bit location aligned to | ||
| 671 | a a64 bit boundary. To obtain the clean value, shift right 2 | ||
| 672 | and apply a mask to zero the top 16 bits of the result. | ||
| 673 | For other storage combinations this attribute will be extended | ||
| 674 | appropriately. | ||
| 675 | |||
| 676 | What: /sys/.../deviceX:buffer/scan_elements/accel_type_available | ||
| 677 | KernelVersion: 2.6.37 | ||
| 678 | Contact: linux-iio@vger.kernel.org | ||
| 679 | Description: | ||
| 680 | If the type parameter can take one of a small set of values, | ||
| 681 | this attribute lists them. | ||
| 682 | |||
| 683 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/inY_index | ||
| 684 | What: /sys/.../deviceX:buffer/scan_elements/inY_supply_index | ||
| 685 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_x_index | ||
| 686 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_y_index | ||
| 687 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/accel_z_index | ||
| 688 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_x_index | ||
| 689 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_y_index | ||
| 690 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/gyro_z_index | ||
| 691 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_x_index | ||
| 692 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_y_index | ||
| 693 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/magn_z_index | ||
| 694 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_x_index | ||
| 695 | What: /sys/bus/iio/devices/deviceX:buffer/scan_elements/incli_y_index | ||
| 696 | What: /sys/.../deviceX:buffer/scan_elements/timestamp_index | ||
| 697 | KernelVersion: 2.6.37 | ||
| 698 | Contact: linux-iio@vger.kernel.org | ||
| 699 | Description: | ||
| 700 | A single positive integer specifying the position of this | ||
| 701 | scan element in the buffer. Note these are not dependent on | ||
| 702 | what is enabled and may not be contiguous. Thus for user-space | ||
| 703 | to establish the full layout these must be used in conjunction | ||
| 704 | with all _en attributes to establish which channels are present, | ||
| 705 | and the relevant _type attributes to establish the data storage | ||
| 706 | format. | ||
| 707 | |||
| 708 | What: /sys/bus/iio/devices/deviceX/gyro_z_quadrature_correction_raw | ||
| 709 | KernelVersion: 2.6.38 | ||
| 710 | Contact: linux-iio@xxxxxxxxxxxxxxx | ||
| 711 | Description: | ||
| 712 | This attribute is used to read the amount of quadrature error | ||
| 713 | present in the device at a given time. | ||
diff --git a/drivers/staging/iio/accel/accel.h b/drivers/staging/iio/accel/accel.h new file mode 100644 index 00000000000..50651f835ce --- /dev/null +++ b/drivers/staging/iio/accel/accel.h | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | |||
| 2 | #include "../sysfs.h" | ||
| 3 | |||
| 4 | /* Accelerometer types of attribute */ | ||
| 5 | #define IIO_DEV_ATTR_ACCEL_OFFSET(_mode, _show, _store, _addr) \ | ||
| 6 | IIO_DEVICE_ATTR(accel_offset, _mode, _show, _store, _addr) | ||
| 7 | |||
| 8 | #define IIO_DEV_ATTR_ACCEL_X_OFFSET(_mode, _show, _store, _addr) \ | ||
| 9 | IIO_DEVICE_ATTR(accel_x_offset, _mode, _show, _store, _addr) | ||
| 10 | |||
| 11 | #define IIO_DEV_ATTR_ACCEL_Y_OFFSET(_mode, _show, _store, _addr) \ | ||
| 12 | IIO_DEVICE_ATTR(accel_y_offset, _mode, _show, _store, _addr) | ||
| 13 | |||
| 14 | #define IIO_DEV_ATTR_ACCEL_Z_OFFSET(_mode, _show, _store, _addr) \ | ||
| 15 | IIO_DEVICE_ATTR(accel_z_offset, _mode, _show, _store, _addr) | ||
| 16 | |||
| 17 | #define IIO_CONST_ATTR_ACCEL_SCALE(_string) \ | ||
| 18 | IIO_CONST_ATTR(accel_scale, _string) | ||
| 19 | |||
| 20 | #define IIO_DEV_ATTR_ACCEL_SCALE(_mode, _show, _store, _addr) \ | ||
| 21 | IIO_DEVICE_ATTR(accel_scale, _mode, _show, _store, _addr) | ||
| 22 | |||
| 23 | #define IIO_DEV_ATTR_ACCEL_X_SCALE(_mode, _show, _store, _addr) \ | ||
| 24 | IIO_DEVICE_ATTR(accel_x_scale, _mode, _show, _store, _addr) | ||
| 25 | |||
| 26 | #define IIO_DEV_ATTR_ACCEL_Y_SCALE(_mode, _show, _store, _addr) \ | ||
| 27 | IIO_DEVICE_ATTR(accel_y_scale, _mode, _show, _store, _addr) | ||
| 28 | |||
| 29 | #define IIO_DEV_ATTR_ACCEL_Z_SCALE(_mode, _show, _store, _addr) \ | ||
| 30 | IIO_DEVICE_ATTR(accel_z_scale, _mode, _show, _store, _addr) | ||
| 31 | |||
| 32 | #define IIO_DEV_ATTR_ACCEL_CALIBBIAS(_mode, _show, _store, _addr) \ | ||
| 33 | IIO_DEVICE_ATTR(accel_calibbias, _mode, _show, _store, _addr) | ||
| 34 | |||
| 35 | #define IIO_DEV_ATTR_ACCEL_X_CALIBBIAS(_mode, _show, _store, _addr) \ | ||
| 36 | IIO_DEVICE_ATTR(accel_x_calibbias, _mode, _show, _store, _addr) | ||
| 37 | |||
| 38 | #define IIO_DEV_ATTR_ACCEL_Y_CALIBBIAS(_mode, _show, _store, _addr) \ | ||
| 39 | IIO_DEVICE_ATTR(accel_y_calibbias, _mode, _show, _store, _addr) | ||
| 40 | |||
| 41 | #define IIO_DEV_ATTR_ACCEL_Z_CALIBBIAS(_mode, _show, _store, _addr) \ | ||
| 42 | IIO_DEVICE_ATTR(accel_z_calibbias, _mode, _show, _store, _addr) | ||
| 43 | |||
| 44 | #define IIO_DEV_ATTR_ACCEL_CALIBSCALE(_mode, _show, _store, _addr) \ | ||
| 45 | IIO_DEVICE_ATTR(accel_calibscale, _mode, _show, _store, _addr) | ||
| 46 | |||
| 47 | #define IIO_DEV_ATTR_ACCEL_X_CALIBSCALE(_mode, _show, _store, _addr) \ | ||
| 48 | IIO_DEVICE_ATTR(accel_x_calibscale, _mode, _show, _store, _addr) | ||
| 49 | |||
| 50 | #define IIO_DEV_ATTR_ACCEL_Y_CALIBSCALE(_mode, _show, _store, _addr) \ | ||
| 51 | IIO_DEVICE_ATTR(accel_y_calibscale, _mode, _show, _store, _addr) | ||
| 52 | |||
| 53 | #define IIO_DEV_ATTR_ACCEL_Z_CALIBSCALE(_mode, _show, _store, _addr) \ | ||
| 54 | IIO_DEVICE_ATTR(accel_z_calibscale, _mode, _show, _store, _addr) | ||
| 55 | |||
| 56 | #define IIO_DEV_ATTR_ACCEL(_show, _addr) \ | ||
| 57 | IIO_DEVICE_ATTR(accel_raw, S_IRUGO, _show, NULL, _addr) | ||
| 58 | |||
| 59 | #define IIO_DEV_ATTR_ACCEL_X(_show, _addr) \ | ||
| 60 | IIO_DEVICE_ATTR(accel_x_raw, S_IRUGO, _show, NULL, _addr) | ||
| 61 | |||
| 62 | #define IIO_DEV_ATTR_ACCEL_Y(_show, _addr) \ | ||
| 63 | IIO_DEVICE_ATTR(accel_y_raw, S_IRUGO, _show, NULL, _addr) | ||
| 64 | |||
| 65 | #define IIO_DEV_ATTR_ACCEL_Z(_show, _addr) \ | ||
| 66 | IIO_DEVICE_ATTR(accel_z_raw, S_IRUGO, _show, NULL, _addr) | ||
| 67 | |||
| 68 | #define IIO_DEV_ATTR_ACCEL_XY(_show, _addr) \ | ||
| 69 | IIO_DEVICE_ATTR(accel_xy, S_IRUGO, _show, NULL, _addr) | ||
| 70 | |||
| 71 | #define IIO_DEV_ATTR_ACCEL_PEAK(_show, _addr) \ | ||
| 72 | IIO_DEVICE_ATTR(accel_peak, S_IRUGO, _show, NULL, _addr) | ||
| 73 | |||
| 74 | #define IIO_DEV_ATTR_ACCEL_XPEAK(_show, _addr) \ | ||
| 75 | IIO_DEVICE_ATTR(accel_xpeak, S_IRUGO, _show, NULL, _addr) | ||
| 76 | |||
| 77 | #define IIO_DEV_ATTR_ACCEL_YPEAK(_show, _addr) \ | ||
| 78 | IIO_DEVICE_ATTR(accel_ypeak, S_IRUGO, _show, NULL, _addr) | ||
| 79 | |||
| 80 | #define IIO_DEV_ATTR_ACCEL_ZPEAK(_show, _addr) \ | ||
| 81 | IIO_DEVICE_ATTR(accel_zpeak, S_IRUGO, _show, NULL, _addr) | ||
| 82 | |||
| 83 | #define IIO_DEV_ATTR_ACCEL_XYPEAK(_show, _addr) \ | ||
| 84 | IIO_DEVICE_ATTR(accel_xypeak, S_IRUGO, _show, NULL, _addr) | ||
| 85 | |||
| 86 | #define IIO_DEV_ATTR_ACCEL_XYZPEAK(_show, _addr) \ | ||
| 87 | IIO_DEVICE_ATTR(accel_xyzpeak, S_IRUGO, _show, NULL, _addr) | ||
diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c new file mode 100644 index 00000000000..66e708ddf8b --- /dev/null +++ b/drivers/staging/iio/accel/adis16201_ring.c | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | #include <linux/interrupt.h> | ||
| 2 | #include <linux/irq.h> | ||
| 3 | #include <linux/mutex.h> | ||
| 4 | #include <linux/device.h> | ||
| 5 | #include <linux/kernel.h> | ||
| 6 | #include <linux/spi/spi.h> | ||
| 7 | #include <linux/slab.h> | ||
| 8 | #include <linux/sysfs.h> | ||
| 9 | |||
| 10 | #include "../iio.h" | ||
| 11 | #include "../sysfs.h" | ||
| 12 | #include "../ring_sw.h" | ||
| 13 | #include "accel.h" | ||
| 14 | #include "../trigger.h" | ||
| 15 | #include "adis16201.h" | ||
| 16 | |||
| 17 | |||
| 18 | /** | ||
| 19 | * adis16201_read_ring_data() read data registers which will be placed into ring | ||
| 20 | * @dev: device associated with child of actual device (iio_dev or iio_trig) | ||
| 21 | * @rx: somewhere to pass back the value read | ||
| 22 | **/ | ||
| 23 | static int adis16201_read_ring_data(struct iio_dev *indio_dev, u8 *rx) | ||
| 24 | { | ||
| 25 | struct spi_message msg; | ||
| 26 | struct adis16201_state *st = iio_priv(indio_dev); | ||
| 27 | struct spi_transfer xfers[ADIS16201_OUTPUTS + 1]; | ||
| 28 | int ret; | ||
| 29 | int i; | ||
| 30 | |||
| 31 | mutex_lock(&st->buf_lock); | ||
| 32 | |||
| 33 | spi_message_init(&msg); | ||
| 34 | |||
| 35 | memset(xfers, 0, sizeof(xfers)); | ||
| 36 | for (i = 0; i <= ADIS16201_OUTPUTS; i++) { | ||
| 37 | xfers[i].bits_per_word = 8; | ||
| 38 | xfers[i].cs_change = 1; | ||
| 39 | xfers[i].len = 2; | ||
| 40 | xfers[i].delay_usecs = 20; | ||
| 41 | xfers[i].tx_buf = st->tx + 2 * i; | ||
| 42 | st->tx[2 * i] = ADIS16201_READ_REG(ADIS16201_SUPPLY_OUT + | ||
| 43 | 2 * i); | ||
| 44 | st->tx[2 * i + 1] = 0; | ||
| 45 | if (i >= 1) | ||
| 46 | xfers[i].rx_buf = rx + 2 * (i - 1); | ||
| 47 | spi_message_add_tail(&xfers[i], &msg); | ||
| 48 | } | ||
| 49 | |||
| 50 | ret = spi_sync(st->us, &msg); | ||
| 51 | if (ret) | ||
| 52 | dev_err(&st->us->dev, "problem when burst reading"); | ||
| 53 | |||
| 54 | mutex_unlock(&st->buf_lock); | ||
| 55 | |||
| 56 | return ret; | ||
| 57 | } | ||
| 58 | |||
| 59 | /* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device | ||
| 60 | * specific to be rolled into the core. | ||
| 61 | */ | ||
| 62 | static irqreturn_t adis16201_trigger_handler(int irq, void *p) | ||
| 63 | { | ||
| 64 | struct iio_poll_func *pf = p; | ||
| 65 | struct iio_dev *indio_dev = pf->private_data; | ||
| 66 | struct adis16201_state *st = iio_priv(indio_dev); | ||
| 67 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 68 | |||
| 69 | int i = 0; | ||
| 70 | s16 *data; | ||
| 71 | size_t datasize = ring->access->get_bytes_per_datum(ring); | ||
| 72 | |||
| 73 | data = kmalloc(datasize, GFP_KERNEL); | ||
| 74 | if (data == NULL) { | ||
| 75 | dev_err(&st->us->dev, "memory alloc failed in ring bh"); | ||
| 76 | return -ENOMEM; | ||
| 77 | } | ||
| 78 | |||
| 79 | if (ring->scan_count) | ||
| 80 | if (adis16201_read_ring_data(indio_dev, st->rx) >= 0) | ||
| 81 | for (; i < ring->scan_count; i++) | ||
| 82 | data[i] = be16_to_cpup( | ||
| 83 | (__be16 *)&(st->rx[i*2])); | ||
| 84 | |||
| 85 | /* Guaranteed to be aligned with 8 byte boundary */ | ||
| 86 | if (ring->scan_timestamp) | ||
| 87 | *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; | ||
| 88 | |||
| 89 | ring->access->store_to(ring, (u8 *)data, pf->timestamp); | ||
| 90 | |||
| 91 | iio_trigger_notify_done(indio_dev->trig); | ||
| 92 | kfree(data); | ||
| 93 | |||
| 94 | return IRQ_HANDLED; | ||
| 95 | } | ||
| 96 | |||
| 97 | void adis16201_unconfigure_ring(struct iio_dev *indio_dev) | ||
| 98 | { | ||
| 99 | iio_dealloc_pollfunc(indio_dev->pollfunc); | ||
| 100 | iio_sw_rb_free(indio_dev->ring); | ||
| 101 | } | ||
| 102 | |||
| 103 | static const struct iio_ring_setup_ops adis16201_ring_setup_ops = { | ||
| 104 | .preenable = &iio_sw_ring_preenable, | ||
| 105 | .postenable = &iio_triggered_ring_postenable, | ||
| 106 | .predisable = &iio_triggered_ring_predisable, | ||
| 107 | }; | ||
| 108 | |||
| 109 | int adis16201_configure_ring(struct iio_dev *indio_dev) | ||
| 110 | { | ||
| 111 | int ret = 0; | ||
| 112 | struct iio_ring_buffer *ring; | ||
| 113 | |||
| 114 | ring = iio_sw_rb_allocate(indio_dev); | ||
| 115 | if (!ring) { | ||
| 116 | ret = -ENOMEM; | ||
| 117 | return ret; | ||
| 118 | } | ||
| 119 | indio_dev->ring = ring; | ||
| 120 | /* Effectively select the ring buffer implementation */ | ||
| 121 | ring->bpe = 2; | ||
| 122 | ring->scan_timestamp = true; | ||
| 123 | ring->access = &ring_sw_access_funcs; | ||
| 124 | ring->setup_ops = &adis16201_ring_setup_ops; | ||
| 125 | ring->owner = THIS_MODULE; | ||
| 126 | |||
| 127 | /* Set default scan mode */ | ||
| 128 | iio_scan_mask_set(ring, ADIS16201_SCAN_SUPPLY); | ||
| 129 | iio_scan_mask_set(ring, ADIS16201_SCAN_ACC_X); | ||
| 130 | iio_scan_mask_set(ring, ADIS16201_SCAN_ACC_Y); | ||
| 131 | iio_scan_mask_set(ring, ADIS16201_SCAN_AUX_ADC); | ||
| 132 | iio_scan_mask_set(ring, ADIS16201_SCAN_TEMP); | ||
| 133 | iio_scan_mask_set(ring, ADIS16201_SCAN_INCLI_X); | ||
| 134 | iio_scan_mask_set(ring, ADIS16201_SCAN_INCLI_Y); | ||
| 135 | |||
| 136 | indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, | ||
| 137 | &adis16201_trigger_handler, | ||
| 138 | IRQF_ONESHOT, | ||
| 139 | indio_dev, | ||
| 140 | "adis16201_consumer%d", | ||
| 141 | indio_dev->id); | ||
| 142 | if (indio_dev->pollfunc == NULL) { | ||
| 143 | ret = -ENOMEM; | ||
| 144 | goto error_iio_sw_rb_free; | ||
| 145 | } | ||
| 146 | |||
| 147 | indio_dev->modes |= INDIO_RING_TRIGGERED; | ||
| 148 | return 0; | ||
| 149 | error_iio_sw_rb_free: | ||
| 150 | iio_sw_rb_free(indio_dev->ring); | ||
| 151 | return ret; | ||
| 152 | } | ||
diff --git a/drivers/staging/iio/accel/adis16201_trigger.c b/drivers/staging/iio/accel/adis16201_trigger.c new file mode 100644 index 00000000000..3a95c083b45 --- /dev/null +++ b/drivers/staging/iio/accel/adis16201_trigger.c | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | #include <linux/interrupt.h> | ||
| 2 | #include <linux/irq.h> | ||
| 3 | #include <linux/mutex.h> | ||
| 4 | #include <linux/device.h> | ||
| 5 | #include <linux/kernel.h> | ||
| 6 | #include <linux/sysfs.h> | ||
| 7 | #include <linux/spi/spi.h> | ||
| 8 | |||
| 9 | #include "../iio.h" | ||
| 10 | #include "../sysfs.h" | ||
| 11 | #include "../trigger.h" | ||
| 12 | #include "adis16201.h" | ||
| 13 | |||
| 14 | /** | ||
| 15 | * adis16201_data_rdy_trigger_set_state() set datardy interrupt state | ||
| 16 | **/ | ||
| 17 | static int adis16201_data_rdy_trigger_set_state(struct iio_trigger *trig, | ||
| 18 | bool state) | ||
| 19 | { | ||
| 20 | struct iio_dev *indio_dev = trig->private_data; | ||
| 21 | |||
| 22 | dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); | ||
| 23 | return adis16201_set_irq(indio_dev, state); | ||
| 24 | } | ||
| 25 | |||
| 26 | int adis16201_probe_trigger(struct iio_dev *indio_dev) | ||
| 27 | { | ||
| 28 | int ret; | ||
| 29 | struct adis16201_state *st = iio_priv(indio_dev); | ||
| 30 | |||
| 31 | st->trig = iio_allocate_trigger("adis16201-dev%d", indio_dev->id); | ||
| 32 | if (st->trig == NULL) { | ||
| 33 | ret = -ENOMEM; | ||
| 34 | goto error_ret; | ||
| 35 | } | ||
| 36 | ret = request_irq(st->us->irq, | ||
| 37 | &iio_trigger_generic_data_rdy_poll, | ||
| 38 | IRQF_TRIGGER_RISING, | ||
| 39 | "adis16201", | ||
| 40 | st->trig); | ||
| 41 | if (ret) | ||
| 42 | goto error_free_trig; | ||
| 43 | st->trig->dev.parent = &st->us->dev; | ||
| 44 | st->trig->owner = THIS_MODULE; | ||
| 45 | st->trig->private_data = indio_dev; | ||
| 46 | st->trig->set_trigger_state = &adis16201_data_rdy_trigger_set_state; | ||
| 47 | ret = iio_trigger_register(st->trig); | ||
| 48 | |||
| 49 | /* select default trigger */ | ||
| 50 | indio_dev->trig = st->trig; | ||
| 51 | if (ret) | ||
| 52 | goto error_free_irq; | ||
| 53 | |||
| 54 | return 0; | ||
| 55 | |||
| 56 | error_free_irq: | ||
| 57 | free_irq(st->us->irq, st->trig); | ||
| 58 | error_free_trig: | ||
| 59 | iio_free_trigger(st->trig); | ||
| 60 | error_ret: | ||
| 61 | return ret; | ||
| 62 | } | ||
| 63 | |||
| 64 | void adis16201_remove_trigger(struct iio_dev *indio_dev) | ||
| 65 | { | ||
| 66 | struct adis16201_state *state = iio_priv(indio_dev); | ||
| 67 | |||
| 68 | iio_trigger_unregister(state->trig); | ||
| 69 | free_irq(state->us->irq, state->trig); | ||
| 70 | iio_free_trigger(state->trig); | ||
| 71 | } | ||
diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c new file mode 100644 index 00000000000..d2c07c52746 --- /dev/null +++ b/drivers/staging/iio/accel/adis16203_ring.c | |||
| @@ -0,0 +1,158 @@ | |||
| 1 | #include <linux/interrupt.h> | ||
| 2 | #include <linux/irq.h> | ||
| 3 | #include <linux/gpio.h> | ||
| 4 | #include <linux/workqueue.h> | ||
| 5 | #include <linux/mutex.h> | ||
| 6 | #include <linux/device.h> | ||
| 7 | #include <linux/kernel.h> | ||
| 8 | #include <linux/spi/spi.h> | ||
| 9 | #include <linux/slab.h> | ||
| 10 | #include <linux/sysfs.h> | ||
| 11 | #include <linux/list.h> | ||
| 12 | |||
| 13 | #include "../iio.h" | ||
| 14 | #include "../sysfs.h" | ||
| 15 | #include "../ring_sw.h" | ||
| 16 | #include "accel.h" | ||
| 17 | #include "../trigger.h" | ||
| 18 | #include "adis16203.h" | ||
| 19 | |||
| 20 | /** | ||
| 21 | * adis16203_read_ring_data() read data registers which will be placed into ring | ||
| 22 | * @dev: device associated with child of actual device (iio_dev or iio_trig) | ||
| 23 | * @rx: somewhere to pass back the value read | ||
| 24 | **/ | ||
| 25 | static int adis16203_read_ring_data(struct device *dev, u8 *rx) | ||
| 26 | { | ||
| 27 | struct spi_message msg; | ||
| 28 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 29 | struct adis16203_state *st = iio_priv(indio_dev); | ||
| 30 | struct spi_transfer xfers[ADIS16203_OUTPUTS + 1]; | ||
| 31 | int ret; | ||
| 32 | int i; | ||
| 33 | |||
| 34 | mutex_lock(&st->buf_lock); | ||
| 35 | |||
| 36 | spi_message_init(&msg); | ||
| 37 | |||
| 38 | memset(xfers, 0, sizeof(xfers)); | ||
| 39 | for (i = 0; i <= ADIS16203_OUTPUTS; i++) { | ||
| 40 | xfers[i].bits_per_word = 8; | ||
| 41 | xfers[i].cs_change = 1; | ||
| 42 | xfers[i].len = 2; | ||
| 43 | xfers[i].delay_usecs = 20; | ||
| 44 | xfers[i].tx_buf = st->tx + 2 * i; | ||
| 45 | if (i < 1) /* SUPPLY_OUT: 0x02, AUX_ADC: 0x08 */ | ||
| 46 | st->tx[2 * i] = ADIS16203_READ_REG(ADIS16203_SUPPLY_OUT + 2 * i); | ||
| 47 | else | ||
| 48 | st->tx[2 * i] = ADIS16203_READ_REG(ADIS16203_SUPPLY_OUT + 2 * i + 6); | ||
| 49 | st->tx[2 * i + 1] = 0; | ||
| 50 | if (i >= 1) | ||
| 51 | xfers[i].rx_buf = rx + 2 * (i - 1); | ||
| 52 | spi_message_add_tail(&xfers[i], &msg); | ||
| 53 | } | ||
| 54 | |||
| 55 | ret = spi_sync(st->us, &msg); | ||
| 56 | if (ret) | ||
| 57 | dev_err(&st->us->dev, "problem when burst reading"); | ||
| 58 | |||
| 59 | mutex_unlock(&st->buf_lock); | ||
| 60 | |||
| 61 | return ret; | ||
| 62 | } | ||
| 63 | |||
| 64 | /* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device | ||
| 65 | * specific to be rolled into the core. | ||
| 66 | */ | ||
| 67 | static irqreturn_t adis16203_trigger_handler(int irq, void *p) | ||
| 68 | { | ||
| 69 | struct iio_poll_func *pf = p; | ||
| 70 | struct iio_dev *indio_dev = pf->private_data; | ||
| 71 | struct adis16203_state *st = iio_priv(indio_dev); | ||
| 72 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 73 | |||
| 74 | int i = 0; | ||
| 75 | s16 *data; | ||
| 76 | size_t datasize = ring->access->get_bytes_per_datum(ring); | ||
| 77 | |||
| 78 | data = kmalloc(datasize, GFP_KERNEL); | ||
| 79 | if (data == NULL) { | ||
| 80 | dev_err(&st->us->dev, "memory alloc failed in ring bh"); | ||
| 81 | return -ENOMEM; | ||
| 82 | } | ||
| 83 | |||
| 84 | if (ring->scan_count) | ||
| 85 | if (adis16203_read_ring_data(&indio_dev->dev, st->rx) >= 0) | ||
| 86 | for (; i < ring->scan_count; i++) | ||
| 87 | data[i] = be16_to_cpup( | ||
| 88 | (__be16 *)&(st->rx[i*2])); | ||
| 89 | |||
| 90 | /* Guaranteed to be aligned with 8 byte boundary */ | ||
| 91 | if (ring->scan_timestamp) | ||
| 92 | *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; | ||
| 93 | |||
| 94 | ring->access->store_to(ring, | ||
| 95 | (u8 *)data, | ||
| 96 | pf->timestamp); | ||
| 97 | |||
| 98 | iio_trigger_notify_done(indio_dev->trig); | ||
| 99 | kfree(data); | ||
| 100 | |||
| 101 | return IRQ_HANDLED; | ||
| 102 | } | ||
| 103 | |||
| 104 | void adis16203_unconfigure_ring(struct iio_dev *indio_dev) | ||
| 105 | { | ||
| 106 | iio_dealloc_pollfunc(indio_dev->pollfunc); | ||
| 107 | iio_sw_rb_free(indio_dev->ring); | ||
| 108 | } | ||
| 109 | |||
| 110 | static const struct iio_ring_setup_ops adis16203_ring_setup_ops = { | ||
| 111 | .preenable = &iio_sw_ring_preenable, | ||
| 112 | .postenable = &iio_triggered_ring_postenable, | ||
| 113 | .predisable = &iio_triggered_ring_predisable, | ||
| 114 | }; | ||
| 115 | |||
| 116 | int adis16203_configure_ring(struct iio_dev *indio_dev) | ||
| 117 | { | ||
| 118 | int ret = 0; | ||
| 119 | struct iio_ring_buffer *ring; | ||
| 120 | |||
| 121 | ring = iio_sw_rb_allocate(indio_dev); | ||
| 122 | if (!ring) { | ||
| 123 | ret = -ENOMEM; | ||
| 124 | return ret; | ||
| 125 | } | ||
| 126 | indio_dev->ring = ring; | ||
| 127 | /* Effectively select the ring buffer implementation */ | ||
| 128 | ring->bpe = 2; | ||
| 129 | ring->scan_timestamp = true; | ||
| 130 | ring->access = &ring_sw_access_funcs; | ||
| 131 | ring->setup_ops = &adis16203_ring_setup_ops; | ||
| 132 | ring->owner = THIS_MODULE; | ||
| 133 | |||
| 134 | /* Set default scan mode */ | ||
| 135 | iio_scan_mask_set(ring, ADIS16203_SCAN_SUPPLY); | ||
| 136 | iio_scan_mask_set(ring, ADIS16203_SCAN_TEMP); | ||
| 137 | iio_scan_mask_set(ring, ADIS16203_SCAN_AUX_ADC); | ||
| 138 | iio_scan_mask_set(ring, ADIS16203_SCAN_INCLI_X); | ||
| 139 | iio_scan_mask_set(ring, ADIS16203_SCAN_INCLI_Y); | ||
| 140 | |||
| 141 | indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, | ||
| 142 | &adis16203_trigger_handler, | ||
| 143 | IRQF_ONESHOT, | ||
| 144 | indio_dev, | ||
| 145 | "adis16203_consumer%d", | ||
| 146 | indio_dev->id); | ||
| 147 | if (indio_dev->pollfunc == NULL) { | ||
| 148 | ret = -ENOMEM; | ||
| 149 | goto error_iio_sw_rb_free; | ||
| 150 | } | ||
| 151 | |||
| 152 | indio_dev->modes |= INDIO_RING_TRIGGERED; | ||
| 153 | return 0; | ||
| 154 | |||
| 155 | error_iio_sw_rb_free: | ||
| 156 | iio_sw_rb_free(indio_dev->ring); | ||
| 157 | return ret; | ||
| 158 | } | ||
diff --git a/drivers/staging/iio/accel/adis16203_trigger.c b/drivers/staging/iio/accel/adis16203_trigger.c new file mode 100644 index 00000000000..3caf3e8bc9d --- /dev/null +++ b/drivers/staging/iio/accel/adis16203_trigger.c | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | #include <linux/interrupt.h> | ||
| 2 | #include <linux/irq.h> | ||
| 3 | #include <linux/mutex.h> | ||
| 4 | #include <linux/device.h> | ||
| 5 | #include <linux/kernel.h> | ||
| 6 | #include <linux/sysfs.h> | ||
| 7 | #include <linux/list.h> | ||
| 8 | #include <linux/spi/spi.h> | ||
| 9 | |||
| 10 | #include "../iio.h" | ||
| 11 | #include "../sysfs.h" | ||
| 12 | #include "../trigger.h" | ||
| 13 | #include "adis16203.h" | ||
| 14 | |||
| 15 | /** | ||
| 16 | * adis16203_data_rdy_trigger_set_state() set datardy interrupt state | ||
| 17 | **/ | ||
| 18 | static int adis16203_data_rdy_trigger_set_state(struct iio_trigger *trig, | ||
| 19 | bool state) | ||
| 20 | { | ||
| 21 | struct iio_dev *indio_dev = trig->private_data; | ||
| 22 | |||
| 23 | dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); | ||
| 24 | return adis16203_set_irq(indio_dev, state); | ||
| 25 | } | ||
| 26 | |||
| 27 | int adis16203_probe_trigger(struct iio_dev *indio_dev) | ||
| 28 | { | ||
| 29 | int ret; | ||
| 30 | struct adis16203_state *st = iio_priv(indio_dev); | ||
| 31 | |||
| 32 | st->trig = iio_allocate_trigger("adis16203-dev%d", indio_dev->id); | ||
| 33 | if (st->trig == NULL) { | ||
| 34 | ret = -ENOMEM; | ||
| 35 | goto error_ret; | ||
| 36 | } | ||
| 37 | |||
| 38 | ret = request_irq(st->us->irq, | ||
| 39 | &iio_trigger_generic_data_rdy_poll, | ||
| 40 | IRQF_TRIGGER_RISING, | ||
| 41 | "adis16203", | ||
| 42 | st->trig); | ||
| 43 | if (ret) | ||
| 44 | goto error_free_trig; | ||
| 45 | |||
| 46 | st->trig->dev.parent = &st->us->dev; | ||
| 47 | st->trig->owner = THIS_MODULE; | ||
| 48 | st->trig->private_data = indio_dev; | ||
| 49 | st->trig->set_trigger_state = &adis16203_data_rdy_trigger_set_state; | ||
| 50 | ret = iio_trigger_register(st->trig); | ||
| 51 | |||
| 52 | /* select default trigger */ | ||
| 53 | indio_dev->trig = st->trig; | ||
| 54 | if (ret) | ||
| 55 | goto error_free_irq; | ||
| 56 | |||
| 57 | return 0; | ||
| 58 | |||
| 59 | error_free_irq: | ||
| 60 | free_irq(st->us->irq, st->trig); | ||
| 61 | error_free_trig: | ||
| 62 | iio_free_trigger(st->trig); | ||
| 63 | error_ret: | ||
| 64 | return ret; | ||
| 65 | } | ||
| 66 | |||
| 67 | void adis16203_remove_trigger(struct iio_dev *indio_dev) | ||
| 68 | { | ||
| 69 | struct adis16203_state *st = iio_priv(indio_dev); | ||
| 70 | |||
| 71 | iio_trigger_unregister(st->trig); | ||
| 72 | free_irq(st->us->irq, st->trig); | ||
| 73 | iio_free_trigger(st->trig); | ||
| 74 | } | ||
diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c new file mode 100644 index 00000000000..852df06684d --- /dev/null +++ b/drivers/staging/iio/accel/adis16204_ring.c | |||
| @@ -0,0 +1,154 @@ | |||
| 1 | #include <linux/interrupt.h> | ||
| 2 | #include <linux/irq.h> | ||
| 3 | #include <linux/gpio.h> | ||
| 4 | #include <linux/workqueue.h> | ||
| 5 | #include <linux/mutex.h> | ||
| 6 | #include <linux/device.h> | ||
| 7 | #include <linux/kernel.h> | ||
| 8 | #include <linux/spi/spi.h> | ||
| 9 | #include <linux/slab.h> | ||
| 10 | #include <linux/sysfs.h> | ||
| 11 | #include <linux/list.h> | ||
| 12 | |||
| 13 | #include "../iio.h" | ||
| 14 | #include "../sysfs.h" | ||
| 15 | #include "../ring_sw.h" | ||
| 16 | #include "accel.h" | ||
| 17 | #include "../trigger.h" | ||
| 18 | #include "adis16204.h" | ||
| 19 | |||
| 20 | /** | ||
| 21 | * adis16204_read_ring_data() read data registers which will be placed into ring | ||
| 22 | * @dev: device associated with child of actual device (iio_dev or iio_trig) | ||
| 23 | * @rx: somewhere to pass back the value read | ||
| 24 | **/ | ||
| 25 | static int adis16204_read_ring_data(struct device *dev, u8 *rx) | ||
| 26 | { | ||
| 27 | struct spi_message msg; | ||
| 28 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 29 | struct adis16204_state *st = iio_priv(indio_dev); | ||
| 30 | struct spi_transfer xfers[ADIS16204_OUTPUTS + 1]; | ||
| 31 | int ret; | ||
| 32 | int i; | ||
| 33 | |||
| 34 | mutex_lock(&st->buf_lock); | ||
| 35 | |||
| 36 | spi_message_init(&msg); | ||
| 37 | |||
| 38 | memset(xfers, 0, sizeof(xfers)); | ||
| 39 | for (i = 0; i <= ADIS16204_OUTPUTS; i++) { | ||
| 40 | xfers[i].bits_per_word = 8; | ||
| 41 | xfers[i].cs_change = 1; | ||
| 42 | xfers[i].len = 2; | ||
| 43 | xfers[i].delay_usecs = 20; | ||
| 44 | xfers[i].tx_buf = st->tx + 2 * i; | ||
| 45 | st->tx[2 * i] | ||
| 46 | = ADIS16204_READ_REG(ADIS16204_SUPPLY_OUT + 2 * i); | ||
| 47 | st->tx[2 * i + 1] = 0; | ||
| 48 | if (i >= 1) | ||
| 49 | xfers[i].rx_buf = rx + 2 * (i - 1); | ||
| 50 | spi_message_add_tail(&xfers[i], &msg); | ||
| 51 | } | ||
| 52 | |||
| 53 | ret = spi_sync(st->us, &msg); | ||
| 54 | if (ret) | ||
| 55 | dev_err(&st->us->dev, "problem when burst reading"); | ||
| 56 | |||
| 57 | mutex_unlock(&st->buf_lock); | ||
| 58 | |||
| 59 | return ret; | ||
| 60 | } | ||
| 61 | |||
| 62 | /* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device | ||
| 63 | * specific to be rolled into the core. | ||
| 64 | */ | ||
| 65 | static irqreturn_t adis16204_trigger_handler(int irq, void *p) | ||
| 66 | { | ||
| 67 | struct iio_poll_func *pf = p; | ||
| 68 | struct iio_dev *indio_dev = pf->private_data; | ||
| 69 | struct adis16204_state *st = iio_priv(indio_dev); | ||
| 70 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 71 | int i = 0; | ||
| 72 | s16 *data; | ||
| 73 | size_t datasize = ring->access->get_bytes_per_datum(ring); | ||
| 74 | |||
| 75 | data = kmalloc(datasize, GFP_KERNEL); | ||
| 76 | if (data == NULL) { | ||
| 77 | dev_err(&st->us->dev, "memory alloc failed in ring bh"); | ||
| 78 | return -ENOMEM; | ||
| 79 | } | ||
| 80 | |||
| 81 | if (ring->scan_count) | ||
| 82 | if (adis16204_read_ring_data(&indio_dev->dev, st->rx) >= 0) | ||
| 83 | for (; i < ring->scan_count; i++) | ||
| 84 | data[i] = be16_to_cpup( | ||
| 85 | (__be16 *)&(st->rx[i*2])); | ||
| 86 | |||
| 87 | /* Guaranteed to be aligned with 8 byte boundary */ | ||
| 88 | if (ring->scan_timestamp) | ||
| 89 | *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; | ||
| 90 | |||
| 91 | ring->access->store_to(ring, (u8 *)data, pf->timestamp); | ||
| 92 | |||
| 93 | iio_trigger_notify_done(indio_dev->trig); | ||
| 94 | kfree(data); | ||
| 95 | |||
| 96 | return IRQ_HANDLED; | ||
| 97 | } | ||
| 98 | |||
| 99 | void adis16204_unconfigure_ring(struct iio_dev *indio_dev) | ||
| 100 | { | ||
| 101 | iio_dealloc_pollfunc(indio_dev->pollfunc); | ||
| 102 | iio_sw_rb_free(indio_dev->ring); | ||
| 103 | } | ||
| 104 | |||
| 105 | static const struct iio_ring_setup_ops adis16204_ring_setup_ops = { | ||
| 106 | .preenable = &iio_sw_ring_preenable, | ||
| 107 | .postenable = &iio_triggered_ring_postenable, | ||
| 108 | .predisable = &iio_triggered_ring_predisable, | ||
| 109 | }; | ||
| 110 | |||
| 111 | int adis16204_configure_ring(struct iio_dev *indio_dev) | ||
| 112 | { | ||
| 113 | int ret = 0; | ||
| 114 | struct iio_ring_buffer *ring; | ||
| 115 | |||
| 116 | ring = iio_sw_rb_allocate(indio_dev); | ||
| 117 | if (!ring) { | ||
| 118 | ret = -ENOMEM; | ||
| 119 | return ret; | ||
| 120 | } | ||
| 121 | indio_dev->ring = ring; | ||
| 122 | /* Effectively select the ring buffer implementation */ | ||
| 123 | ring->access = &ring_sw_access_funcs; | ||
| 124 | ring->bpe = 2; | ||
| 125 | ring->scan_timestamp = true; | ||
| 126 | ring->setup_ops = &adis16204_ring_setup_ops; | ||
| 127 | ring->owner = THIS_MODULE; | ||
| 128 | |||
| 129 | /* Set default scan mode */ | ||
| 130 | iio_scan_mask_set(ring, ADIS16204_SCAN_SUPPLY); | ||
| 131 | iio_scan_mask_set(ring, ADIS16204_SCAN_ACC_X); | ||
| 132 | iio_scan_mask_set(ring, ADIS16204_SCAN_ACC_Y); | ||
| 133 | iio_scan_mask_set(ring, ADIS16204_SCAN_AUX_ADC); | ||
| 134 | iio_scan_mask_set(ring, ADIS16204_SCAN_TEMP); | ||
| 135 | |||
| 136 | indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, | ||
| 137 | &adis16204_trigger_handler, | ||
| 138 | IRQF_ONESHOT, | ||
| 139 | indio_dev, | ||
| 140 | "%s_consumer%d", | ||
| 141 | indio_dev->name, | ||
| 142 | indio_dev->id); | ||
| 143 | if (indio_dev->pollfunc == NULL) { | ||
| 144 | ret = -ENOMEM; | ||
| 145 | goto error_iio_sw_rb_free; | ||
| 146 | } | ||
| 147 | |||
| 148 | indio_dev->modes |= INDIO_RING_TRIGGERED; | ||
| 149 | return 0; | ||
| 150 | |||
| 151 | error_iio_sw_rb_free: | ||
| 152 | iio_sw_rb_free(indio_dev->ring); | ||
| 153 | return ret; | ||
| 154 | } | ||
diff --git a/drivers/staging/iio/accel/adis16204_trigger.c b/drivers/staging/iio/accel/adis16204_trigger.c new file mode 100644 index 00000000000..01f73b9b888 --- /dev/null +++ b/drivers/staging/iio/accel/adis16204_trigger.c | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | #include <linux/interrupt.h> | ||
| 2 | #include <linux/irq.h> | ||
| 3 | #include <linux/mutex.h> | ||
| 4 | #include <linux/device.h> | ||
| 5 | #include <linux/kernel.h> | ||
| 6 | #include <linux/sysfs.h> | ||
| 7 | #include <linux/list.h> | ||
| 8 | #include <linux/spi/spi.h> | ||
| 9 | |||
| 10 | #include "../iio.h" | ||
| 11 | #include "../sysfs.h" | ||
| 12 | #include "../trigger.h" | ||
| 13 | #include "adis16204.h" | ||
| 14 | |||
| 15 | /** | ||
| 16 | * adis16204_data_rdy_trigger_set_state() set datardy interrupt state | ||
| 17 | **/ | ||
| 18 | static int adis16204_data_rdy_trigger_set_state(struct iio_trigger *trig, | ||
| 19 | bool state) | ||
| 20 | { | ||
| 21 | struct iio_dev *indio_dev = trig->private_data; | ||
| 22 | |||
| 23 | dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); | ||
| 24 | return adis16204_set_irq(indio_dev, state); | ||
| 25 | } | ||
| 26 | |||
| 27 | int adis16204_probe_trigger(struct iio_dev *indio_dev) | ||
| 28 | { | ||
| 29 | int ret; | ||
| 30 | struct adis16204_state *st = iio_priv(indio_dev); | ||
| 31 | |||
| 32 | st->trig = iio_allocate_trigger("adis16204-dev%d", indio_dev->id); | ||
| 33 | if (st->trig == NULL) { | ||
| 34 | ret = -ENOMEM; | ||
| 35 | goto error_ret; | ||
| 36 | } | ||
| 37 | |||
| 38 | ret = request_irq(st->us->irq, | ||
| 39 | &iio_trigger_generic_data_rdy_poll, | ||
| 40 | IRQF_TRIGGER_RISING, | ||
| 41 | "adis16204", | ||
| 42 | st->trig); | ||
| 43 | if (ret) | ||
| 44 | goto error_free_trig; | ||
| 45 | |||
| 46 | st->trig->dev.parent = &st->us->dev; | ||
| 47 | st->trig->owner = THIS_MODULE; | ||
| 48 | st->trig->private_data = indio_dev; | ||
| 49 | st->trig->set_trigger_state = &adis16204_data_rdy_trigger_set_state; | ||
| 50 | ret = iio_trigger_register(st->trig); | ||
| 51 | |||
| 52 | /* select default trigger */ | ||
| 53 | indio_dev->trig = st->trig; | ||
| 54 | if (ret) | ||
| 55 | goto error_free_irq; | ||
| 56 | |||
| 57 | return 0; | ||
| 58 | |||
| 59 | error_free_irq: | ||
| 60 | free_irq(st->us->irq, st->trig); | ||
| 61 | error_free_trig: | ||
| 62 | iio_free_trigger(st->trig); | ||
| 63 | error_ret: | ||
| 64 | return ret; | ||
| 65 | } | ||
| 66 | |||
| 67 | void adis16204_remove_trigger(struct iio_dev *indio_dev) | ||
| 68 | { | ||
| 69 | struct adis16204_state *state = iio_priv(indio_dev); | ||
| 70 | |||
| 71 | iio_trigger_unregister(state->trig); | ||
| 72 | free_irq(state->us->irq, state->trig); | ||
| 73 | iio_free_trigger(state->trig); | ||
| 74 | } | ||
diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c new file mode 100644 index 00000000000..45017d3f02f --- /dev/null +++ b/drivers/staging/iio/accel/adis16209_ring.c | |||
| @@ -0,0 +1,157 @@ | |||
| 1 | #include <linux/interrupt.h> | ||
| 2 | #include <linux/irq.h> | ||
| 3 | #include <linux/gpio.h> | ||
| 4 | #include <linux/workqueue.h> | ||
| 5 | #include <linux/mutex.h> | ||
| 6 | #include <linux/device.h> | ||
| 7 | #include <linux/kernel.h> | ||
| 8 | #include <linux/spi/spi.h> | ||
| 9 | #include <linux/slab.h> | ||
| 10 | #include <linux/sysfs.h> | ||
| 11 | #include <linux/list.h> | ||
| 12 | |||
| 13 | #include "../iio.h" | ||
| 14 | #include "../sysfs.h" | ||
| 15 | #include "../ring_sw.h" | ||
| 16 | #include "accel.h" | ||
| 17 | #include "../trigger.h" | ||
| 18 | #include "adis16209.h" | ||
| 19 | |||
| 20 | /** | ||
| 21 | * adis16209_read_ring_data() read data registers which will be placed into ring | ||
| 22 | * @dev: device associated with child of actual device (iio_dev or iio_trig) | ||
| 23 | * @rx: somewhere to pass back the value read | ||
| 24 | **/ | ||
| 25 | static int adis16209_read_ring_data(struct device *dev, u8 *rx) | ||
| 26 | { | ||
| 27 | struct spi_message msg; | ||
| 28 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 29 | struct adis16209_state *st = iio_priv(indio_dev); | ||
| 30 | struct spi_transfer xfers[ADIS16209_OUTPUTS + 1]; | ||
| 31 | int ret; | ||
| 32 | int i; | ||
| 33 | |||
| 34 | mutex_lock(&st->buf_lock); | ||
| 35 | |||
| 36 | spi_message_init(&msg); | ||
| 37 | |||
| 38 | memset(xfers, 0, sizeof(xfers)); | ||
| 39 | for (i = 0; i <= ADIS16209_OUTPUTS; i++) { | ||
| 40 | xfers[i].bits_per_word = 8; | ||
| 41 | xfers[i].cs_change = 1; | ||
| 42 | xfers[i].len = 2; | ||
| 43 | xfers[i].delay_usecs = 30; | ||
| 44 | xfers[i].tx_buf = st->tx + 2 * i; | ||
| 45 | st->tx[2 * i] | ||
| 46 | = ADIS16209_READ_REG(ADIS16209_SUPPLY_OUT + 2 * i); | ||
| 47 | st->tx[2 * i + 1] = 0; | ||
| 48 | if (i >= 1) | ||
| 49 | xfers[i].rx_buf = rx + 2 * (i - 1); | ||
| 50 | spi_message_add_tail(&xfers[i], &msg); | ||
| 51 | } | ||
| 52 | |||
| 53 | ret = spi_sync(st->us, &msg); | ||
| 54 | if (ret) | ||
| 55 | dev_err(&st->us->dev, "problem when burst reading"); | ||
| 56 | |||
| 57 | mutex_unlock(&st->buf_lock); | ||
| 58 | |||
| 59 | return ret; | ||
| 60 | } | ||
| 61 | |||
| 62 | /* Whilst this makes a lot of calls to iio_sw_ring functions - it is to device | ||
| 63 | * specific to be rolled into the core. | ||
| 64 | */ | ||
| 65 | static irqreturn_t adis16209_trigger_handler(int irq, void *p) | ||
| 66 | { | ||
| 67 | struct iio_poll_func *pf = p; | ||
| 68 | struct iio_dev *indio_dev = pf->private_data; | ||
| 69 | struct adis16209_state *st = iio_priv(indio_dev); | ||
| 70 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 71 | |||
| 72 | int i = 0; | ||
| 73 | s16 *data; | ||
| 74 | size_t datasize = ring->access->get_bytes_per_datum(ring); | ||
| 75 | |||
| 76 | data = kmalloc(datasize , GFP_KERNEL); | ||
| 77 | if (data == NULL) { | ||
| 78 | dev_err(&st->us->dev, "memory alloc failed in ring bh"); | ||
| 79 | return -ENOMEM; | ||
| 80 | } | ||
| 81 | |||
| 82 | if (ring->scan_count && | ||
| 83 | adis16209_read_ring_data(&indio_dev->dev, st->rx) >= 0) | ||
| 84 | for (; i < ring->scan_count; i++) | ||
| 85 | data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); | ||
| 86 | |||
| 87 | /* Guaranteed to be aligned with 8 byte boundary */ | ||
| 88 | if (ring->scan_timestamp) | ||
| 89 | *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; | ||
| 90 | |||
| 91 | ring->access->store_to(ring, (u8 *)data, pf->timestamp); | ||
| 92 | |||
| 93 | iio_trigger_notify_done(indio_dev->trig); | ||
| 94 | kfree(data); | ||
| 95 | |||
| 96 | return IRQ_HANDLED; | ||
| 97 | } | ||
| 98 | |||
| 99 | void adis16209_unconfigure_ring(struct iio_dev *indio_dev) | ||
| 100 | { | ||
| 101 | iio_dealloc_pollfunc(indio_dev->pollfunc); | ||
| 102 | iio_sw_rb_free(indio_dev->ring); | ||
| 103 | } | ||
| 104 | |||
| 105 | static const struct iio_ring_setup_ops adis16209_ring_setup_ops = { | ||
| 106 | .preenable = &iio_sw_ring_preenable, | ||
| 107 | .postenable = &iio_triggered_ring_postenable, | ||
| 108 | .predisable = &iio_triggered_ring_predisable, | ||
| 109 | }; | ||
| 110 | |||
| 111 | int adis16209_configure_ring(struct iio_dev *indio_dev) | ||
| 112 | { | ||
| 113 | int ret = 0; | ||
| 114 | struct iio_ring_buffer *ring; | ||
| 115 | |||
| 116 | ring = iio_sw_rb_allocate(indio_dev); | ||
| 117 | if (!ring) { | ||
| 118 | ret = -ENOMEM; | ||
| 119 | return ret; | ||
| 120 | } | ||
| 121 | indio_dev->ring = ring; | ||
| 122 | /* Effectively select the ring buffer implementation */ | ||
| 123 | ring->access = &ring_sw_access_funcs; | ||
| 124 | ring->bpe = 2; | ||
| 125 | ring->scan_timestamp = true; | ||
| 126 | ring->setup_ops = &adis16209_ring_setup_ops; | ||
| 127 | ring->owner = THIS_MODULE; | ||
| 128 | |||
| 129 | /* Set default scan mode */ | ||
| 130 | iio_scan_mask_set(ring, ADIS16209_SCAN_SUPPLY); | ||
| 131 | iio_scan_mask_set(ring, ADIS16209_SCAN_ACC_X); | ||
| 132 | iio_scan_mask_set(ring, ADIS16209_SCAN_ACC_Y); | ||
| 133 | iio_scan_mask_set(ring, ADIS16209_SCAN_AUX_ADC); | ||
| 134 | iio_scan_mask_set(ring, ADIS16209_SCAN_TEMP); | ||
| 135 | iio_scan_mask_set(ring, ADIS16209_SCAN_INCLI_X); | ||
| 136 | iio_scan_mask_set(ring, ADIS16209_SCAN_INCLI_Y); | ||
| 137 | iio_scan_mask_set(ring, ADIS16209_SCAN_ROT); | ||
| 138 | |||
| 139 | indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, | ||
| 140 | &adis16209_trigger_handler, | ||
| 141 | IRQF_ONESHOT, | ||
| 142 | indio_dev, | ||
| 143 | "%s_consumer%d", | ||
| 144 | indio_dev->name, | ||
| 145 | indio_dev->id); | ||
| 146 | if (indio_dev->pollfunc == NULL) { | ||
| 147 | ret = -ENOMEM; | ||
| 148 | goto error_iio_sw_rb_free; | ||
| 149 | } | ||
| 150 | |||
| 151 | indio_dev->modes |= INDIO_RING_TRIGGERED; | ||
| 152 | return 0; | ||
| 153 | |||
| 154 | error_iio_sw_rb_free: | ||
| 155 | iio_sw_rb_free(indio_dev->ring); | ||
| 156 | return ret; | ||
| 157 | } | ||
diff --git a/drivers/staging/iio/accel/adis16209_trigger.c b/drivers/staging/iio/accel/adis16209_trigger.c new file mode 100644 index 00000000000..6df7b47ec7b --- /dev/null +++ b/drivers/staging/iio/accel/adis16209_trigger.c | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | #include <linux/interrupt.h> | ||
| 2 | #include <linux/irq.h> | ||
| 3 | #include <linux/mutex.h> | ||
| 4 | #include <linux/device.h> | ||
| 5 | #include <linux/kernel.h> | ||
| 6 | #include <linux/sysfs.h> | ||
| 7 | #include <linux/list.h> | ||
| 8 | #include <linux/spi/spi.h> | ||
| 9 | |||
| 10 | #include "../iio.h" | ||
| 11 | #include "../sysfs.h" | ||
| 12 | #include "../trigger.h" | ||
| 13 | #include "adis16209.h" | ||
| 14 | |||
| 15 | /** | ||
| 16 | * adis16209_data_rdy_trig_poll() the event handler for the data rdy trig | ||
| 17 | **/ | ||
| 18 | static irqreturn_t adis16209_data_rdy_trig_poll(int irq, void *trig) | ||
| 19 | { | ||
| 20 | iio_trigger_poll(trig, iio_get_time_ns()); | ||
| 21 | return IRQ_HANDLED; | ||
| 22 | } | ||
| 23 | |||
| 24 | /** | ||
| 25 | * adis16209_data_rdy_trigger_set_state() set datardy interrupt state | ||
| 26 | **/ | ||
| 27 | static int adis16209_data_rdy_trigger_set_state(struct iio_trigger *trig, | ||
| 28 | bool state) | ||
| 29 | { | ||
| 30 | struct iio_dev *indio_dev = trig->private_data; | ||
| 31 | |||
| 32 | dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); | ||
| 33 | return adis16209_set_irq(indio_dev, state); | ||
| 34 | } | ||
| 35 | |||
| 36 | int adis16209_probe_trigger(struct iio_dev *indio_dev) | ||
| 37 | { | ||
| 38 | int ret; | ||
| 39 | struct adis16209_state *st = iio_priv(indio_dev); | ||
| 40 | |||
| 41 | st->trig = iio_allocate_trigger("adis16209-dev%d", indio_dev->id); | ||
| 42 | if (st->trig == NULL) { | ||
| 43 | ret = -ENOMEM; | ||
| 44 | goto error_ret; | ||
| 45 | } | ||
| 46 | |||
| 47 | ret = request_irq(st->us->irq, | ||
| 48 | adis16209_data_rdy_trig_poll, | ||
| 49 | IRQF_TRIGGER_RISING, | ||
| 50 | "adis16209", | ||
| 51 | st->trig); | ||
| 52 | if (ret) | ||
| 53 | goto error_free_trig; | ||
| 54 | st->trig->dev.parent = &st->us->dev; | ||
| 55 | st->trig->owner = THIS_MODULE; | ||
| 56 | st->trig->private_data = indio_dev; | ||
| 57 | st->trig->set_trigger_state = &adis16209_data_rdy_trigger_set_state; | ||
| 58 | ret = iio_trigger_register(st->trig); | ||
| 59 | |||
| 60 | /* select default trigger */ | ||
| 61 | indio_dev->trig = st->trig; | ||
| 62 | if (ret) | ||
| 63 | goto error_free_irq; | ||
| 64 | |||
| 65 | return 0; | ||
| 66 | |||
| 67 | error_free_irq: | ||
| 68 | free_irq(st->us->irq, st->trig); | ||
| 69 | error_free_trig: | ||
| 70 | iio_free_trigger(st->trig); | ||
| 71 | error_ret: | ||
| 72 | return ret; | ||
| 73 | } | ||
| 74 | |||
| 75 | void adis16209_remove_trigger(struct iio_dev *indio_dev) | ||
| 76 | { | ||
| 77 | struct adis16209_state *st = iio_priv(indio_dev); | ||
| 78 | |||
| 79 | iio_trigger_unregister(st->trig); | ||
| 80 | free_irq(st->us->irq, st->trig); | ||
| 81 | iio_free_trigger(st->trig); | ||
| 82 | } | ||
diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c new file mode 100644 index 00000000000..c812a34daca --- /dev/null +++ b/drivers/staging/iio/accel/adis16240_ring.c | |||
| @@ -0,0 +1,152 @@ | |||
| 1 | #include <linux/interrupt.h> | ||
| 2 | #include <linux/irq.h> | ||
| 3 | #include <linux/gpio.h> | ||
| 4 | #include <linux/workqueue.h> | ||
| 5 | #include <linux/mutex.h> | ||
| 6 | #include <linux/device.h> | ||
| 7 | #include <linux/kernel.h> | ||
| 8 | #include <linux/spi/spi.h> | ||
| 9 | #include <linux/slab.h> | ||
| 10 | #include <linux/sysfs.h> | ||
| 11 | #include <linux/list.h> | ||
| 12 | |||
| 13 | #include "../iio.h" | ||
| 14 | #include "../sysfs.h" | ||
| 15 | #include "../ring_sw.h" | ||
| 16 | #include "accel.h" | ||
| 17 | #include "../trigger.h" | ||
| 18 | #include "adis16240.h" | ||
| 19 | |||
| 20 | /** | ||
| 21 | * adis16240_read_ring_data() read data registers which will be placed into ring | ||
| 22 | * @dev: device associated with child of actual device (iio_dev or iio_trig) | ||
| 23 | * @rx: somewhere to pass back the value read | ||
| 24 | **/ | ||
| 25 | static int adis16240_read_ring_data(struct device *dev, u8 *rx) | ||
| 26 | { | ||
| 27 | struct spi_message msg; | ||
| 28 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 29 | struct adis16240_state *st = iio_priv(indio_dev); | ||
| 30 | struct spi_transfer xfers[ADIS16240_OUTPUTS + 1]; | ||
| 31 | int ret; | ||
| 32 | int i; | ||
| 33 | |||
| 34 | mutex_lock(&st->buf_lock); | ||
| 35 | |||
| 36 | spi_message_init(&msg); | ||
| 37 | |||
| 38 | memset(xfers, 0, sizeof(xfers)); | ||
| 39 | for (i = 0; i <= ADIS16240_OUTPUTS; i++) { | ||
| 40 | xfers[i].bits_per_word = 8; | ||
| 41 | xfers[i].cs_change = 1; | ||
| 42 | xfers[i].len = 2; | ||
| 43 | xfers[i].delay_usecs = 30; | ||
| 44 | xfers[i].tx_buf = st->tx + 2 * i; | ||
| 45 | st->tx[2 * i] | ||
| 46 | = ADIS16240_READ_REG(ADIS16240_SUPPLY_OUT + 2 * i); | ||
| 47 | st->tx[2 * i + 1] = 0; | ||
| 48 | if (i >= 1) | ||
| 49 | xfers[i].rx_buf = rx + 2 * (i - 1); | ||
| 50 | spi_message_add_tail(&xfers[i], &msg); | ||
| 51 | } | ||
| 52 | |||
| 53 | ret = spi_sync(st->us, &msg); | ||
| 54 | if (ret) | ||
| 55 | dev_err(&st->us->dev, "problem when burst reading"); | ||
| 56 | |||
| 57 | mutex_unlock(&st->buf_lock); | ||
| 58 | |||
| 59 | return ret; | ||
| 60 | } | ||
| 61 | |||
| 62 | static irqreturn_t adis16240_trigger_handler(int irq, void *p) | ||
| 63 | { | ||
| 64 | struct iio_poll_func *pf = p; | ||
| 65 | struct iio_dev *indio_dev = pf->private_data; | ||
| 66 | struct adis16240_state *st = iio_priv(indio_dev); | ||
| 67 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 68 | |||
| 69 | int i = 0; | ||
| 70 | s16 *data; | ||
| 71 | size_t datasize = ring->access->get_bytes_per_datum(ring); | ||
| 72 | |||
| 73 | data = kmalloc(datasize, GFP_KERNEL); | ||
| 74 | if (data == NULL) { | ||
| 75 | dev_err(&st->us->dev, "memory alloc failed in ring bh"); | ||
| 76 | return -ENOMEM; | ||
| 77 | } | ||
| 78 | |||
| 79 | if (ring->scan_count && | ||
| 80 | adis16240_read_ring_data(&indio_dev->dev, st->rx) >= 0) | ||
| 81 | for (; i < ring->scan_count; i++) | ||
| 82 | data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); | ||
| 83 | |||
| 84 | /* Guaranteed to be aligned with 8 byte boundary */ | ||
| 85 | if (ring->scan_timestamp) | ||
| 86 | *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; | ||
| 87 | |||
| 88 | ring->access->store_to(ring, (u8 *)data, pf->timestamp); | ||
| 89 | |||
| 90 | iio_trigger_notify_done(indio_dev->trig); | ||
| 91 | kfree(data); | ||
| 92 | |||
| 93 | return IRQ_HANDLED; | ||
| 94 | } | ||
| 95 | |||
| 96 | void adis16240_unconfigure_ring(struct iio_dev *indio_dev) | ||
| 97 | { | ||
| 98 | iio_dealloc_pollfunc(indio_dev->pollfunc); | ||
| 99 | iio_sw_rb_free(indio_dev->ring); | ||
| 100 | } | ||
| 101 | |||
| 102 | static const struct iio_ring_setup_ops adis16240_ring_setup_ops = { | ||
| 103 | .preenable = &iio_sw_ring_preenable, | ||
| 104 | .postenable = &iio_triggered_ring_postenable, | ||
| 105 | .predisable = &iio_triggered_ring_predisable, | ||
| 106 | }; | ||
| 107 | |||
| 108 | int adis16240_configure_ring(struct iio_dev *indio_dev) | ||
| 109 | { | ||
| 110 | int ret = 0; | ||
| 111 | struct iio_ring_buffer *ring; | ||
| 112 | |||
| 113 | ring = iio_sw_rb_allocate(indio_dev); | ||
| 114 | if (!ring) { | ||
| 115 | ret = -ENOMEM; | ||
| 116 | return ret; | ||
| 117 | } | ||
| 118 | indio_dev->ring = ring; | ||
| 119 | /* Effectively select the ring buffer implementation */ | ||
| 120 | ring->access = &ring_sw_access_funcs; | ||
| 121 | ring->bpe = 2; | ||
| 122 | ring->scan_timestamp = true; | ||
| 123 | ring->setup_ops = &adis16240_ring_setup_ops; | ||
| 124 | ring->owner = THIS_MODULE; | ||
| 125 | |||
| 126 | /* Set default scan mode */ | ||
| 127 | iio_scan_mask_set(ring, ADIS16240_SCAN_SUPPLY); | ||
| 128 | iio_scan_mask_set(ring, ADIS16240_SCAN_ACC_X); | ||
| 129 | iio_scan_mask_set(ring, ADIS16240_SCAN_ACC_Y); | ||
| 130 | iio_scan_mask_set(ring, ADIS16240_SCAN_ACC_Z); | ||
| 131 | iio_scan_mask_set(ring, ADIS16240_SCAN_AUX_ADC); | ||
| 132 | iio_scan_mask_set(ring, ADIS16240_SCAN_TEMP); | ||
| 133 | |||
| 134 | indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, | ||
| 135 | &adis16240_trigger_handler, | ||
| 136 | IRQF_ONESHOT, | ||
| 137 | indio_dev, | ||
| 138 | "%s_consumer%d", | ||
| 139 | indio_dev->name, | ||
| 140 | indio_dev->id); | ||
| 141 | if (indio_dev->pollfunc == NULL) { | ||
| 142 | ret = -ENOMEM; | ||
| 143 | goto error_iio_sw_rb_free; | ||
| 144 | } | ||
| 145 | |||
| 146 | indio_dev->modes |= INDIO_RING_TRIGGERED; | ||
| 147 | return 0; | ||
| 148 | |||
| 149 | error_iio_sw_rb_free: | ||
| 150 | iio_sw_rb_free(indio_dev->ring); | ||
| 151 | return ret; | ||
| 152 | } | ||
diff --git a/drivers/staging/iio/accel/adis16240_trigger.c b/drivers/staging/iio/accel/adis16240_trigger.c new file mode 100644 index 00000000000..17135fc33c9 --- /dev/null +++ b/drivers/staging/iio/accel/adis16240_trigger.c | |||
| @@ -0,0 +1,83 @@ | |||
| 1 | #include <linux/interrupt.h> | ||
| 2 | #include <linux/irq.h> | ||
| 3 | #include <linux/mutex.h> | ||
| 4 | #include <linux/device.h> | ||
| 5 | #include <linux/kernel.h> | ||
| 6 | #include <linux/sysfs.h> | ||
| 7 | #include <linux/list.h> | ||
| 8 | #include <linux/spi/spi.h> | ||
| 9 | |||
| 10 | #include "../iio.h" | ||
| 11 | #include "../sysfs.h" | ||
| 12 | #include "../trigger.h" | ||
| 13 | #include "adis16240.h" | ||
| 14 | |||
| 15 | /** | ||
| 16 | * adis16240_data_rdy_trig_poll() the event handler for the data rdy trig | ||
| 17 | **/ | ||
| 18 | static irqreturn_t adis16240_data_rdy_trig_poll(int irq, void *trig) | ||
| 19 | { | ||
| 20 | iio_trigger_poll(trig, iio_get_time_ns()); | ||
| 21 | return IRQ_HANDLED; | ||
| 22 | } | ||
| 23 | |||
| 24 | /** | ||
| 25 | * adis16240_data_rdy_trigger_set_state() set datardy interrupt state | ||
| 26 | **/ | ||
| 27 | static int adis16240_data_rdy_trigger_set_state(struct iio_trigger *trig, | ||
| 28 | bool state) | ||
| 29 | { | ||
| 30 | struct iio_dev *indio_dev = trig->private_data; | ||
| 31 | |||
| 32 | dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); | ||
| 33 | return adis16240_set_irq(indio_dev, state); | ||
| 34 | } | ||
| 35 | |||
| 36 | int adis16240_probe_trigger(struct iio_dev *indio_dev) | ||
| 37 | { | ||
| 38 | int ret; | ||
| 39 | struct adis16240_state *st = iio_priv(indio_dev); | ||
| 40 | |||
| 41 | st->trig = iio_allocate_trigger("adis16240-dev%d", indio_dev->id); | ||
| 42 | if (st->trig == NULL) { | ||
| 43 | ret = -ENOMEM; | ||
| 44 | goto error_ret; | ||
| 45 | } | ||
| 46 | |||
| 47 | ret = request_irq(st->us->irq, | ||
| 48 | adis16240_data_rdy_trig_poll, | ||
| 49 | IRQF_TRIGGER_RISING, | ||
| 50 | "adis16240", | ||
| 51 | st->trig); | ||
| 52 | if (ret) | ||
| 53 | goto error_free_trig; | ||
| 54 | |||
| 55 | st->trig->dev.parent = &st->us->dev; | ||
| 56 | st->trig->owner = THIS_MODULE; | ||
| 57 | st->trig->private_data = indio_dev; | ||
| 58 | st->trig->set_trigger_state = &adis16240_data_rdy_trigger_set_state; | ||
| 59 | ret = iio_trigger_register(st->trig); | ||
| 60 | |||
| 61 | /* select default trigger */ | ||
| 62 | indio_dev->trig = st->trig; | ||
| 63 | if (ret) | ||
| 64 | goto error_free_irq; | ||
| 65 | |||
| 66 | return 0; | ||
| 67 | |||
| 68 | error_free_irq: | ||
| 69 | free_irq(st->us->irq, st->trig); | ||
| 70 | error_free_trig: | ||
| 71 | iio_free_trigger(st->trig); | ||
| 72 | error_ret: | ||
| 73 | return ret; | ||
| 74 | } | ||
| 75 | |||
| 76 | void adis16240_remove_trigger(struct iio_dev *indio_dev) | ||
| 77 | { | ||
| 78 | struct adis16240_state *st = iio_priv(indio_dev); | ||
| 79 | |||
| 80 | iio_trigger_unregister(st->trig); | ||
| 81 | free_irq(st->us->irq, st->trig); | ||
| 82 | iio_free_trigger(st->trig); | ||
| 83 | } | ||
diff --git a/drivers/staging/iio/accel/inclinometer.h b/drivers/staging/iio/accel/inclinometer.h new file mode 100644 index 00000000000..faf73d7892e --- /dev/null +++ b/drivers/staging/iio/accel/inclinometer.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | /* | ||
| 2 | * Inclinometer related attributes | ||
| 3 | */ | ||
| 4 | #include "../sysfs.h" | ||
| 5 | |||
| 6 | #define IIO_DEV_ATTR_INCLI_X(_show, _addr) \ | ||
| 7 | IIO_DEVICE_ATTR(incli_x_raw, S_IRUGO, _show, NULL, _addr) | ||
| 8 | |||
| 9 | #define IIO_DEV_ATTR_INCLI_Y(_show, _addr) \ | ||
| 10 | IIO_DEVICE_ATTR(incli_y_raw, S_IRUGO, _show, NULL, _addr) | ||
| 11 | |||
| 12 | #define IIO_DEV_ATTR_INCLI_Z(_show, _addr) \ | ||
| 13 | IIO_DEVICE_ATTR(incli_z_raw, S_IRUGO, _show, NULL, _addr) | ||
| 14 | |||
| 15 | #define IIO_DEV_ATTR_INCLI_X_OFFSET(_mode, _show, _store, _addr) \ | ||
| 16 | IIO_DEVICE_ATTR(incli_x_offset, _mode, _show, _store, _addr) | ||
| 17 | |||
| 18 | #define IIO_DEV_ATTR_INCLI_Y_OFFSET(_mode, _show, _store, _addr) \ | ||
| 19 | IIO_DEVICE_ATTR(incli_y_offset, _mode, _show, _store, _addr) | ||
| 20 | |||
| 21 | #define IIO_DEV_ATTR_INCLI_Z_OFFSET(_mode, _show, _store, _addr) \ | ||
| 22 | IIO_DEVICE_ATTR(incli_z_offset, _mode, _show, _store, _addr) | ||
| 23 | |||
| 24 | #define IIO_CONST_ATTR_INCLI_SCALE(_string) \ | ||
| 25 | IIO_CONST_ATTR(incli_scale, _string) | ||
diff --git a/drivers/staging/iio/adc/ad7150.c b/drivers/staging/iio/adc/ad7150.c new file mode 100644 index 00000000000..04017ef6688 --- /dev/null +++ b/drivers/staging/iio/adc/ad7150.c | |||
| @@ -0,0 +1,812 @@ | |||
| 1 | /* | ||
| 2 | * AD7150 capacitive sensor driver supporting AD7150/1/6 | ||
| 3 | * | ||
| 4 | * Copyright 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/device.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/i2c.h> | ||
| 14 | |||
| 15 | #include "../iio.h" | ||
| 16 | #include "../sysfs.h" | ||
| 17 | |||
| 18 | /* | ||
| 19 | * AD7150 registers definition | ||
| 20 | */ | ||
| 21 | |||
| 22 | #define AD7150_STATUS 0 | ||
| 23 | #define AD7150_STATUS_OUT1 (1 << 3) | ||
| 24 | #define AD7150_STATUS_OUT2 (1 << 5) | ||
| 25 | #define AD7150_CH1_DATA_HIGH 1 | ||
| 26 | #define AD7150_CH1_DATA_LOW 2 | ||
| 27 | #define AD7150_CH2_DATA_HIGH 3 | ||
| 28 | #define AD7150_CH2_DATA_LOW 4 | ||
| 29 | #define AD7150_CH1_AVG_HIGH 5 | ||
| 30 | #define AD7150_CH1_AVG_LOW 6 | ||
| 31 | #define AD7150_CH2_AVG_HIGH 7 | ||
| 32 | #define AD7150_CH2_AVG_LOW 8 | ||
| 33 | #define AD7150_CH1_SENSITIVITY 9 | ||
| 34 | #define AD7150_CH1_THR_HOLD_H 9 | ||
| 35 | #define AD7150_CH1_TIMEOUT 10 | ||
| 36 | #define AD7150_CH1_THR_HOLD_L 10 | ||
| 37 | #define AD7150_CH1_SETUP 11 | ||
| 38 | #define AD7150_CH2_SENSITIVITY 12 | ||
| 39 | #define AD7150_CH2_THR_HOLD_H 12 | ||
| 40 | #define AD7150_CH2_TIMEOUT 13 | ||
| 41 | #define AD7150_CH2_THR_HOLD_L 13 | ||
| 42 | #define AD7150_CH2_SETUP 14 | ||
| 43 | #define AD7150_CFG 15 | ||
| 44 | #define AD7150_CFG_FIX (1 << 7) | ||
| 45 | #define AD7150_PD_TIMER 16 | ||
| 46 | #define AD7150_CH1_CAPDAC 17 | ||
| 47 | #define AD7150_CH2_CAPDAC 18 | ||
| 48 | #define AD7150_SN3 19 | ||
| 49 | #define AD7150_SN2 20 | ||
| 50 | #define AD7150_SN1 21 | ||
| 51 | #define AD7150_SN0 22 | ||
| 52 | #define AD7150_ID 23 | ||
| 53 | |||
| 54 | #define AD7150_MAX_CONV_MODE 4 | ||
| 55 | |||
| 56 | /* | ||
| 57 | * struct ad7150_chip_info - chip specifc information | ||
| 58 | */ | ||
| 59 | |||
| 60 | struct ad7150_chip_info { | ||
| 61 | struct i2c_client *client; | ||
| 62 | bool inter; | ||
| 63 | u16 ch1_threshold; /* Ch1 Threshold (in fixed threshold mode) */ | ||
| 64 | u8 ch1_sensitivity; /* Ch1 Sensitivity (in adaptive threshold mode) */ | ||
| 65 | u8 ch1_timeout; /* Ch1 Timeout (in adaptive threshold mode) */ | ||
| 66 | u8 ch1_setup; | ||
| 67 | u16 ch2_threshold; /* Ch2 Threshold (in fixed threshold mode) */ | ||
| 68 | u8 ch2_sensitivity; /* Ch1 Sensitivity (in adaptive threshold mode) */ | ||
| 69 | u8 ch2_timeout; /* Ch1 Timeout (in adaptive threshold mode) */ | ||
| 70 | u8 ch2_setup; | ||
| 71 | u8 powerdown_timer; | ||
| 72 | char threshold_mode[10]; /* adaptive/fixed threshold mode */ | ||
| 73 | int old_state; | ||
| 74 | char *conversion_mode; | ||
| 75 | }; | ||
| 76 | |||
| 77 | struct ad7150_conversion_mode { | ||
| 78 | char *name; | ||
| 79 | u8 reg_cfg; | ||
| 80 | }; | ||
| 81 | |||
| 82 | static struct ad7150_conversion_mode | ||
| 83 | ad7150_conv_mode_table[AD7150_MAX_CONV_MODE] = { | ||
| 84 | { "idle", 0 }, | ||
| 85 | { "continuous-conversion", 1 }, | ||
| 86 | { "single-conversion", 2 }, | ||
| 87 | { "power-down", 3 }, | ||
| 88 | }; | ||
| 89 | |||
| 90 | /* | ||
| 91 | * ad7150 register access by I2C | ||
| 92 | */ | ||
| 93 | |||
| 94 | static int ad7150_i2c_read(struct ad7150_chip_info *chip, u8 reg, u8 *data, int len) | ||
| 95 | { | ||
| 96 | struct i2c_client *client = chip->client; | ||
| 97 | int ret = 0; | ||
| 98 | |||
| 99 | ret = i2c_master_send(client, ®, 1); | ||
| 100 | if (ret < 0) { | ||
| 101 | dev_err(&client->dev, "I2C write error\n"); | ||
| 102 | return ret; | ||
| 103 | } | ||
| 104 | |||
| 105 | ret = i2c_master_recv(client, data, len); | ||
| 106 | if (ret < 0) { | ||
| 107 | dev_err(&client->dev, "I2C read error\n"); | ||
| 108 | return ret; | ||
| 109 | } | ||
| 110 | |||
| 111 | return ret; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int ad7150_i2c_write(struct ad7150_chip_info *chip, u8 reg, u8 data) | ||
| 115 | { | ||
| 116 | struct i2c_client *client = chip->client; | ||
| 117 | int ret = 0; | ||
| 118 | |||
| 119 | u8 tx[2] = { | ||
| 120 | reg, | ||
| 121 | data, | ||
| 122 | }; | ||
| 123 | |||
| 124 | ret = i2c_master_send(client, tx, 2); | ||
| 125 | if (ret < 0) | ||
| 126 | dev_err(&client->dev, "I2C write error\n"); | ||
| 127 | |||
| 128 | return ret; | ||
| 129 | } | ||
| 130 | |||
| 131 | /* | ||
| 132 | * sysfs nodes | ||
| 133 | */ | ||
| 134 | |||
| 135 | #define IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(_show) \ | ||
| 136 | IIO_DEVICE_ATTR(available_conversion_modes, S_IRUGO, _show, NULL, 0) | ||
| 137 | #define IIO_DEV_ATTR_CONVERSION_MODE(_mode, _show, _store) \ | ||
| 138 | IIO_DEVICE_ATTR(conversion_mode, _mode, _show, _store, 0) | ||
| 139 | #define IIO_DEV_ATTR_AVAIL_THRESHOLD_MODES(_show) \ | ||
| 140 | IIO_DEVICE_ATTR(available_threshold_modes, S_IRUGO, _show, NULL, 0) | ||
| 141 | #define IIO_DEV_ATTR_THRESHOLD_MODE(_mode, _show, _store) \ | ||
| 142 | IIO_DEVICE_ATTR(threshold_mode, _mode, _show, _store, 0) | ||
| 143 | #define IIO_DEV_ATTR_CH1_THRESHOLD(_mode, _show, _store) \ | ||
| 144 | IIO_DEVICE_ATTR(ch1_threshold, _mode, _show, _store, 0) | ||
| 145 | #define IIO_DEV_ATTR_CH2_THRESHOLD(_mode, _show, _store) \ | ||
| 146 | IIO_DEVICE_ATTR(ch2_threshold, _mode, _show, _store, 0) | ||
| 147 | #define IIO_DEV_ATTR_CH1_SENSITIVITY(_mode, _show, _store) \ | ||
| 148 | IIO_DEVICE_ATTR(ch1_sensitivity, _mode, _show, _store, 0) | ||
| 149 | #define IIO_DEV_ATTR_CH2_SENSITIVITY(_mode, _show, _store) \ | ||
| 150 | IIO_DEVICE_ATTR(ch2_sensitivity, _mode, _show, _store, 0) | ||
| 151 | #define IIO_DEV_ATTR_CH1_TIMEOUT(_mode, _show, _store) \ | ||
| 152 | IIO_DEVICE_ATTR(ch1_timeout, _mode, _show, _store, 0) | ||
| 153 | #define IIO_DEV_ATTR_CH2_TIMEOUT(_mode, _show, _store) \ | ||
| 154 | IIO_DEVICE_ATTR(ch2_timeout, _mode, _show, _store, 0) | ||
| 155 | #define IIO_DEV_ATTR_CH1_VALUE(_show) \ | ||
| 156 | IIO_DEVICE_ATTR(ch1_value, S_IRUGO, _show, NULL, 0) | ||
| 157 | #define IIO_DEV_ATTR_CH2_VALUE(_show) \ | ||
| 158 | IIO_DEVICE_ATTR(ch2_value, S_IRUGO, _show, NULL, 0) | ||
| 159 | #define IIO_DEV_ATTR_CH1_SETUP(_mode, _show, _store) \ | ||
| 160 | IIO_DEVICE_ATTR(ch1_setup, _mode, _show, _store, 0) | ||
| 161 | #define IIO_DEV_ATTR_CH2_SETUP(_mode, _show, _store) \ | ||
| 162 | IIO_DEVICE_ATTR(ch2_setup, _mode, _show, _store, 0) | ||
| 163 | #define IIO_DEV_ATTR_POWERDOWN_TIMER(_mode, _show, _store) \ | ||
| 164 | IIO_DEVICE_ATTR(powerdown_timer, _mode, _show, _store, 0) | ||
| 165 | |||
| 166 | static ssize_t ad7150_show_conversion_modes(struct device *dev, | ||
| 167 | struct device_attribute *attr, | ||
| 168 | char *buf) | ||
| 169 | { | ||
| 170 | int i; | ||
| 171 | int len = 0; | ||
| 172 | |||
| 173 | for (i = 0; i < AD7150_MAX_CONV_MODE; i++) | ||
| 174 | len += sprintf(buf + len, "%s\n", ad7150_conv_mode_table[i].name); | ||
| 175 | |||
| 176 | return len; | ||
| 177 | } | ||
| 178 | |||
| 179 | static IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(ad7150_show_conversion_modes); | ||
| 180 | |||
| 181 | static ssize_t ad7150_show_conversion_mode(struct device *dev, | ||
| 182 | struct device_attribute *attr, | ||
| 183 | char *buf) | ||
| 184 | { | ||
| 185 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 186 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 187 | |||
| 188 | return sprintf(buf, "%s\n", chip->conversion_mode); | ||
| 189 | } | ||
| 190 | |||
| 191 | static ssize_t ad7150_store_conversion_mode(struct device *dev, | ||
| 192 | struct device_attribute *attr, | ||
| 193 | const char *buf, | ||
| 194 | size_t len) | ||
| 195 | { | ||
| 196 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 197 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 198 | u8 cfg; | ||
| 199 | int i; | ||
| 200 | |||
| 201 | ad7150_i2c_read(chip, AD7150_CFG, &cfg, 1); | ||
| 202 | |||
| 203 | for (i = 0; i < AD7150_MAX_CONV_MODE; i++) { | ||
| 204 | if (strncmp(buf, ad7150_conv_mode_table[i].name, | ||
| 205 | strlen(ad7150_conv_mode_table[i].name) - 1) == 0) { | ||
| 206 | chip->conversion_mode = ad7150_conv_mode_table[i].name; | ||
| 207 | cfg |= 0x18 | ad7150_conv_mode_table[i].reg_cfg; | ||
| 208 | ad7150_i2c_write(chip, AD7150_CFG, cfg); | ||
| 209 | return len; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | dev_err(dev, "not supported conversion mode\n"); | ||
| 214 | |||
| 215 | return -EINVAL; | ||
| 216 | } | ||
| 217 | |||
| 218 | static IIO_DEV_ATTR_CONVERSION_MODE(S_IRUGO | S_IWUSR, | ||
| 219 | ad7150_show_conversion_mode, | ||
| 220 | ad7150_store_conversion_mode); | ||
| 221 | |||
| 222 | static ssize_t ad7150_show_threshold_modes(struct device *dev, | ||
| 223 | struct device_attribute *attr, | ||
| 224 | char *buf) | ||
| 225 | { | ||
| 226 | return sprintf(buf, "adaptive\nfixed\n"); | ||
| 227 | } | ||
| 228 | |||
| 229 | static IIO_DEV_ATTR_AVAIL_THRESHOLD_MODES(ad7150_show_threshold_modes); | ||
| 230 | |||
| 231 | static ssize_t ad7150_show_ch1_value(struct device *dev, | ||
| 232 | struct device_attribute *attr, | ||
| 233 | char *buf) | ||
| 234 | { | ||
| 235 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 236 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 237 | u8 data[2]; | ||
| 238 | |||
| 239 | ad7150_i2c_read(chip, AD7150_CH1_DATA_HIGH, data, 2); | ||
| 240 | return sprintf(buf, "%d\n", ((int) data[0] << 8) | data[1]); | ||
| 241 | } | ||
| 242 | |||
| 243 | static IIO_DEV_ATTR_CH1_VALUE(ad7150_show_ch1_value); | ||
| 244 | |||
| 245 | static ssize_t ad7150_show_ch2_value(struct device *dev, | ||
| 246 | struct device_attribute *attr, | ||
| 247 | char *buf) | ||
| 248 | { | ||
| 249 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 250 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 251 | u8 data[2]; | ||
| 252 | |||
| 253 | ad7150_i2c_read(chip, AD7150_CH2_DATA_HIGH, data, 2); | ||
| 254 | return sprintf(buf, "%d\n", ((int) data[0] << 8) | data[1]); | ||
| 255 | } | ||
| 256 | |||
| 257 | static IIO_DEV_ATTR_CH2_VALUE(ad7150_show_ch2_value); | ||
| 258 | |||
| 259 | static ssize_t ad7150_show_threshold_mode(struct device *dev, | ||
| 260 | struct device_attribute *attr, | ||
| 261 | char *buf) | ||
| 262 | { | ||
| 263 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 264 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 265 | |||
| 266 | return sprintf(buf, "%s\n", chip->threshold_mode); | ||
| 267 | } | ||
| 268 | |||
| 269 | static ssize_t ad7150_store_threshold_mode(struct device *dev, | ||
| 270 | struct device_attribute *attr, | ||
| 271 | const char *buf, | ||
| 272 | size_t len) | ||
| 273 | { | ||
| 274 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 275 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 276 | u8 cfg; | ||
| 277 | |||
| 278 | ad7150_i2c_read(chip, AD7150_CFG, &cfg, 1); | ||
| 279 | |||
| 280 | if (strncmp(buf, "fixed", 5) == 0) { | ||
| 281 | strcpy(chip->threshold_mode, "fixed"); | ||
| 282 | cfg |= AD7150_CFG_FIX; | ||
| 283 | ad7150_i2c_write(chip, AD7150_CFG, cfg); | ||
| 284 | |||
| 285 | return len; | ||
| 286 | } else if (strncmp(buf, "adaptive", 8) == 0) { | ||
| 287 | strcpy(chip->threshold_mode, "adaptive"); | ||
| 288 | cfg &= ~AD7150_CFG_FIX; | ||
| 289 | ad7150_i2c_write(chip, AD7150_CFG, cfg); | ||
| 290 | |||
| 291 | return len; | ||
| 292 | } | ||
| 293 | |||
| 294 | dev_err(dev, "not supported threshold mode\n"); | ||
| 295 | return -EINVAL; | ||
| 296 | } | ||
| 297 | |||
| 298 | static IIO_DEV_ATTR_THRESHOLD_MODE(S_IRUGO | S_IWUSR, | ||
| 299 | ad7150_show_threshold_mode, | ||
| 300 | ad7150_store_threshold_mode); | ||
| 301 | |||
| 302 | static ssize_t ad7150_show_ch1_threshold(struct device *dev, | ||
| 303 | struct device_attribute *attr, | ||
| 304 | char *buf) | ||
| 305 | { | ||
| 306 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 307 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 308 | |||
| 309 | return sprintf(buf, "%d\n", chip->ch1_threshold); | ||
| 310 | } | ||
| 311 | |||
| 312 | static ssize_t ad7150_store_ch1_threshold(struct device *dev, | ||
| 313 | struct device_attribute *attr, | ||
| 314 | const char *buf, | ||
| 315 | size_t len) | ||
| 316 | { | ||
| 317 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 318 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 319 | unsigned long data; | ||
| 320 | int ret; | ||
| 321 | |||
| 322 | ret = strict_strtoul(buf, 10, &data); | ||
| 323 | |||
| 324 | if ((!ret) && (data < 0x10000)) { | ||
| 325 | ad7150_i2c_write(chip, AD7150_CH1_THR_HOLD_H, data >> 8); | ||
| 326 | ad7150_i2c_write(chip, AD7150_CH1_THR_HOLD_L, data); | ||
| 327 | chip->ch1_threshold = data; | ||
| 328 | return len; | ||
| 329 | } | ||
| 330 | |||
| 331 | return -EINVAL; | ||
| 332 | } | ||
| 333 | |||
| 334 | static IIO_DEV_ATTR_CH1_THRESHOLD(S_IRUGO | S_IWUSR, | ||
| 335 | ad7150_show_ch1_threshold, | ||
| 336 | ad7150_store_ch1_threshold); | ||
| 337 | |||
| 338 | static ssize_t ad7150_show_ch2_threshold(struct device *dev, | ||
| 339 | struct device_attribute *attr, | ||
| 340 | char *buf) | ||
| 341 | { | ||
| 342 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 343 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 344 | |||
| 345 | return sprintf(buf, "%d\n", chip->ch2_threshold); | ||
| 346 | } | ||
| 347 | |||
| 348 | static ssize_t ad7150_store_ch2_threshold(struct device *dev, | ||
| 349 | struct device_attribute *attr, | ||
| 350 | const char *buf, | ||
| 351 | size_t len) | ||
| 352 | { | ||
| 353 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 354 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 355 | unsigned long data; | ||
| 356 | int ret; | ||
| 357 | |||
| 358 | ret = strict_strtoul(buf, 10, &data); | ||
| 359 | |||
| 360 | if ((!ret) && (data < 0x10000)) { | ||
| 361 | ad7150_i2c_write(chip, AD7150_CH2_THR_HOLD_H, data >> 8); | ||
| 362 | ad7150_i2c_write(chip, AD7150_CH2_THR_HOLD_L, data); | ||
| 363 | chip->ch2_threshold = data; | ||
| 364 | return len; | ||
| 365 | } | ||
| 366 | |||
| 367 | return -EINVAL; | ||
| 368 | } | ||
| 369 | |||
| 370 | static IIO_DEV_ATTR_CH2_THRESHOLD(S_IRUGO | S_IWUSR, | ||
| 371 | ad7150_show_ch2_threshold, | ||
| 372 | ad7150_store_ch2_threshold); | ||
| 373 | |||
| 374 | static ssize_t ad7150_show_ch1_sensitivity(struct device *dev, | ||
| 375 | struct device_attribute *attr, | ||
| 376 | char *buf) | ||
| 377 | { | ||
| 378 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 379 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 380 | |||
| 381 | return sprintf(buf, "%d\n", chip->ch1_sensitivity); | ||
| 382 | } | ||
| 383 | |||
| 384 | static ssize_t ad7150_store_ch1_sensitivity(struct device *dev, | ||
| 385 | struct device_attribute *attr, | ||
| 386 | const char *buf, | ||
| 387 | size_t len) | ||
| 388 | { | ||
| 389 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 390 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 391 | unsigned long data; | ||
| 392 | int ret; | ||
| 393 | |||
| 394 | ret = strict_strtoul(buf, 10, &data); | ||
| 395 | |||
| 396 | if ((!ret) && (data < 0x100)) { | ||
| 397 | ad7150_i2c_write(chip, AD7150_CH1_SENSITIVITY, data); | ||
| 398 | chip->ch1_sensitivity = data; | ||
| 399 | return len; | ||
| 400 | } | ||
| 401 | |||
| 402 | return -EINVAL; | ||
| 403 | } | ||
| 404 | |||
| 405 | static IIO_DEV_ATTR_CH1_SENSITIVITY(S_IRUGO | S_IWUSR, | ||
| 406 | ad7150_show_ch1_sensitivity, | ||
| 407 | ad7150_store_ch1_sensitivity); | ||
| 408 | |||
| 409 | static ssize_t ad7150_show_ch2_sensitivity(struct device *dev, | ||
| 410 | struct device_attribute *attr, | ||
| 411 | char *buf) | ||
| 412 | { | ||
| 413 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 414 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 415 | |||
| 416 | return sprintf(buf, "%d\n", chip->ch2_sensitivity); | ||
| 417 | } | ||
| 418 | |||
| 419 | static ssize_t ad7150_store_ch2_sensitivity(struct device *dev, | ||
| 420 | struct device_attribute *attr, | ||
| 421 | const char *buf, | ||
| 422 | size_t len) | ||
| 423 | { | ||
| 424 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 425 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 426 | unsigned long data; | ||
| 427 | int ret; | ||
| 428 | |||
| 429 | ret = strict_strtoul(buf, 10, &data); | ||
| 430 | |||
| 431 | if ((!ret) && (data < 0x100)) { | ||
| 432 | ad7150_i2c_write(chip, AD7150_CH2_SENSITIVITY, data); | ||
| 433 | chip->ch2_sensitivity = data; | ||
| 434 | return len; | ||
| 435 | } | ||
| 436 | |||
| 437 | return -EINVAL; | ||
| 438 | } | ||
| 439 | |||
| 440 | static IIO_DEV_ATTR_CH2_SENSITIVITY(S_IRUGO | S_IWUSR, | ||
| 441 | ad7150_show_ch2_sensitivity, | ||
| 442 | ad7150_store_ch2_sensitivity); | ||
| 443 | |||
| 444 | static ssize_t ad7150_show_ch1_timeout(struct device *dev, | ||
| 445 | struct device_attribute *attr, | ||
| 446 | char *buf) | ||
| 447 | { | ||
| 448 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 449 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 450 | |||
| 451 | return sprintf(buf, "%d\n", chip->ch1_timeout); | ||
| 452 | } | ||
| 453 | |||
| 454 | static ssize_t ad7150_store_ch1_timeout(struct device *dev, | ||
| 455 | struct device_attribute *attr, | ||
| 456 | const char *buf, | ||
| 457 | size_t len) | ||
| 458 | { | ||
| 459 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 460 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 461 | unsigned long data; | ||
| 462 | int ret; | ||
| 463 | |||
| 464 | ret = strict_strtoul(buf, 10, &data); | ||
| 465 | |||
| 466 | if ((!ret) && (data < 0x100)) { | ||
| 467 | ad7150_i2c_write(chip, AD7150_CH1_TIMEOUT, data); | ||
| 468 | chip->ch1_timeout = data; | ||
| 469 | return len; | ||
| 470 | } | ||
| 471 | |||
| 472 | return -EINVAL; | ||
| 473 | } | ||
| 474 | |||
| 475 | static IIO_DEV_ATTR_CH1_TIMEOUT(S_IRUGO | S_IWUSR, | ||
| 476 | ad7150_show_ch1_timeout, | ||
| 477 | ad7150_store_ch1_timeout); | ||
| 478 | |||
| 479 | static ssize_t ad7150_show_ch2_timeout(struct device *dev, | ||
| 480 | struct device_attribute *attr, | ||
| 481 | char *buf) | ||
| 482 | { | ||
| 483 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 484 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 485 | |||
| 486 | return sprintf(buf, "%d\n", chip->ch2_timeout); | ||
| 487 | } | ||
| 488 | |||
| 489 | static ssize_t ad7150_store_ch2_timeout(struct device *dev, | ||
| 490 | struct device_attribute *attr, | ||
| 491 | const char *buf, | ||
| 492 | size_t len) | ||
| 493 | { | ||
| 494 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 495 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 496 | unsigned long data; | ||
| 497 | int ret; | ||
| 498 | |||
| 499 | ret = strict_strtoul(buf, 10, &data); | ||
| 500 | |||
| 501 | if ((!ret) && (data < 0x100)) { | ||
| 502 | ad7150_i2c_write(chip, AD7150_CH2_TIMEOUT, data); | ||
| 503 | chip->ch2_timeout = data; | ||
| 504 | return len; | ||
| 505 | } | ||
| 506 | |||
| 507 | return -EINVAL; | ||
| 508 | } | ||
| 509 | |||
| 510 | static IIO_DEV_ATTR_CH2_TIMEOUT(S_IRUGO | S_IWUSR, | ||
| 511 | ad7150_show_ch2_timeout, | ||
| 512 | ad7150_store_ch2_timeout); | ||
| 513 | |||
| 514 | static ssize_t ad7150_show_ch1_setup(struct device *dev, | ||
| 515 | struct device_attribute *attr, | ||
| 516 | char *buf) | ||
| 517 | { | ||
| 518 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 519 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 520 | |||
| 521 | return sprintf(buf, "0x%02x\n", chip->ch1_setup); | ||
| 522 | } | ||
| 523 | |||
| 524 | static ssize_t ad7150_store_ch1_setup(struct device *dev, | ||
| 525 | struct device_attribute *attr, | ||
| 526 | const char *buf, | ||
| 527 | size_t len) | ||
| 528 | { | ||
| 529 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 530 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 531 | unsigned long data; | ||
| 532 | int ret; | ||
| 533 | |||
| 534 | ret = strict_strtoul(buf, 10, &data); | ||
| 535 | |||
| 536 | if ((!ret) && (data < 0x100)) { | ||
| 537 | ad7150_i2c_write(chip, AD7150_CH1_SETUP, data); | ||
| 538 | chip->ch1_setup = data; | ||
| 539 | return len; | ||
| 540 | } | ||
| 541 | |||
| 542 | |||
| 543 | return -EINVAL; | ||
| 544 | } | ||
| 545 | |||
| 546 | static IIO_DEV_ATTR_CH1_SETUP(S_IRUGO | S_IWUSR, | ||
| 547 | ad7150_show_ch1_setup, | ||
| 548 | ad7150_store_ch1_setup); | ||
| 549 | |||
| 550 | static ssize_t ad7150_show_ch2_setup(struct device *dev, | ||
| 551 | struct device_attribute *attr, | ||
| 552 | char *buf) | ||
| 553 | { | ||
| 554 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 555 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 556 | |||
| 557 | return sprintf(buf, "0x%02x\n", chip->ch2_setup); | ||
| 558 | } | ||
| 559 | |||
| 560 | static ssize_t ad7150_store_ch2_setup(struct device *dev, | ||
| 561 | struct device_attribute *attr, | ||
| 562 | const char *buf, | ||
| 563 | size_t len) | ||
| 564 | { | ||
| 565 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 566 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 567 | unsigned long data; | ||
| 568 | int ret; | ||
| 569 | |||
| 570 | ret = strict_strtoul(buf, 10, &data); | ||
| 571 | |||
| 572 | if ((!ret) && (data < 0x100)) { | ||
| 573 | ad7150_i2c_write(chip, AD7150_CH2_SETUP, data); | ||
| 574 | chip->ch2_setup = data; | ||
| 575 | return len; | ||
| 576 | } | ||
| 577 | |||
| 578 | return -EINVAL; | ||
| 579 | } | ||
| 580 | |||
| 581 | static IIO_DEV_ATTR_CH2_SETUP(S_IRUGO | S_IWUSR, | ||
| 582 | ad7150_show_ch2_setup, | ||
| 583 | ad7150_store_ch2_setup); | ||
| 584 | |||
| 585 | static ssize_t ad7150_show_powerdown_timer(struct device *dev, | ||
| 586 | struct device_attribute *attr, | ||
| 587 | char *buf) | ||
| 588 | { | ||
| 589 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 590 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 591 | |||
| 592 | return sprintf(buf, "0x%02x\n", chip->powerdown_timer); | ||
| 593 | } | ||
| 594 | |||
| 595 | static ssize_t ad7150_store_powerdown_timer(struct device *dev, | ||
| 596 | struct device_attribute *attr, | ||
| 597 | const char *buf, | ||
| 598 | size_t len) | ||
| 599 | { | ||
| 600 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 601 | struct ad7150_chip_info *chip = iio_priv(dev_info); | ||
| 602 | unsigned long data; | ||
| 603 | int ret; | ||
| 604 | |||
| 605 | ret = strict_strtoul(buf, 10, &data); | ||
| 606 | |||
| 607 | if ((!ret) && (data < 0x40)) { | ||
| 608 | chip->powerdown_timer = data; | ||
| 609 | return len; | ||
| 610 | } | ||
| 611 | |||
| 612 | return -EINVAL; | ||
| 613 | } | ||
| 614 | |||
| 615 | static IIO_DEV_ATTR_POWERDOWN_TIMER(S_IRUGO | S_IWUSR, | ||
| 616 | ad7150_show_powerdown_timer, | ||
| 617 | ad7150_store_powerdown_timer); | ||
| 618 | |||
| 619 | static struct attribute *ad7150_attributes[] = { | ||
| 620 | &iio_dev_attr_available_threshold_modes.dev_attr.attr, | ||
| 621 | &iio_dev_attr_threshold_mode.dev_attr.attr, | ||
| 622 | &iio_dev_attr_ch1_threshold.dev_attr.attr, | ||
| 623 | &iio_dev_attr_ch2_threshold.dev_attr.attr, | ||
| 624 | &iio_dev_attr_ch1_timeout.dev_attr.attr, | ||
| 625 | &iio_dev_attr_ch2_timeout.dev_attr.attr, | ||
| 626 | &iio_dev_attr_ch1_setup.dev_attr.attr, | ||
| 627 | &iio_dev_attr_ch2_setup.dev_attr.attr, | ||
| 628 | &iio_dev_attr_ch1_sensitivity.dev_attr.attr, | ||
| 629 | &iio_dev_attr_ch2_sensitivity.dev_attr.attr, | ||
| 630 | &iio_dev_attr_powerdown_timer.dev_attr.attr, | ||
| 631 | &iio_dev_attr_ch1_value.dev_attr.attr, | ||
| 632 | &iio_dev_attr_ch2_value.dev_attr.attr, | ||
| 633 | NULL, | ||
| 634 | }; | ||
| 635 | |||
| 636 | static const struct attribute_group ad7150_attribute_group = { | ||
| 637 | .attrs = ad7150_attributes, | ||
| 638 | }; | ||
| 639 | |||
| 640 | /* | ||
| 641 | * threshold events | ||
| 642 | */ | ||
| 643 | |||
| 644 | static irqreturn_t ad7150_event_handler(int irq, void *private) | ||
| 645 | { | ||
| 646 | struct iio_dev *indio_dev = private; | ||
| 647 | struct ad7150_chip_info *chip = iio_priv(indio_dev); | ||
| 648 | u8 int_status; | ||
| 649 | s64 timestamp = iio_get_time_ns(); | ||
| 650 | |||
| 651 | ad7150_i2c_read(chip, AD7150_STATUS, &int_status, 1); | ||
| 652 | |||
| 653 | if ((int_status & AD7150_STATUS_OUT1) && !(chip->old_state & AD7150_STATUS_OUT1)) | ||
| 654 | iio_push_event(indio_dev, 0, | ||
| 655 | IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_IN, | ||
| 656 | 0, | ||
| 657 | IIO_EV_TYPE_THRESH, | ||
| 658 | IIO_EV_DIR_RISING), | ||
| 659 | timestamp); | ||
| 660 | else if ((!(int_status & AD7150_STATUS_OUT1)) && (chip->old_state & AD7150_STATUS_OUT1)) | ||
| 661 | iio_push_event(indio_dev, 0, | ||
| 662 | IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_IN, | ||
| 663 | 0, | ||
| 664 | IIO_EV_TYPE_THRESH, | ||
| 665 | IIO_EV_DIR_FALLING), | ||
| 666 | timestamp); | ||
| 667 | |||
| 668 | if ((int_status & AD7150_STATUS_OUT2) && !(chip->old_state & AD7150_STATUS_OUT2)) | ||
| 669 | iio_push_event(indio_dev, 0, | ||
| 670 | IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_IN, | ||
| 671 | 1, | ||
| 672 | IIO_EV_TYPE_THRESH, | ||
| 673 | IIO_EV_DIR_RISING), | ||
| 674 | timestamp); | ||
| 675 | else if ((!(int_status & AD7150_STATUS_OUT2)) && (chip->old_state & AD7150_STATUS_OUT2)) | ||
| 676 | iio_push_event(indio_dev, 0, | ||
| 677 | IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_IN, | ||
| 678 | 1, | ||
| 679 | IIO_EV_TYPE_THRESH, | ||
| 680 | IIO_EV_DIR_FALLING), | ||
| 681 | timestamp); | ||
| 682 | return IRQ_HANDLED; | ||
| 683 | } | ||
| 684 | |||
| 685 | static IIO_CONST_ATTR(ch1_high_en, "1"); | ||
| 686 | static IIO_CONST_ATTR(ch2_high_en, "1"); | ||
| 687 | static IIO_CONST_ATTR(ch1_low_en, "1"); | ||
| 688 | static IIO_CONST_ATTR(ch2_low_en, "1"); | ||
| 689 | |||
| 690 | static struct attribute *ad7150_event_attributes[] = { | ||
| 691 | &iio_const_attr_ch1_high_en.dev_attr.attr, | ||
| 692 | &iio_const_attr_ch2_high_en.dev_attr.attr, | ||
| 693 | &iio_const_attr_ch1_low_en.dev_attr.attr, | ||
| 694 | &iio_const_attr_ch2_low_en.dev_attr.attr, | ||
| 695 | NULL, | ||
| 696 | }; | ||
| 697 | |||
| 698 | static struct attribute_group ad7150_event_attribute_group = { | ||
| 699 | .attrs = ad7150_event_attributes, | ||
| 700 | }; | ||
| 701 | |||
| 702 | static const struct iio_info ad7150_info = { | ||
| 703 | .attrs = &ad7150_attribute_group, | ||
| 704 | .num_interrupt_lines = 1, | ||
| 705 | .event_attrs = &ad7150_event_attribute_group, | ||
| 706 | .driver_module = THIS_MODULE, | ||
| 707 | }; | ||
| 708 | /* | ||
| 709 | * device probe and remove | ||
| 710 | */ | ||
| 711 | |||
| 712 | static int __devinit ad7150_probe(struct i2c_client *client, | ||
| 713 | const struct i2c_device_id *id) | ||
| 714 | { | ||
| 715 | int ret = 0, regdone = 0; | ||
| 716 | struct ad7150_chip_info *chip; | ||
| 717 | struct iio_dev *indio_dev; | ||
| 718 | |||
| 719 | indio_dev = iio_allocate_device(sizeof(*chip)); | ||
| 720 | if (indio_dev == NULL) { | ||
| 721 | ret = -ENOMEM; | ||
| 722 | goto error_ret; | ||
| 723 | } | ||
| 724 | chip = iio_priv(indio_dev); | ||
| 725 | /* this is only used for device removal purposes */ | ||
| 726 | i2c_set_clientdata(client, indio_dev); | ||
| 727 | |||
| 728 | chip->client = client; | ||
| 729 | |||
| 730 | /* Establish that the iio_dev is a child of the i2c device */ | ||
| 731 | indio_dev->name = id->name; | ||
| 732 | indio_dev->dev.parent = &client->dev; | ||
| 733 | |||
| 734 | indio_dev->info = &ad7150_info; | ||
| 735 | |||
| 736 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 737 | |||
| 738 | ret = iio_device_register(indio_dev); | ||
| 739 | if (ret) | ||
| 740 | goto error_free_dev; | ||
| 741 | regdone = 1; | ||
| 742 | |||
| 743 | if (client->irq) { | ||
| 744 | ret = request_threaded_irq(client->irq, | ||
| 745 | NULL, | ||
| 746 | &ad7150_event_handler, | ||
| 747 | IRQF_TRIGGER_RISING | | ||
| 748 | IRQF_TRIGGER_FALLING, | ||
| 749 | "ad7150", | ||
| 750 | indio_dev); | ||
| 751 | if (ret) | ||
| 752 | goto error_free_dev; | ||
| 753 | } | ||
| 754 | |||
| 755 | dev_err(&client->dev, "%s capacitive sensor registered, irq: %d\n", id->name, client->irq); | ||
| 756 | |||
| 757 | return 0; | ||
| 758 | |||
| 759 | error_free_dev: | ||
| 760 | if (regdone) | ||
| 761 | iio_device_unregister(indio_dev); | ||
| 762 | else | ||
| 763 | iio_free_device(indio_dev); | ||
| 764 | error_ret: | ||
| 765 | return ret; | ||
| 766 | } | ||
| 767 | |||
| 768 | static int __devexit ad7150_remove(struct i2c_client *client) | ||
| 769 | { | ||
| 770 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | ||
| 771 | |||
| 772 | if (client->irq) | ||
| 773 | free_irq(client->irq, indio_dev); | ||
| 774 | iio_device_unregister(indio_dev); | ||
| 775 | |||
| 776 | return 0; | ||
| 777 | } | ||
| 778 | |||
| 779 | static const struct i2c_device_id ad7150_id[] = { | ||
| 780 | { "ad7150", 0 }, | ||
| 781 | { "ad7151", 0 }, | ||
| 782 | { "ad7156", 0 }, | ||
| 783 | {} | ||
| 784 | }; | ||
| 785 | |||
| 786 | MODULE_DEVICE_TABLE(i2c, ad7150_id); | ||
| 787 | |||
| 788 | static struct i2c_driver ad7150_driver = { | ||
| 789 | .driver = { | ||
| 790 | .name = "ad7150", | ||
| 791 | }, | ||
| 792 | .probe = ad7150_probe, | ||
| 793 | .remove = __devexit_p(ad7150_remove), | ||
| 794 | .id_table = ad7150_id, | ||
| 795 | }; | ||
| 796 | |||
| 797 | static __init int ad7150_init(void) | ||
| 798 | { | ||
| 799 | return i2c_add_driver(&ad7150_driver); | ||
| 800 | } | ||
| 801 | |||
| 802 | static __exit void ad7150_exit(void) | ||
| 803 | { | ||
| 804 | i2c_del_driver(&ad7150_driver); | ||
| 805 | } | ||
| 806 | |||
| 807 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | ||
| 808 | MODULE_DESCRIPTION("Analog Devices ad7150/1/6 capacitive sensor driver"); | ||
| 809 | MODULE_LICENSE("GPL v2"); | ||
| 810 | |||
| 811 | module_init(ad7150_init); | ||
| 812 | module_exit(ad7150_exit); | ||
diff --git a/drivers/staging/iio/adc/ad7152.c b/drivers/staging/iio/adc/ad7152.c new file mode 100644 index 00000000000..21f5f380fb5 --- /dev/null +++ b/drivers/staging/iio/adc/ad7152.c | |||
| @@ -0,0 +1,586 @@ | |||
| 1 | /* | ||
| 2 | * AD7152 capacitive sensor driver supporting AD7152/3 | ||
| 3 | * | ||
| 4 | * Copyright 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/device.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/sysfs.h> | ||
| 14 | #include <linux/i2c.h> | ||
| 15 | |||
| 16 | #include "../iio.h" | ||
| 17 | #include "../sysfs.h" | ||
| 18 | |||
| 19 | /* | ||
| 20 | * AD7152 registers definition | ||
| 21 | */ | ||
| 22 | |||
| 23 | #define AD7152_STATUS 0 | ||
| 24 | #define AD7152_STATUS_RDY1 (1 << 0) | ||
| 25 | #define AD7152_STATUS_RDY2 (1 << 1) | ||
| 26 | #define AD7152_CH1_DATA_HIGH 1 | ||
| 27 | #define AD7152_CH1_DATA_LOW 2 | ||
| 28 | #define AD7152_CH2_DATA_HIGH 3 | ||
| 29 | #define AD7152_CH2_DATA_LOW 4 | ||
| 30 | #define AD7152_CH1_OFFS_HIGH 5 | ||
| 31 | #define AD7152_CH1_OFFS_LOW 6 | ||
| 32 | #define AD7152_CH2_OFFS_HIGH 7 | ||
| 33 | #define AD7152_CH2_OFFS_LOW 8 | ||
| 34 | #define AD7152_CH1_GAIN_HIGH 9 | ||
| 35 | #define AD7152_CH1_GAIN_LOW 10 | ||
| 36 | #define AD7152_CH1_SETUP 11 | ||
| 37 | #define AD7152_CH2_GAIN_HIGH 12 | ||
| 38 | #define AD7152_CH2_GAIN_LOW 13 | ||
| 39 | #define AD7152_CH2_SETUP 14 | ||
| 40 | #define AD7152_CFG 15 | ||
| 41 | #define AD7152_RESEVERD 16 | ||
| 42 | #define AD7152_CAPDAC_POS 17 | ||
| 43 | #define AD7152_CAPDAC_NEG 18 | ||
| 44 | #define AD7152_CFG2 26 | ||
| 45 | |||
| 46 | #define AD7152_MAX_CONV_MODE 6 | ||
| 47 | |||
| 48 | /* | ||
| 49 | * struct ad7152_chip_info - chip specifc information | ||
| 50 | */ | ||
| 51 | |||
| 52 | struct ad7152_chip_info { | ||
| 53 | struct i2c_client *client; | ||
| 54 | u16 ch1_offset; /* Channel 1 offset calibration coefficient */ | ||
| 55 | u16 ch1_gain; /* Channel 1 gain coefficient */ | ||
| 56 | u8 ch1_setup; | ||
| 57 | u16 ch2_offset; /* Channel 2 offset calibration coefficient */ | ||
| 58 | u16 ch2_gain; /* Channel 1 gain coefficient */ | ||
| 59 | u8 ch2_setup; | ||
| 60 | u8 filter_rate_setup; /* Capacitive channel digital filter setup; conversion time/update rate setup per channel */ | ||
| 61 | char *conversion_mode; | ||
| 62 | }; | ||
| 63 | |||
| 64 | struct ad7152_conversion_mode { | ||
| 65 | char *name; | ||
| 66 | u8 reg_cfg; | ||
| 67 | }; | ||
| 68 | |||
| 69 | static struct ad7152_conversion_mode | ||
| 70 | ad7152_conv_mode_table[AD7152_MAX_CONV_MODE] = { | ||
| 71 | { "idle", 0 }, | ||
| 72 | { "continuous-conversion", 1 }, | ||
| 73 | { "single-conversion", 2 }, | ||
| 74 | { "power-down", 3 }, | ||
| 75 | { "offset-calibration", 5 }, | ||
| 76 | { "gain-calibration", 6 }, | ||
| 77 | }; | ||
| 78 | |||
| 79 | /* | ||
| 80 | * ad7152 register access by I2C | ||
| 81 | */ | ||
| 82 | |||
| 83 | static int ad7152_i2c_read(struct ad7152_chip_info *chip, u8 reg, u8 *data, int len) | ||
| 84 | { | ||
| 85 | struct i2c_client *client = chip->client; | ||
| 86 | int ret; | ||
| 87 | |||
| 88 | ret = i2c_master_send(client, ®, 1); | ||
| 89 | if (ret < 0) { | ||
| 90 | dev_err(&client->dev, "I2C write error\n"); | ||
| 91 | return ret; | ||
| 92 | } | ||
| 93 | |||
| 94 | ret = i2c_master_recv(client, data, len); | ||
| 95 | if (ret < 0) { | ||
| 96 | dev_err(&client->dev, "I2C read error\n"); | ||
| 97 | } | ||
| 98 | |||
| 99 | return ret; | ||
| 100 | } | ||
| 101 | |||
| 102 | static int ad7152_i2c_write(struct ad7152_chip_info *chip, u8 reg, u8 data) | ||
| 103 | { | ||
| 104 | struct i2c_client *client = chip->client; | ||
| 105 | int ret; | ||
| 106 | |||
| 107 | u8 tx[2] = { | ||
| 108 | reg, | ||
| 109 | data, | ||
| 110 | }; | ||
| 111 | |||
| 112 | ret = i2c_master_send(client, tx, 2); | ||
| 113 | if (ret < 0) | ||
| 114 | dev_err(&client->dev, "I2C write error\n"); | ||
| 115 | |||
| 116 | return ret; | ||
| 117 | } | ||
| 118 | |||
| 119 | /* | ||
| 120 | * sysfs nodes | ||
| 121 | */ | ||
| 122 | |||
| 123 | #define IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(_show) \ | ||
| 124 | IIO_DEVICE_ATTR(available_conversion_modes, S_IRUGO, _show, NULL, 0) | ||
| 125 | #define IIO_DEV_ATTR_CONVERSION_MODE(_mode, _show, _store) \ | ||
| 126 | IIO_DEVICE_ATTR(conversion_mode, _mode, _show, _store, 0) | ||
| 127 | #define IIO_DEV_ATTR_CH1_OFFSET(_mode, _show, _store) \ | ||
| 128 | IIO_DEVICE_ATTR(ch1_offset, _mode, _show, _store, 0) | ||
| 129 | #define IIO_DEV_ATTR_CH2_OFFSET(_mode, _show, _store) \ | ||
| 130 | IIO_DEVICE_ATTR(ch2_offset, _mode, _show, _store, 0) | ||
| 131 | #define IIO_DEV_ATTR_CH1_GAIN(_mode, _show, _store) \ | ||
| 132 | IIO_DEVICE_ATTR(ch1_gain, _mode, _show, _store, 0) | ||
| 133 | #define IIO_DEV_ATTR_CH2_GAIN(_mode, _show, _store) \ | ||
| 134 | IIO_DEVICE_ATTR(ch2_gain, _mode, _show, _store, 0) | ||
| 135 | #define IIO_DEV_ATTR_CH1_VALUE(_show) \ | ||
| 136 | IIO_DEVICE_ATTR(ch1_value, S_IRUGO, _show, NULL, 0) | ||
| 137 | #define IIO_DEV_ATTR_CH2_VALUE(_show) \ | ||
| 138 | IIO_DEVICE_ATTR(ch2_value, S_IRUGO, _show, NULL, 0) | ||
| 139 | #define IIO_DEV_ATTR_CH1_SETUP(_mode, _show, _store) \ | ||
| 140 | IIO_DEVICE_ATTR(ch1_setup, _mode, _show, _store, 0) | ||
| 141 | #define IIO_DEV_ATTR_CH2_SETUP(_mode, _show, _store) \ | ||
| 142 | IIO_DEVICE_ATTR(ch2_setup, _mode, _show, _store, 0) | ||
| 143 | #define IIO_DEV_ATTR_FILTER_RATE_SETUP(_mode, _show, _store) \ | ||
| 144 | IIO_DEVICE_ATTR(filter_rate_setup, _mode, _show, _store, 0) | ||
| 145 | |||
| 146 | static ssize_t ad7152_show_conversion_modes(struct device *dev, | ||
| 147 | struct device_attribute *attr, | ||
| 148 | char *buf) | ||
| 149 | { | ||
| 150 | int i; | ||
| 151 | int len = 0; | ||
| 152 | |||
| 153 | for (i = 0; i < AD7152_MAX_CONV_MODE; i++) | ||
| 154 | len += sprintf(buf + len, "%s ", ad7152_conv_mode_table[i].name); | ||
| 155 | |||
| 156 | len += sprintf(buf + len, "\n"); | ||
| 157 | |||
| 158 | return len; | ||
| 159 | } | ||
| 160 | |||
| 161 | static IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(ad7152_show_conversion_modes); | ||
| 162 | |||
| 163 | static ssize_t ad7152_show_ch1_value(struct device *dev, | ||
| 164 | struct device_attribute *attr, | ||
| 165 | char *buf) | ||
| 166 | { | ||
| 167 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 168 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 169 | u8 data[2]; | ||
| 170 | |||
| 171 | ad7152_i2c_read(chip, AD7152_CH1_DATA_HIGH, data, 2); | ||
| 172 | return sprintf(buf, "%d\n", ((int)data[0] << 8) | data[1]); | ||
| 173 | } | ||
| 174 | |||
| 175 | static IIO_DEV_ATTR_CH1_VALUE(ad7152_show_ch1_value); | ||
| 176 | |||
| 177 | static ssize_t ad7152_show_ch2_value(struct device *dev, | ||
| 178 | struct device_attribute *attr, | ||
| 179 | char *buf) | ||
| 180 | { | ||
| 181 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 182 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 183 | u8 data[2]; | ||
| 184 | |||
| 185 | ad7152_i2c_read(chip, AD7152_CH2_DATA_HIGH, data, 2); | ||
| 186 | return sprintf(buf, "%d\n", ((int)data[0] << 8) | data[1]); | ||
| 187 | } | ||
| 188 | |||
| 189 | static IIO_DEV_ATTR_CH2_VALUE(ad7152_show_ch2_value); | ||
| 190 | |||
| 191 | static ssize_t ad7152_show_conversion_mode(struct device *dev, | ||
| 192 | struct device_attribute *attr, | ||
| 193 | char *buf) | ||
| 194 | { | ||
| 195 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 196 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 197 | |||
| 198 | return sprintf(buf, "%s\n", chip->conversion_mode); | ||
| 199 | } | ||
| 200 | |||
| 201 | static ssize_t ad7152_store_conversion_mode(struct device *dev, | ||
| 202 | struct device_attribute *attr, | ||
| 203 | const char *buf, | ||
| 204 | size_t len) | ||
| 205 | { | ||
| 206 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 207 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 208 | u8 cfg; | ||
| 209 | int i; | ||
| 210 | |||
| 211 | ad7152_i2c_read(chip, AD7152_CFG, &cfg, 1); | ||
| 212 | |||
| 213 | for (i = 0; i < AD7152_MAX_CONV_MODE; i++) | ||
| 214 | if (strncmp(buf, ad7152_conv_mode_table[i].name, | ||
| 215 | strlen(ad7152_conv_mode_table[i].name) - 1) == 0) { | ||
| 216 | chip->conversion_mode = ad7152_conv_mode_table[i].name; | ||
| 217 | cfg |= 0x18 | ad7152_conv_mode_table[i].reg_cfg; | ||
| 218 | ad7152_i2c_write(chip, AD7152_CFG, cfg); | ||
| 219 | return len; | ||
| 220 | } | ||
| 221 | |||
| 222 | dev_err(dev, "not supported conversion mode\n"); | ||
| 223 | |||
| 224 | return -EINVAL; | ||
| 225 | } | ||
| 226 | |||
| 227 | static IIO_DEV_ATTR_CONVERSION_MODE(S_IRUGO | S_IWUSR, | ||
| 228 | ad7152_show_conversion_mode, | ||
| 229 | ad7152_store_conversion_mode); | ||
| 230 | |||
| 231 | static ssize_t ad7152_show_ch1_offset(struct device *dev, | ||
| 232 | struct device_attribute *attr, | ||
| 233 | char *buf) | ||
| 234 | { | ||
| 235 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 236 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 237 | |||
| 238 | return sprintf(buf, "%d\n", chip->ch1_offset); | ||
| 239 | } | ||
| 240 | |||
| 241 | static ssize_t ad7152_store_ch1_offset(struct device *dev, | ||
| 242 | struct device_attribute *attr, | ||
| 243 | const char *buf, | ||
| 244 | size_t len) | ||
| 245 | { | ||
| 246 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 247 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 248 | unsigned long data; | ||
| 249 | int ret; | ||
| 250 | |||
| 251 | ret = strict_strtoul(buf, 10, &data); | ||
| 252 | |||
| 253 | if ((!ret) && (data < 0x10000)) { | ||
| 254 | ad7152_i2c_write(chip, AD7152_CH1_OFFS_HIGH, data >> 8); | ||
| 255 | ad7152_i2c_write(chip, AD7152_CH1_OFFS_LOW, data); | ||
| 256 | chip->ch1_offset = data; | ||
| 257 | return len; | ||
| 258 | } | ||
| 259 | |||
| 260 | return -EINVAL; | ||
| 261 | } | ||
| 262 | |||
| 263 | static IIO_DEV_ATTR_CH1_OFFSET(S_IRUGO | S_IWUSR, | ||
| 264 | ad7152_show_ch1_offset, | ||
| 265 | ad7152_store_ch1_offset); | ||
| 266 | |||
| 267 | static ssize_t ad7152_show_ch2_offset(struct device *dev, | ||
| 268 | struct device_attribute *attr, | ||
| 269 | char *buf) | ||
| 270 | { | ||
| 271 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 272 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 273 | |||
| 274 | return sprintf(buf, "%d\n", chip->ch2_offset); | ||
| 275 | } | ||
| 276 | |||
| 277 | static ssize_t ad7152_store_ch2_offset(struct device *dev, | ||
| 278 | struct device_attribute *attr, | ||
| 279 | const char *buf, | ||
| 280 | size_t len) | ||
| 281 | { | ||
| 282 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 283 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 284 | unsigned long data; | ||
| 285 | int ret; | ||
| 286 | |||
| 287 | ret = strict_strtoul(buf, 10, &data); | ||
| 288 | |||
| 289 | if ((!ret) && (data < 0x10000)) { | ||
| 290 | ad7152_i2c_write(chip, AD7152_CH2_OFFS_HIGH, data >> 8); | ||
| 291 | ad7152_i2c_write(chip, AD7152_CH2_OFFS_LOW, data); | ||
| 292 | chip->ch2_offset = data; | ||
| 293 | return len; | ||
| 294 | } | ||
| 295 | |||
| 296 | return -EINVAL; | ||
| 297 | } | ||
| 298 | |||
| 299 | static IIO_DEV_ATTR_CH2_OFFSET(S_IRUGO | S_IWUSR, | ||
| 300 | ad7152_show_ch2_offset, | ||
| 301 | ad7152_store_ch2_offset); | ||
| 302 | |||
| 303 | static ssize_t ad7152_show_ch1_gain(struct device *dev, | ||
| 304 | struct device_attribute *attr, | ||
| 305 | char *buf) | ||
| 306 | { | ||
| 307 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 308 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 309 | |||
| 310 | return sprintf(buf, "%d\n", chip->ch1_gain); | ||
| 311 | } | ||
| 312 | |||
| 313 | static ssize_t ad7152_store_ch1_gain(struct device *dev, | ||
| 314 | struct device_attribute *attr, | ||
| 315 | const char *buf, | ||
| 316 | size_t len) | ||
| 317 | { | ||
| 318 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 319 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 320 | unsigned long data; | ||
| 321 | int ret; | ||
| 322 | |||
| 323 | ret = strict_strtoul(buf, 10, &data); | ||
| 324 | |||
| 325 | if ((!ret) && (data < 0x10000)) { | ||
| 326 | ad7152_i2c_write(chip, AD7152_CH1_GAIN_HIGH, data >> 8); | ||
| 327 | ad7152_i2c_write(chip, AD7152_CH1_GAIN_LOW, data); | ||
| 328 | chip->ch1_gain = data; | ||
| 329 | return len; | ||
| 330 | } | ||
| 331 | |||
| 332 | return -EINVAL; | ||
| 333 | } | ||
| 334 | |||
| 335 | static IIO_DEV_ATTR_CH1_GAIN(S_IRUGO | S_IWUSR, | ||
| 336 | ad7152_show_ch1_gain, | ||
| 337 | ad7152_store_ch1_gain); | ||
| 338 | |||
| 339 | static ssize_t ad7152_show_ch2_gain(struct device *dev, | ||
| 340 | struct device_attribute *attr, | ||
| 341 | char *buf) | ||
| 342 | { | ||
| 343 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 344 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 345 | |||
| 346 | return sprintf(buf, "%d\n", chip->ch2_gain); | ||
| 347 | } | ||
| 348 | |||
| 349 | static ssize_t ad7152_store_ch2_gain(struct device *dev, | ||
| 350 | struct device_attribute *attr, | ||
| 351 | const char *buf, | ||
| 352 | size_t len) | ||
| 353 | { | ||
| 354 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 355 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 356 | unsigned long data; | ||
| 357 | int ret; | ||
| 358 | |||
| 359 | ret = strict_strtoul(buf, 10, &data); | ||
| 360 | |||
| 361 | if ((!ret) && (data < 0x10000)) { | ||
| 362 | ad7152_i2c_write(chip, AD7152_CH2_GAIN_HIGH, data >> 8); | ||
| 363 | ad7152_i2c_write(chip, AD7152_CH2_GAIN_LOW, data); | ||
| 364 | chip->ch2_gain = data; | ||
| 365 | return len; | ||
| 366 | } | ||
| 367 | |||
| 368 | return -EINVAL; | ||
| 369 | } | ||
| 370 | |||
| 371 | static IIO_DEV_ATTR_CH2_GAIN(S_IRUGO | S_IWUSR, | ||
| 372 | ad7152_show_ch2_gain, | ||
| 373 | ad7152_store_ch2_gain); | ||
| 374 | |||
| 375 | static ssize_t ad7152_show_ch1_setup(struct device *dev, | ||
| 376 | struct device_attribute *attr, | ||
| 377 | char *buf) | ||
| 378 | { | ||
| 379 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 380 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 381 | |||
| 382 | return sprintf(buf, "0x%02x\n", chip->ch1_setup); | ||
| 383 | } | ||
| 384 | |||
| 385 | static ssize_t ad7152_store_ch1_setup(struct device *dev, | ||
| 386 | struct device_attribute *attr, | ||
| 387 | const char *buf, | ||
| 388 | size_t len) | ||
| 389 | { | ||
| 390 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 391 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 392 | unsigned long data; | ||
| 393 | int ret; | ||
| 394 | |||
| 395 | ret = strict_strtoul(buf, 10, &data); | ||
| 396 | |||
| 397 | if ((!ret) && (data < 0x100)) { | ||
| 398 | ad7152_i2c_write(chip, AD7152_CH1_SETUP, data); | ||
| 399 | chip->ch1_setup = data; | ||
| 400 | return len; | ||
| 401 | } | ||
| 402 | |||
| 403 | return -EINVAL; | ||
| 404 | } | ||
| 405 | |||
| 406 | static IIO_DEV_ATTR_CH1_SETUP(S_IRUGO | S_IWUSR, | ||
| 407 | ad7152_show_ch1_setup, | ||
| 408 | ad7152_store_ch1_setup); | ||
| 409 | |||
| 410 | static ssize_t ad7152_show_ch2_setup(struct device *dev, | ||
| 411 | struct device_attribute *attr, | ||
| 412 | char *buf) | ||
| 413 | { | ||
| 414 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 415 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 416 | |||
| 417 | return sprintf(buf, "0x%02x\n", chip->ch2_setup); | ||
| 418 | } | ||
| 419 | |||
| 420 | static ssize_t ad7152_store_ch2_setup(struct device *dev, | ||
| 421 | struct device_attribute *attr, | ||
| 422 | const char *buf, | ||
| 423 | size_t len) | ||
| 424 | { | ||
| 425 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 426 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 427 | unsigned long data; | ||
| 428 | int ret; | ||
| 429 | |||
| 430 | ret = strict_strtoul(buf, 10, &data); | ||
| 431 | |||
| 432 | if ((!ret) && (data < 0x100)) { | ||
| 433 | ad7152_i2c_write(chip, AD7152_CH2_SETUP, data); | ||
| 434 | chip->ch2_setup = data; | ||
| 435 | return len; | ||
| 436 | } | ||
| 437 | |||
| 438 | return -EINVAL; | ||
| 439 | } | ||
| 440 | |||
| 441 | static IIO_DEV_ATTR_CH2_SETUP(S_IRUGO | S_IWUSR, | ||
| 442 | ad7152_show_ch2_setup, | ||
| 443 | ad7152_store_ch2_setup); | ||
| 444 | |||
| 445 | static ssize_t ad7152_show_filter_rate_setup(struct device *dev, | ||
| 446 | struct device_attribute *attr, | ||
| 447 | char *buf) | ||
| 448 | { | ||
| 449 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 450 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 451 | |||
| 452 | return sprintf(buf, "0x%02x\n", chip->filter_rate_setup); | ||
| 453 | } | ||
| 454 | |||
| 455 | static ssize_t ad7152_store_filter_rate_setup(struct device *dev, | ||
| 456 | struct device_attribute *attr, | ||
| 457 | const char *buf, | ||
| 458 | size_t len) | ||
| 459 | { | ||
| 460 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 461 | struct ad7152_chip_info *chip = iio_priv(dev_info); | ||
| 462 | unsigned long data; | ||
| 463 | int ret; | ||
| 464 | |||
| 465 | ret = strict_strtoul(buf, 10, &data); | ||
| 466 | |||
| 467 | if ((!ret) && (data < 0x100)) { | ||
| 468 | ad7152_i2c_write(chip, AD7152_CFG2, data); | ||
| 469 | chip->filter_rate_setup = data; | ||
| 470 | return len; | ||
| 471 | } | ||
| 472 | |||
| 473 | return -EINVAL; | ||
| 474 | } | ||
| 475 | |||
| 476 | static IIO_DEV_ATTR_FILTER_RATE_SETUP(S_IRUGO | S_IWUSR, | ||
| 477 | ad7152_show_filter_rate_setup, | ||
| 478 | ad7152_store_filter_rate_setup); | ||
| 479 | |||
| 480 | static struct attribute *ad7152_attributes[] = { | ||
| 481 | &iio_dev_attr_available_conversion_modes.dev_attr.attr, | ||
| 482 | &iio_dev_attr_conversion_mode.dev_attr.attr, | ||
| 483 | &iio_dev_attr_ch1_gain.dev_attr.attr, | ||
| 484 | &iio_dev_attr_ch2_gain.dev_attr.attr, | ||
| 485 | &iio_dev_attr_ch1_offset.dev_attr.attr, | ||
| 486 | &iio_dev_attr_ch2_offset.dev_attr.attr, | ||
| 487 | &iio_dev_attr_ch1_value.dev_attr.attr, | ||
| 488 | &iio_dev_attr_ch2_value.dev_attr.attr, | ||
| 489 | &iio_dev_attr_ch1_setup.dev_attr.attr, | ||
| 490 | &iio_dev_attr_ch2_setup.dev_attr.attr, | ||
| 491 | &iio_dev_attr_filter_rate_setup.dev_attr.attr, | ||
| 492 | NULL, | ||
| 493 | }; | ||
| 494 | |||
| 495 | static const struct attribute_group ad7152_attribute_group = { | ||
| 496 | .attrs = ad7152_attributes, | ||
| 497 | }; | ||
| 498 | |||
| 499 | static const struct iio_info ad7152_info = { | ||
| 500 | .attrs = &ad7152_attribute_group, | ||
| 501 | .driver_module = THIS_MODULE, | ||
| 502 | }; | ||
| 503 | /* | ||
| 504 | * device probe and remove | ||
| 505 | */ | ||
| 506 | |||
| 507 | static int __devinit ad7152_probe(struct i2c_client *client, | ||
| 508 | const struct i2c_device_id *id) | ||
| 509 | { | ||
| 510 | int ret = 0; | ||
| 511 | struct ad7152_chip_info *chip; | ||
| 512 | struct iio_dev *indio_dev; | ||
| 513 | |||
| 514 | indio_dev = iio_allocate_device(sizeof(*chip)); | ||
| 515 | if (indio_dev == NULL) { | ||
| 516 | ret = -ENOMEM; | ||
| 517 | goto error_ret; | ||
| 518 | } | ||
| 519 | chip = iio_priv(indio_dev); | ||
| 520 | /* this is only used for device removal purposes */ | ||
| 521 | i2c_set_clientdata(client, indio_dev); | ||
| 522 | |||
| 523 | chip->client = client; | ||
| 524 | |||
| 525 | /* Echipabilish that the iio_dev is a child of the i2c device */ | ||
| 526 | indio_dev->name = id->name; | ||
| 527 | indio_dev->dev.parent = &client->dev; | ||
| 528 | indio_dev->info = &ad7152_info; | ||
| 529 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 530 | |||
| 531 | ret = iio_device_register(indio_dev); | ||
| 532 | if (ret) | ||
| 533 | goto error_free_dev; | ||
| 534 | |||
| 535 | dev_err(&client->dev, "%s capacitive sensor registered\n", id->name); | ||
| 536 | |||
| 537 | return 0; | ||
| 538 | |||
| 539 | error_free_dev: | ||
| 540 | iio_free_device(indio_dev); | ||
| 541 | error_ret: | ||
| 542 | return ret; | ||
| 543 | } | ||
| 544 | |||
| 545 | static int __devexit ad7152_remove(struct i2c_client *client) | ||
| 546 | { | ||
| 547 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | ||
| 548 | |||
| 549 | iio_device_unregister(indio_dev); | ||
| 550 | |||
| 551 | return 0; | ||
| 552 | } | ||
| 553 | |||
| 554 | static const struct i2c_device_id ad7152_id[] = { | ||
| 555 | { "ad7152", 0 }, | ||
| 556 | { "ad7153", 0 }, | ||
| 557 | {} | ||
| 558 | }; | ||
| 559 | |||
| 560 | MODULE_DEVICE_TABLE(i2c, ad7152_id); | ||
| 561 | |||
| 562 | static struct i2c_driver ad7152_driver = { | ||
| 563 | .driver = { | ||
| 564 | .name = "ad7152", | ||
| 565 | }, | ||
| 566 | .probe = ad7152_probe, | ||
| 567 | .remove = __devexit_p(ad7152_remove), | ||
| 568 | .id_table = ad7152_id, | ||
| 569 | }; | ||
| 570 | |||
| 571 | static __init int ad7152_init(void) | ||
| 572 | { | ||
| 573 | return i2c_add_driver(&ad7152_driver); | ||
| 574 | } | ||
| 575 | |||
| 576 | static __exit void ad7152_exit(void) | ||
| 577 | { | ||
| 578 | i2c_del_driver(&ad7152_driver); | ||
| 579 | } | ||
| 580 | |||
| 581 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | ||
| 582 | MODULE_DESCRIPTION("Analog Devices ad7152/3 capacitive sensor driver"); | ||
| 583 | MODULE_LICENSE("GPL v2"); | ||
| 584 | |||
| 585 | module_init(ad7152_init); | ||
| 586 | module_exit(ad7152_exit); | ||
diff --git a/drivers/staging/iio/adc/ad7298.h b/drivers/staging/iio/adc/ad7298.h new file mode 100644 index 00000000000..628f5adcf0c --- /dev/null +++ b/drivers/staging/iio/adc/ad7298.h | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | /* | ||
| 2 | * AD7298 SPI ADC driver | ||
| 3 | * | ||
| 4 | * Copyright 2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef IIO_ADC_AD7298_H_ | ||
| 10 | #define IIO_ADC_AD7298_H_ | ||
| 11 | |||
| 12 | #define AD7298_WRITE (1 << 15) /* write to the control register */ | ||
| 13 | #define AD7298_REPEAT (1 << 14) /* repeated conversion enable */ | ||
| 14 | #define AD7298_CH(x) (1 << (13 - (x))) /* channel select */ | ||
| 15 | #define AD7298_TSENSE (1 << 5) /* temperature conversion enable */ | ||
| 16 | #define AD7298_EXTREF (1 << 2) /* external reference enable */ | ||
| 17 | #define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */ | ||
| 18 | #define AD7298_PDD (1 << 0) /* partial power down enable */ | ||
| 19 | |||
| 20 | #define AD7298_MAX_CHAN 8 | ||
| 21 | #define AD7298_BITS 12 | ||
| 22 | #define AD7298_STORAGE_BITS 16 | ||
| 23 | #define AD7298_INTREF_mV 2500 | ||
| 24 | |||
| 25 | #define AD7298_CH_TEMP 9 | ||
| 26 | |||
| 27 | #define RES_MASK(bits) ((1 << (bits)) - 1) | ||
| 28 | |||
| 29 | /* | ||
| 30 | * TODO: struct ad7298_platform_data needs to go into include/linux/iio | ||
| 31 | */ | ||
| 32 | |||
| 33 | struct ad7298_platform_data { | ||
| 34 | /* External Vref voltage applied */ | ||
| 35 | u16 vref_mv; | ||
| 36 | }; | ||
| 37 | |||
| 38 | struct ad7298_state { | ||
| 39 | struct spi_device *spi; | ||
| 40 | struct regulator *reg; | ||
| 41 | size_t d_size; | ||
| 42 | u16 int_vref_mv; | ||
| 43 | unsigned ext_ref; | ||
| 44 | struct spi_transfer ring_xfer[10]; | ||
| 45 | struct spi_transfer scan_single_xfer[3]; | ||
| 46 | struct spi_message ring_msg; | ||
| 47 | struct spi_message scan_single_msg; | ||
| 48 | /* | ||
| 49 | * DMA (thus cache coherency maintenance) requires the | ||
| 50 | * transfer buffers to live in their own cache lines. | ||
| 51 | */ | ||
| 52 | unsigned short rx_buf[8] ____cacheline_aligned; | ||
| 53 | unsigned short tx_buf[2]; | ||
| 54 | }; | ||
| 55 | |||
| 56 | #ifdef CONFIG_IIO_RING_BUFFER | ||
| 57 | int ad7298_scan_from_ring(struct iio_dev *indio_dev, long ch); | ||
| 58 | int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev); | ||
| 59 | void ad7298_ring_cleanup(struct iio_dev *indio_dev); | ||
| 60 | #else /* CONFIG_IIO_RING_BUFFER */ | ||
| 61 | static inline int ad7298_scan_from_ring(struct iio_dev *indio_dev, long ch) | ||
| 62 | { | ||
| 63 | return 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | static inline int | ||
| 67 | ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev) | ||
| 68 | { | ||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | |||
| 72 | static inline void ad7298_ring_cleanup(struct iio_dev *indio_dev) | ||
| 73 | { | ||
| 74 | } | ||
| 75 | #endif /* CONFIG_IIO_RING_BUFFER */ | ||
| 76 | #endif /* IIO_ADC_AD7298_H_ */ | ||
diff --git a/drivers/staging/iio/adc/ad7298_core.c b/drivers/staging/iio/adc/ad7298_core.c new file mode 100644 index 00000000000..b8e4ae29b0b --- /dev/null +++ b/drivers/staging/iio/adc/ad7298_core.c | |||
| @@ -0,0 +1,299 @@ | |||
| 1 | /* | ||
| 2 | * AD7298 SPI ADC driver | ||
| 3 | * | ||
| 4 | * Copyright 2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/device.h> | ||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/sysfs.h> | ||
| 13 | #include <linux/spi/spi.h> | ||
| 14 | #include <linux/regulator/consumer.h> | ||
| 15 | #include <linux/err.h> | ||
| 16 | #include <linux/delay.h> | ||
| 17 | |||
| 18 | #include "../iio.h" | ||
| 19 | #include "../sysfs.h" | ||
| 20 | #include "../ring_generic.h" | ||
| 21 | #include "adc.h" | ||
| 22 | |||
| 23 | #include "ad7298.h" | ||
| 24 | |||
| 25 | static struct iio_chan_spec ad7298_channels[] = { | ||
| 26 | IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, | ||
| 27 | (1 << IIO_CHAN_INFO_SCALE_SEPARATE), | ||
| 28 | 9, AD7298_CH_TEMP, IIO_ST('s', 32, 32, 0), 0), | ||
| 29 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, | ||
| 30 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 31 | 0, 0, IIO_ST('u', 12, 16, 0), 0), | ||
| 32 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 1, 0, | ||
| 33 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 34 | 1, 1, IIO_ST('u', 12, 16, 0), 0), | ||
| 35 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 2, 0, | ||
| 36 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 37 | 2, 2, IIO_ST('u', 12, 16, 0), 0), | ||
| 38 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 3, 0, | ||
| 39 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 40 | 3, 3, IIO_ST('u', 12, 16, 0), 0), | ||
| 41 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 4, 0, | ||
| 42 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 43 | 4, 4, IIO_ST('u', 12, 16, 0), 0), | ||
| 44 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 5, 0, | ||
| 45 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 46 | 5, 5, IIO_ST('u', 12, 16, 0), 0), | ||
| 47 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 6, 0, | ||
| 48 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 49 | 6, 6, IIO_ST('u', 12, 16, 0), 0), | ||
| 50 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 7, 0, | ||
| 51 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 52 | 7, 7, IIO_ST('u', 12, 16, 0), 0), | ||
| 53 | IIO_CHAN_SOFT_TIMESTAMP(8), | ||
| 54 | }; | ||
| 55 | |||
| 56 | static int ad7298_scan_direct(struct ad7298_state *st, unsigned ch) | ||
| 57 | { | ||
| 58 | int ret; | ||
| 59 | st->tx_buf[0] = cpu_to_be16(AD7298_WRITE | st->ext_ref | | ||
| 60 | (AD7298_CH(0) >> ch)); | ||
| 61 | |||
| 62 | ret = spi_sync(st->spi, &st->scan_single_msg); | ||
| 63 | if (ret) | ||
| 64 | return ret; | ||
| 65 | |||
| 66 | return be16_to_cpu(st->rx_buf[0]); | ||
| 67 | } | ||
| 68 | |||
| 69 | static int ad7298_scan_temp(struct ad7298_state *st, int *val) | ||
| 70 | { | ||
| 71 | int tmp, ret; | ||
| 72 | |||
| 73 | tmp = cpu_to_be16(AD7298_WRITE | AD7298_TSENSE | | ||
| 74 | AD7298_TAVG | st->ext_ref); | ||
| 75 | |||
| 76 | ret = spi_write(st->spi, (u8 *)&tmp, 2); | ||
| 77 | if (ret) | ||
| 78 | return ret; | ||
| 79 | |||
| 80 | tmp = 0; | ||
| 81 | |||
| 82 | ret = spi_write(st->spi, (u8 *)&tmp, 2); | ||
| 83 | if (ret) | ||
| 84 | return ret; | ||
| 85 | |||
| 86 | usleep_range(101, 1000); /* sleep > 100us */ | ||
| 87 | |||
| 88 | ret = spi_read(st->spi, (u8 *)&tmp, 2); | ||
| 89 | if (ret) | ||
| 90 | return ret; | ||
| 91 | |||
| 92 | tmp = be16_to_cpu(tmp) & RES_MASK(AD7298_BITS); | ||
| 93 | |||
| 94 | /* | ||
| 95 | * One LSB of the ADC corresponds to 0.25 deg C. | ||
| 96 | * The temperature reading is in 12-bit twos complement format | ||
| 97 | */ | ||
| 98 | |||
| 99 | if (tmp & (1 << (AD7298_BITS - 1))) { | ||
| 100 | tmp = (4096 - tmp) * 250; | ||
| 101 | tmp -= (2 * tmp); | ||
| 102 | |||
| 103 | } else { | ||
| 104 | tmp *= 250; /* temperature in milli degrees Celsius */ | ||
| 105 | } | ||
| 106 | |||
| 107 | *val = tmp; | ||
| 108 | |||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | static int ad7298_read_raw(struct iio_dev *dev_info, | ||
| 113 | struct iio_chan_spec const *chan, | ||
| 114 | int *val, | ||
| 115 | int *val2, | ||
| 116 | long m) | ||
| 117 | { | ||
| 118 | int ret; | ||
| 119 | struct ad7298_state *st = iio_priv(dev_info); | ||
| 120 | unsigned int scale_uv; | ||
| 121 | |||
| 122 | switch (m) { | ||
| 123 | case 0: | ||
| 124 | mutex_lock(&dev_info->mlock); | ||
| 125 | if (iio_ring_enabled(dev_info)) { | ||
| 126 | if (chan->address == AD7298_CH_TEMP) | ||
| 127 | ret = -ENODEV; | ||
| 128 | else | ||
| 129 | ret = ad7298_scan_from_ring(dev_info, | ||
| 130 | chan->address); | ||
| 131 | } else { | ||
| 132 | if (chan->address == AD7298_CH_TEMP) | ||
| 133 | ret = ad7298_scan_temp(st, val); | ||
| 134 | else | ||
| 135 | ret = ad7298_scan_direct(st, chan->address); | ||
| 136 | } | ||
| 137 | mutex_unlock(&dev_info->mlock); | ||
| 138 | |||
| 139 | if (ret < 0) | ||
| 140 | return ret; | ||
| 141 | |||
| 142 | if (chan->address != AD7298_CH_TEMP) | ||
| 143 | *val = ret & RES_MASK(AD7298_BITS); | ||
| 144 | |||
| 145 | return IIO_VAL_INT; | ||
| 146 | case (1 << IIO_CHAN_INFO_SCALE_SHARED): | ||
| 147 | scale_uv = (st->int_vref_mv * 1000) >> AD7298_BITS; | ||
| 148 | *val = scale_uv / 1000; | ||
| 149 | *val2 = (scale_uv % 1000) * 1000; | ||
| 150 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 151 | case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): | ||
| 152 | *val = 1; | ||
| 153 | *val2 = 0; | ||
| 154 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 155 | } | ||
| 156 | return -EINVAL; | ||
| 157 | } | ||
| 158 | |||
| 159 | static const struct iio_info ad7298_info = { | ||
| 160 | .read_raw = &ad7298_read_raw, | ||
| 161 | .driver_module = THIS_MODULE, | ||
| 162 | }; | ||
| 163 | |||
| 164 | static int __devinit ad7298_probe(struct spi_device *spi) | ||
| 165 | { | ||
| 166 | struct ad7298_platform_data *pdata = spi->dev.platform_data; | ||
| 167 | struct ad7298_state *st; | ||
| 168 | int ret, regdone = 0; | ||
| 169 | struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st)); | ||
| 170 | |||
| 171 | if (indio_dev == NULL) | ||
| 172 | return -ENOMEM; | ||
| 173 | |||
| 174 | st = iio_priv(indio_dev); | ||
| 175 | |||
| 176 | st->reg = regulator_get(&spi->dev, "vcc"); | ||
| 177 | if (!IS_ERR(st->reg)) { | ||
| 178 | ret = regulator_enable(st->reg); | ||
| 179 | if (ret) | ||
| 180 | goto error_put_reg; | ||
| 181 | } | ||
| 182 | |||
| 183 | spi_set_drvdata(spi, indio_dev); | ||
| 184 | |||
| 185 | st->spi = spi; | ||
| 186 | |||
| 187 | indio_dev->name = spi_get_device_id(spi)->name; | ||
| 188 | indio_dev->dev.parent = &spi->dev; | ||
| 189 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 190 | indio_dev->channels = ad7298_channels; | ||
| 191 | indio_dev->num_channels = ARRAY_SIZE(ad7298_channels); | ||
| 192 | indio_dev->info = &ad7298_info; | ||
| 193 | |||
| 194 | /* Setup default message */ | ||
| 195 | |||
| 196 | st->scan_single_xfer[0].tx_buf = &st->tx_buf[0]; | ||
| 197 | st->scan_single_xfer[0].len = 2; | ||
| 198 | st->scan_single_xfer[0].cs_change = 1; | ||
| 199 | st->scan_single_xfer[1].tx_buf = &st->tx_buf[1]; | ||
| 200 | st->scan_single_xfer[1].len = 2; | ||
| 201 | st->scan_single_xfer[1].cs_change = 1; | ||
| 202 | st->scan_single_xfer[2].rx_buf = &st->rx_buf[0]; | ||
| 203 | st->scan_single_xfer[2].len = 2; | ||
| 204 | |||
| 205 | spi_message_init(&st->scan_single_msg); | ||
| 206 | spi_message_add_tail(&st->scan_single_xfer[0], &st->scan_single_msg); | ||
| 207 | spi_message_add_tail(&st->scan_single_xfer[1], &st->scan_single_msg); | ||
| 208 | spi_message_add_tail(&st->scan_single_xfer[2], &st->scan_single_msg); | ||
| 209 | |||
| 210 | if (pdata && pdata->vref_mv) { | ||
| 211 | st->int_vref_mv = pdata->vref_mv; | ||
| 212 | st->ext_ref = AD7298_EXTREF; | ||
| 213 | } else { | ||
| 214 | st->int_vref_mv = AD7298_INTREF_mV; | ||
| 215 | } | ||
| 216 | |||
| 217 | ret = ad7298_register_ring_funcs_and_init(indio_dev); | ||
| 218 | if (ret) | ||
| 219 | goto error_disable_reg; | ||
| 220 | |||
| 221 | ret = iio_device_register(indio_dev); | ||
| 222 | if (ret) | ||
| 223 | goto error_disable_reg; | ||
| 224 | regdone = 1; | ||
| 225 | |||
| 226 | ret = iio_ring_buffer_register_ex(indio_dev->ring, 0, | ||
| 227 | &ad7298_channels[1], /* skip temp0 */ | ||
| 228 | ARRAY_SIZE(ad7298_channels) - 1); | ||
| 229 | if (ret) | ||
| 230 | goto error_cleanup_ring; | ||
| 231 | |||
| 232 | return 0; | ||
| 233 | |||
| 234 | error_cleanup_ring: | ||
| 235 | ad7298_ring_cleanup(indio_dev); | ||
| 236 | error_disable_reg: | ||
| 237 | if (!IS_ERR(st->reg)) | ||
| 238 | regulator_disable(st->reg); | ||
| 239 | error_put_reg: | ||
| 240 | if (!IS_ERR(st->reg)) | ||
| 241 | regulator_put(st->reg); | ||
| 242 | |||
| 243 | if (regdone) | ||
| 244 | iio_device_unregister(indio_dev); | ||
| 245 | else | ||
| 246 | iio_free_device(indio_dev); | ||
| 247 | |||
| 248 | return ret; | ||
| 249 | } | ||
| 250 | |||
| 251 | static int __devexit ad7298_remove(struct spi_device *spi) | ||
| 252 | { | ||
| 253 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 254 | struct ad7298_state *st = iio_priv(indio_dev); | ||
| 255 | |||
| 256 | iio_ring_buffer_unregister(indio_dev->ring); | ||
| 257 | ad7298_ring_cleanup(indio_dev); | ||
| 258 | iio_device_unregister(indio_dev); | ||
| 259 | if (!IS_ERR(st->reg)) { | ||
| 260 | regulator_disable(st->reg); | ||
| 261 | regulator_put(st->reg); | ||
| 262 | } | ||
| 263 | iio_device_unregister(indio_dev); | ||
| 264 | |||
| 265 | return 0; | ||
| 266 | } | ||
| 267 | |||
| 268 | static const struct spi_device_id ad7298_id[] = { | ||
| 269 | {"ad7298", 0}, | ||
| 270 | {} | ||
| 271 | }; | ||
| 272 | |||
| 273 | static struct spi_driver ad7298_driver = { | ||
| 274 | .driver = { | ||
| 275 | .name = "ad7298", | ||
| 276 | .bus = &spi_bus_type, | ||
| 277 | .owner = THIS_MODULE, | ||
| 278 | }, | ||
| 279 | .probe = ad7298_probe, | ||
| 280 | .remove = __devexit_p(ad7298_remove), | ||
| 281 | .id_table = ad7298_id, | ||
| 282 | }; | ||
| 283 | |||
| 284 | static int __init ad7298_init(void) | ||
| 285 | { | ||
| 286 | return spi_register_driver(&ad7298_driver); | ||
| 287 | } | ||
| 288 | module_init(ad7298_init); | ||
| 289 | |||
| 290 | static void __exit ad7298_exit(void) | ||
| 291 | { | ||
| 292 | spi_unregister_driver(&ad7298_driver); | ||
| 293 | } | ||
| 294 | module_exit(ad7298_exit); | ||
| 295 | |||
| 296 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
| 297 | MODULE_DESCRIPTION("Analog Devices AD7298 ADC"); | ||
| 298 | MODULE_LICENSE("GPL v2"); | ||
| 299 | MODULE_ALIAS("spi:ad7298"); | ||
diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c new file mode 100644 index 00000000000..a04c0335262 --- /dev/null +++ b/drivers/staging/iio/adc/ad7298_ring.c | |||
| @@ -0,0 +1,202 @@ | |||
| 1 | /* | ||
| 2 | * AD7298 SPI ADC driver | ||
| 3 | * | ||
| 4 | * Copyright 2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/device.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/sysfs.h> | ||
| 14 | #include <linux/spi/spi.h> | ||
| 15 | |||
| 16 | #include "../iio.h" | ||
| 17 | #include "../ring_generic.h" | ||
| 18 | #include "../ring_sw.h" | ||
| 19 | #include "../trigger.h" | ||
| 20 | #include "../sysfs.h" | ||
| 21 | |||
| 22 | #include "ad7298.h" | ||
| 23 | |||
| 24 | int ad7298_scan_from_ring(struct iio_dev *dev_info, long ch) | ||
| 25 | { | ||
| 26 | struct iio_ring_buffer *ring = dev_info->ring; | ||
| 27 | int ret; | ||
| 28 | u16 *ring_data; | ||
| 29 | |||
| 30 | if (!(ring->scan_mask & (1 << ch))) { | ||
| 31 | ret = -EBUSY; | ||
| 32 | goto error_ret; | ||
| 33 | } | ||
| 34 | |||
| 35 | ring_data = kmalloc(ring->access->get_bytes_per_datum(ring), | ||
| 36 | GFP_KERNEL); | ||
| 37 | if (ring_data == NULL) { | ||
| 38 | ret = -ENOMEM; | ||
| 39 | goto error_ret; | ||
| 40 | } | ||
| 41 | ret = ring->access->read_last(ring, (u8 *) ring_data); | ||
| 42 | if (ret) | ||
| 43 | goto error_free_ring_data; | ||
| 44 | |||
| 45 | ret = be16_to_cpu(ring_data[ch]); | ||
| 46 | |||
| 47 | error_free_ring_data: | ||
| 48 | kfree(ring_data); | ||
| 49 | error_ret: | ||
| 50 | return ret; | ||
| 51 | } | ||
| 52 | |||
| 53 | /** | ||
| 54 | * ad7298_ring_preenable() setup the parameters of the ring before enabling | ||
| 55 | * | ||
| 56 | * The complex nature of the setting of the number of bytes per datum is due | ||
| 57 | * to this driver currently ensuring that the timestamp is stored at an 8 | ||
| 58 | * byte boundary. | ||
| 59 | **/ | ||
| 60 | static int ad7298_ring_preenable(struct iio_dev *indio_dev) | ||
| 61 | { | ||
| 62 | struct ad7298_state *st = iio_priv(indio_dev); | ||
| 63 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 64 | size_t d_size; | ||
| 65 | int i, m; | ||
| 66 | unsigned short command; | ||
| 67 | |||
| 68 | d_size = ring->scan_count * (AD7298_STORAGE_BITS / 8); | ||
| 69 | |||
| 70 | if (ring->scan_timestamp) { | ||
| 71 | d_size += sizeof(s64); | ||
| 72 | |||
| 73 | if (d_size % sizeof(s64)) | ||
| 74 | d_size += sizeof(s64) - (d_size % sizeof(s64)); | ||
| 75 | } | ||
| 76 | |||
| 77 | if (ring->access->set_bytes_per_datum) | ||
| 78 | ring->access->set_bytes_per_datum(ring, d_size); | ||
| 79 | |||
| 80 | st->d_size = d_size; | ||
| 81 | |||
| 82 | command = AD7298_WRITE | st->ext_ref; | ||
| 83 | |||
| 84 | for (i = 0, m = AD7298_CH(0); i < AD7298_MAX_CHAN; i++, m >>= 1) | ||
| 85 | if (ring->scan_mask & (1 << i)) | ||
| 86 | command |= m; | ||
| 87 | |||
| 88 | st->tx_buf[0] = cpu_to_be16(command); | ||
| 89 | |||
| 90 | /* build spi ring message */ | ||
| 91 | st->ring_xfer[0].tx_buf = &st->tx_buf[0]; | ||
| 92 | st->ring_xfer[0].len = 2; | ||
| 93 | st->ring_xfer[0].cs_change = 1; | ||
| 94 | st->ring_xfer[1].tx_buf = &st->tx_buf[1]; | ||
| 95 | st->ring_xfer[1].len = 2; | ||
| 96 | st->ring_xfer[1].cs_change = 1; | ||
| 97 | |||
| 98 | spi_message_init(&st->ring_msg); | ||
| 99 | spi_message_add_tail(&st->ring_xfer[0], &st->ring_msg); | ||
| 100 | spi_message_add_tail(&st->ring_xfer[1], &st->ring_msg); | ||
| 101 | |||
| 102 | for (i = 0; i < ring->scan_count; i++) { | ||
| 103 | st->ring_xfer[i + 2].rx_buf = &st->rx_buf[i]; | ||
| 104 | st->ring_xfer[i + 2].len = 2; | ||
| 105 | st->ring_xfer[i + 2].cs_change = 1; | ||
| 106 | spi_message_add_tail(&st->ring_xfer[i + 2], &st->ring_msg); | ||
| 107 | } | ||
| 108 | /* make sure last transfer cs_change is not set */ | ||
| 109 | st->ring_xfer[i + 1].cs_change = 0; | ||
| 110 | |||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | /** | ||
| 115 | * ad7298_trigger_handler() bh of trigger launched polling to ring buffer | ||
| 116 | * | ||
| 117 | * Currently there is no option in this driver to disable the saving of | ||
| 118 | * timestamps within the ring. | ||
| 119 | **/ | ||
| 120 | static irqreturn_t ad7298_trigger_handler(int irq, void *p) | ||
| 121 | { | ||
| 122 | struct iio_poll_func *pf = p; | ||
| 123 | struct iio_dev *indio_dev = pf->private_data; | ||
| 124 | struct ad7298_state *st = iio_priv(indio_dev); | ||
| 125 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 126 | s64 time_ns; | ||
| 127 | __u16 buf[16]; | ||
| 128 | int b_sent, i; | ||
| 129 | |||
| 130 | b_sent = spi_sync(st->spi, &st->ring_msg); | ||
| 131 | if (b_sent) | ||
| 132 | return b_sent; | ||
| 133 | |||
| 134 | if (ring->scan_timestamp) { | ||
| 135 | time_ns = iio_get_time_ns(); | ||
| 136 | memcpy((u8 *)buf + st->d_size - sizeof(s64), | ||
| 137 | &time_ns, sizeof(time_ns)); | ||
| 138 | } | ||
| 139 | |||
| 140 | for (i = 0; i < ring->scan_count; i++) | ||
| 141 | buf[i] = be16_to_cpu(st->rx_buf[i]); | ||
| 142 | |||
| 143 | indio_dev->ring->access->store_to(ring, (u8 *)buf, time_ns); | ||
| 144 | iio_trigger_notify_done(indio_dev->trig); | ||
| 145 | |||
| 146 | return IRQ_HANDLED; | ||
| 147 | } | ||
| 148 | |||
| 149 | static const struct iio_ring_setup_ops ad7298_ring_setup_ops = { | ||
| 150 | .preenable = &ad7298_ring_preenable, | ||
| 151 | .postenable = &iio_triggered_ring_postenable, | ||
| 152 | .predisable = &iio_triggered_ring_predisable, | ||
| 153 | }; | ||
| 154 | |||
| 155 | int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev) | ||
| 156 | { | ||
| 157 | int ret; | ||
| 158 | |||
| 159 | indio_dev->ring = iio_sw_rb_allocate(indio_dev); | ||
| 160 | if (!indio_dev->ring) { | ||
| 161 | ret = -ENOMEM; | ||
| 162 | goto error_ret; | ||
| 163 | } | ||
| 164 | /* Effectively select the ring buffer implementation */ | ||
| 165 | indio_dev->ring->access = &ring_sw_access_funcs; | ||
| 166 | |||
| 167 | indio_dev->pollfunc = iio_alloc_pollfunc(NULL, | ||
| 168 | &ad7298_trigger_handler, | ||
| 169 | IRQF_ONESHOT, | ||
| 170 | indio_dev, | ||
| 171 | "ad7298_consumer%d", | ||
| 172 | indio_dev->id); | ||
| 173 | |||
| 174 | if (indio_dev->pollfunc == NULL) { | ||
| 175 | ret = -ENOMEM; | ||
| 176 | goto error_deallocate_sw_rb; | ||
| 177 | } | ||
| 178 | |||
| 179 | /* Ring buffer functions - here trigger setup related */ | ||
| 180 | indio_dev->ring->setup_ops = &ad7298_ring_setup_ops; | ||
| 181 | indio_dev->ring->scan_timestamp = true; | ||
| 182 | |||
| 183 | /* Flag that polled ring buffering is possible */ | ||
| 184 | indio_dev->modes |= INDIO_RING_TRIGGERED; | ||
| 185 | return 0; | ||
| 186 | |||
| 187 | error_deallocate_sw_rb: | ||
| 188 | iio_sw_rb_free(indio_dev->ring); | ||
| 189 | error_ret: | ||
| 190 | return ret; | ||
| 191 | } | ||
| 192 | |||
| 193 | void ad7298_ring_cleanup(struct iio_dev *indio_dev) | ||
| 194 | { | ||
| 195 | if (indio_dev->trig) { | ||
| 196 | iio_put_trigger(indio_dev->trig); | ||
| 197 | iio_trigger_dettach_poll_func(indio_dev->trig, | ||
| 198 | indio_dev->pollfunc); | ||
| 199 | } | ||
| 200 | iio_dealloc_pollfunc(indio_dev->pollfunc); | ||
| 201 | iio_sw_rb_free(indio_dev->ring); | ||
| 202 | } | ||
diff --git a/drivers/staging/iio/adc/ad7314.c b/drivers/staging/iio/adc/ad7314.c new file mode 100644 index 00000000000..9070d9cac72 --- /dev/null +++ b/drivers/staging/iio/adc/ad7314.c | |||
| @@ -0,0 +1,281 @@ | |||
| 1 | /* | ||
| 2 | * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302 | ||
| 3 | * | ||
| 4 | * Copyright 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/device.h> | ||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/sysfs.h> | ||
| 13 | #include <linux/spi/spi.h> | ||
| 14 | |||
| 15 | #include "../iio.h" | ||
| 16 | #include "../sysfs.h" | ||
| 17 | |||
| 18 | /* | ||
| 19 | * AD7314 power mode | ||
| 20 | */ | ||
| 21 | #define AD7314_PD 0x2000 | ||
| 22 | |||
| 23 | /* | ||
| 24 | * AD7314 temperature masks | ||
| 25 | */ | ||
| 26 | #define AD7314_TEMP_SIGN 0x200 | ||
| 27 | #define AD7314_TEMP_MASK 0x7FE0 | ||
| 28 | #define AD7314_TEMP_OFFSET 5 | ||
| 29 | #define AD7314_TEMP_FLOAT_OFFSET 2 | ||
| 30 | #define AD7314_TEMP_FLOAT_MASK 0x3 | ||
| 31 | |||
| 32 | /* | ||
| 33 | * ADT7301 and ADT7302 temperature masks | ||
| 34 | */ | ||
| 35 | #define ADT7301_TEMP_SIGN 0x2000 | ||
| 36 | #define ADT7301_TEMP_MASK 0x2FFF | ||
| 37 | #define ADT7301_TEMP_FLOAT_OFFSET 5 | ||
| 38 | #define ADT7301_TEMP_FLOAT_MASK 0x1F | ||
| 39 | |||
| 40 | /* | ||
| 41 | * struct ad7314_chip_info - chip specifc information | ||
| 42 | */ | ||
| 43 | |||
| 44 | struct ad7314_chip_info { | ||
| 45 | struct spi_device *spi_dev; | ||
| 46 | s64 last_timestamp; | ||
| 47 | u8 mode; | ||
| 48 | }; | ||
| 49 | |||
| 50 | /* | ||
| 51 | * ad7314 register access by SPI | ||
| 52 | */ | ||
| 53 | |||
| 54 | static int ad7314_spi_read(struct ad7314_chip_info *chip, u16 *data) | ||
| 55 | { | ||
| 56 | struct spi_device *spi_dev = chip->spi_dev; | ||
| 57 | int ret = 0; | ||
| 58 | u16 value; | ||
| 59 | |||
| 60 | ret = spi_read(spi_dev, (u8 *)&value, sizeof(value)); | ||
| 61 | if (ret < 0) { | ||
| 62 | dev_err(&spi_dev->dev, "SPI read error\n"); | ||
| 63 | return ret; | ||
| 64 | } | ||
| 65 | |||
| 66 | *data = be16_to_cpu((u16)value); | ||
| 67 | |||
| 68 | return ret; | ||
| 69 | } | ||
| 70 | |||
| 71 | static int ad7314_spi_write(struct ad7314_chip_info *chip, u16 data) | ||
| 72 | { | ||
| 73 | struct spi_device *spi_dev = chip->spi_dev; | ||
| 74 | int ret = 0; | ||
| 75 | u16 value = cpu_to_be16(data); | ||
| 76 | |||
| 77 | ret = spi_write(spi_dev, (u8 *)&value, sizeof(value)); | ||
| 78 | if (ret < 0) | ||
| 79 | dev_err(&spi_dev->dev, "SPI write error\n"); | ||
| 80 | |||
| 81 | return ret; | ||
| 82 | } | ||
| 83 | |||
| 84 | static ssize_t ad7314_show_mode(struct device *dev, | ||
| 85 | struct device_attribute *attr, | ||
| 86 | char *buf) | ||
| 87 | { | ||
| 88 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 89 | struct ad7314_chip_info *chip = iio_priv(dev_info); | ||
| 90 | |||
| 91 | if (chip->mode) | ||
| 92 | return sprintf(buf, "power-save\n"); | ||
| 93 | else | ||
| 94 | return sprintf(buf, "full\n"); | ||
| 95 | } | ||
| 96 | |||
| 97 | static ssize_t ad7314_store_mode(struct device *dev, | ||
| 98 | struct device_attribute *attr, | ||
| 99 | const char *buf, | ||
| 100 | size_t len) | ||
| 101 | { | ||
| 102 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 103 | struct ad7314_chip_info *chip = iio_priv(dev_info); | ||
| 104 | u16 mode = 0; | ||
| 105 | int ret; | ||
| 106 | |||
| 107 | if (!strcmp(buf, "full")) | ||
| 108 | mode = AD7314_PD; | ||
| 109 | |||
| 110 | ret = ad7314_spi_write(chip, mode); | ||
| 111 | if (ret) | ||
| 112 | return -EIO; | ||
| 113 | |||
| 114 | chip->mode = mode; | ||
| 115 | |||
| 116 | return len; | ||
| 117 | } | ||
| 118 | |||
| 119 | static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, | ||
| 120 | ad7314_show_mode, | ||
| 121 | ad7314_store_mode, | ||
| 122 | 0); | ||
| 123 | |||
| 124 | static ssize_t ad7314_show_available_modes(struct device *dev, | ||
| 125 | struct device_attribute *attr, | ||
| 126 | char *buf) | ||
| 127 | { | ||
| 128 | return sprintf(buf, "full\npower-save\n"); | ||
| 129 | } | ||
| 130 | |||
| 131 | static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7314_show_available_modes, NULL, 0); | ||
| 132 | |||
| 133 | static ssize_t ad7314_show_temperature(struct device *dev, | ||
| 134 | struct device_attribute *attr, | ||
| 135 | char *buf) | ||
| 136 | { | ||
| 137 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 138 | struct ad7314_chip_info *chip = iio_priv(dev_info); | ||
| 139 | u16 data; | ||
| 140 | char sign = ' '; | ||
| 141 | int ret; | ||
| 142 | |||
| 143 | if (chip->mode) { | ||
| 144 | ret = ad7314_spi_write(chip, 0); | ||
| 145 | if (ret) | ||
| 146 | return -EIO; | ||
| 147 | } | ||
| 148 | |||
| 149 | ret = ad7314_spi_read(chip, &data); | ||
| 150 | if (ret) | ||
| 151 | return -EIO; | ||
| 152 | |||
| 153 | if (chip->mode) | ||
| 154 | ad7314_spi_write(chip, chip->mode); | ||
| 155 | |||
| 156 | if (strcmp(dev_info->name, "ad7314")) { | ||
| 157 | data = (data & AD7314_TEMP_MASK) >> | ||
| 158 | AD7314_TEMP_OFFSET; | ||
| 159 | if (data & AD7314_TEMP_SIGN) { | ||
| 160 | data = (AD7314_TEMP_SIGN << 1) - data; | ||
| 161 | sign = '-'; | ||
| 162 | } | ||
| 163 | |||
| 164 | return sprintf(buf, "%c%d.%.2d\n", sign, | ||
| 165 | data >> AD7314_TEMP_FLOAT_OFFSET, | ||
| 166 | (data & AD7314_TEMP_FLOAT_MASK) * 25); | ||
| 167 | } else { | ||
| 168 | data &= ADT7301_TEMP_MASK; | ||
| 169 | if (data & ADT7301_TEMP_SIGN) { | ||
| 170 | data = (ADT7301_TEMP_SIGN << 1) - data; | ||
| 171 | sign = '-'; | ||
| 172 | } | ||
| 173 | |||
| 174 | return sprintf(buf, "%c%d.%.5d\n", sign, | ||
| 175 | data >> ADT7301_TEMP_FLOAT_OFFSET, | ||
| 176 | (data & ADT7301_TEMP_FLOAT_MASK) * 3125); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | static IIO_DEVICE_ATTR(temperature, S_IRUGO, ad7314_show_temperature, NULL, 0); | ||
| 181 | |||
| 182 | static struct attribute *ad7314_attributes[] = { | ||
| 183 | &iio_dev_attr_available_modes.dev_attr.attr, | ||
| 184 | &iio_dev_attr_mode.dev_attr.attr, | ||
| 185 | &iio_dev_attr_temperature.dev_attr.attr, | ||
| 186 | NULL, | ||
| 187 | }; | ||
| 188 | |||
| 189 | static const struct attribute_group ad7314_attribute_group = { | ||
| 190 | .attrs = ad7314_attributes, | ||
| 191 | }; | ||
| 192 | |||
| 193 | static const struct iio_info ad7314_info = { | ||
| 194 | .attrs = &ad7314_attribute_group, | ||
| 195 | .driver_module = THIS_MODULE, | ||
| 196 | }; | ||
| 197 | /* | ||
| 198 | * device probe and remove | ||
| 199 | */ | ||
| 200 | |||
| 201 | static int __devinit ad7314_probe(struct spi_device *spi_dev) | ||
| 202 | { | ||
| 203 | struct ad7314_chip_info *chip; | ||
| 204 | struct iio_dev *indio_dev; | ||
| 205 | int ret = 0; | ||
| 206 | |||
| 207 | indio_dev = iio_allocate_device(sizeof(*chip)); | ||
| 208 | if (indio_dev == NULL) { | ||
| 209 | ret = -ENOMEM; | ||
| 210 | goto error_ret; | ||
| 211 | } | ||
| 212 | chip = iio_priv(indio_dev); | ||
| 213 | /* this is only used for device removal purposes */ | ||
| 214 | dev_set_drvdata(&spi_dev->dev, chip); | ||
| 215 | |||
| 216 | chip->spi_dev = spi_dev; | ||
| 217 | |||
| 218 | indio_dev->name = spi_get_device_id(spi_dev)->name; | ||
| 219 | indio_dev->dev.parent = &spi_dev->dev; | ||
| 220 | indio_dev->info = &ad7314_info; | ||
| 221 | |||
| 222 | ret = iio_device_register(indio_dev); | ||
| 223 | if (ret) | ||
| 224 | goto error_free_dev; | ||
| 225 | |||
| 226 | dev_info(&spi_dev->dev, "%s temperature sensor registered.\n", | ||
| 227 | indio_dev->name); | ||
| 228 | |||
| 229 | return 0; | ||
| 230 | error_free_dev: | ||
| 231 | iio_free_device(indio_dev); | ||
| 232 | error_ret: | ||
| 233 | return ret; | ||
| 234 | } | ||
| 235 | |||
| 236 | static int __devexit ad7314_remove(struct spi_device *spi_dev) | ||
| 237 | { | ||
| 238 | struct iio_dev *indio_dev = dev_get_drvdata(&spi_dev->dev); | ||
| 239 | |||
| 240 | dev_set_drvdata(&spi_dev->dev, NULL); | ||
| 241 | iio_device_unregister(indio_dev); | ||
| 242 | iio_free_device(indio_dev); | ||
| 243 | |||
| 244 | return 0; | ||
| 245 | } | ||
| 246 | |||
| 247 | static const struct spi_device_id ad7314_id[] = { | ||
| 248 | { "adt7301", 0 }, | ||
| 249 | { "adt7302", 0 }, | ||
| 250 | { "ad7314", 0 }, | ||
| 251 | {} | ||
| 252 | }; | ||
| 253 | |||
| 254 | static struct spi_driver ad7314_driver = { | ||
| 255 | .driver = { | ||
| 256 | .name = "ad7314", | ||
| 257 | .bus = &spi_bus_type, | ||
| 258 | .owner = THIS_MODULE, | ||
| 259 | }, | ||
| 260 | .probe = ad7314_probe, | ||
| 261 | .remove = __devexit_p(ad7314_remove), | ||
| 262 | .id_table = ad7314_id, | ||
| 263 | }; | ||
| 264 | |||
| 265 | static __init int ad7314_init(void) | ||
| 266 | { | ||
| 267 | return spi_register_driver(&ad7314_driver); | ||
| 268 | } | ||
| 269 | |||
| 270 | static __exit void ad7314_exit(void) | ||
| 271 | { | ||
| 272 | spi_unregister_driver(&ad7314_driver); | ||
| 273 | } | ||
| 274 | |||
| 275 | MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); | ||
| 276 | MODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital" | ||
| 277 | " temperature sensor driver"); | ||
| 278 | MODULE_LICENSE("GPL v2"); | ||
| 279 | |||
| 280 | module_init(ad7314_init); | ||
| 281 | module_exit(ad7314_exit); | ||
diff --git a/drivers/staging/iio/adc/ad7476.h b/drivers/staging/iio/adc/ad7476.h new file mode 100644 index 00000000000..0d44976e846 --- /dev/null +++ b/drivers/staging/iio/adc/ad7476.h | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | /* | ||
| 2 | * AD7476/5/7/8 (A) SPI ADC driver | ||
| 3 | * | ||
| 4 | * Copyright 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | #ifndef IIO_ADC_AD7476_H_ | ||
| 9 | #define IIO_ADC_AD7476_H_ | ||
| 10 | |||
| 11 | #define RES_MASK(bits) ((1 << (bits)) - 1) | ||
| 12 | |||
| 13 | /* | ||
| 14 | * TODO: struct ad7476_platform_data needs to go into include/linux/iio | ||
| 15 | */ | ||
| 16 | |||
| 17 | struct ad7476_platform_data { | ||
| 18 | u16 vref_mv; | ||
| 19 | }; | ||
| 20 | |||
| 21 | struct ad7476_chip_info { | ||
| 22 | u16 int_vref_mv; | ||
| 23 | struct iio_chan_spec channel[2]; | ||
| 24 | }; | ||
| 25 | |||
| 26 | struct ad7476_state { | ||
| 27 | struct spi_device *spi; | ||
| 28 | const struct ad7476_chip_info *chip_info; | ||
| 29 | struct regulator *reg; | ||
| 30 | size_t d_size; | ||
| 31 | u16 int_vref_mv; | ||
| 32 | struct spi_transfer xfer; | ||
| 33 | struct spi_message msg; | ||
| 34 | /* | ||
| 35 | * DMA (thus cache coherency maintenance) requires the | ||
| 36 | * transfer buffers to live in their own cache lines. | ||
| 37 | */ | ||
| 38 | unsigned char data[2] ____cacheline_aligned; | ||
| 39 | }; | ||
| 40 | |||
| 41 | enum ad7476_supported_device_ids { | ||
| 42 | ID_AD7466, | ||
| 43 | ID_AD7467, | ||
| 44 | ID_AD7468, | ||
| 45 | ID_AD7475, | ||
| 46 | ID_AD7476, | ||
| 47 | ID_AD7477, | ||
| 48 | ID_AD7478, | ||
| 49 | ID_AD7495 | ||
| 50 | }; | ||
| 51 | |||
| 52 | #ifdef CONFIG_IIO_RING_BUFFER | ||
| 53 | int ad7476_scan_from_ring(struct iio_dev *indio_dev); | ||
| 54 | int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev); | ||
| 55 | void ad7476_ring_cleanup(struct iio_dev *indio_dev); | ||
| 56 | #else /* CONFIG_IIO_RING_BUFFER */ | ||
| 57 | static inline int ad7476_scan_from_ring(struct iio_dev *indio_dev) | ||
| 58 | { | ||
| 59 | return 0; | ||
| 60 | } | ||
| 61 | |||
| 62 | static inline int | ||
| 63 | ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) | ||
| 64 | { | ||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | static inline void ad7476_ring_cleanup(struct iio_dev *indio_dev) | ||
| 69 | { | ||
| 70 | } | ||
| 71 | #endif /* CONFIG_IIO_RING_BUFFER */ | ||
| 72 | #endif /* IIO_ADC_AD7476_H_ */ | ||
diff --git a/drivers/staging/iio/adc/ad7476_core.c b/drivers/staging/iio/adc/ad7476_core.c new file mode 100644 index 00000000000..c21089894d2 --- /dev/null +++ b/drivers/staging/iio/adc/ad7476_core.c | |||
| @@ -0,0 +1,270 @@ | |||
| 1 | /* | ||
| 2 | * AD7466/7/8 AD7476/5/7/8 (A) SPI ADC driver | ||
| 3 | * | ||
| 4 | * Copyright 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/device.h> | ||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/sysfs.h> | ||
| 13 | #include <linux/spi/spi.h> | ||
| 14 | #include <linux/regulator/consumer.h> | ||
| 15 | #include <linux/err.h> | ||
| 16 | |||
| 17 | #include "../iio.h" | ||
| 18 | #include "../sysfs.h" | ||
| 19 | #include "../ring_generic.h" | ||
| 20 | #include "adc.h" | ||
| 21 | |||
| 22 | #include "ad7476.h" | ||
| 23 | |||
| 24 | static int ad7476_scan_direct(struct ad7476_state *st) | ||
| 25 | { | ||
| 26 | int ret; | ||
| 27 | |||
| 28 | ret = spi_sync(st->spi, &st->msg); | ||
| 29 | if (ret) | ||
| 30 | return ret; | ||
| 31 | |||
| 32 | return (st->data[0] << 8) | st->data[1]; | ||
| 33 | } | ||
| 34 | |||
| 35 | static int ad7476_read_raw(struct iio_dev *dev_info, | ||
| 36 | struct iio_chan_spec const *chan, | ||
| 37 | int *val, | ||
| 38 | int *val2, | ||
| 39 | long m) | ||
| 40 | { | ||
| 41 | int ret; | ||
| 42 | struct ad7476_state *st = iio_priv(dev_info); | ||
| 43 | unsigned int scale_uv; | ||
| 44 | |||
| 45 | switch (m) { | ||
| 46 | case 0: | ||
| 47 | mutex_lock(&dev_info->mlock); | ||
| 48 | if (iio_ring_enabled(dev_info)) | ||
| 49 | ret = ad7476_scan_from_ring(dev_info); | ||
| 50 | else | ||
| 51 | ret = ad7476_scan_direct(st); | ||
| 52 | mutex_unlock(&dev_info->mlock); | ||
| 53 | |||
| 54 | if (ret < 0) | ||
| 55 | return ret; | ||
| 56 | *val = (ret >> st->chip_info->channel[0].scan_type.shift) & | ||
| 57 | RES_MASK(st->chip_info->channel[0].scan_type.realbits); | ||
| 58 | return IIO_VAL_INT; | ||
| 59 | case (1 << IIO_CHAN_INFO_SCALE_SHARED): | ||
| 60 | scale_uv = (st->int_vref_mv * 1000) | ||
| 61 | >> st->chip_info->channel[0].scan_type.realbits; | ||
| 62 | *val = scale_uv/1000; | ||
| 63 | *val2 = (scale_uv%1000)*1000; | ||
| 64 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 65 | } | ||
| 66 | return -EINVAL; | ||
| 67 | } | ||
| 68 | |||
| 69 | static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { | ||
| 70 | [ID_AD7466] = { | ||
| 71 | .channel[0] = IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, | ||
| 72 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 73 | 0, 0, IIO_ST('u', 12, 16, 0), 0), | ||
| 74 | .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), | ||
| 75 | }, | ||
| 76 | [ID_AD7467] = { | ||
| 77 | .channel[0] = IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, | ||
| 78 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 79 | 0, 0, IIO_ST('u', 10, 16, 2), 0), | ||
| 80 | .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), | ||
| 81 | }, | ||
| 82 | [ID_AD7468] = { | ||
| 83 | .channel[0] = IIO_CHAN(IIO_IN, 0, 1 , 0, NULL, 0, 0, | ||
| 84 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 85 | 0, 0, IIO_ST('u', 8, 16, 4), 0), | ||
| 86 | .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), | ||
| 87 | }, | ||
| 88 | [ID_AD7475] = { | ||
| 89 | .channel[0] = IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, | ||
| 90 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 91 | 0, 0, IIO_ST('u', 12, 16, 0), 0), | ||
| 92 | .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), | ||
| 93 | }, | ||
| 94 | [ID_AD7476] = { | ||
| 95 | .channel[0] = IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, | ||
| 96 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 97 | 0, 0, IIO_ST('u', 12, 16, 0), 0), | ||
| 98 | .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), | ||
| 99 | }, | ||
| 100 | [ID_AD7477] = { | ||
| 101 | .channel[0] = IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, | ||
| 102 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 103 | 0, 0, IIO_ST('u', 10, 16, 2), 0), | ||
| 104 | .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), | ||
| 105 | }, | ||
| 106 | [ID_AD7478] = { | ||
| 107 | .channel[0] = IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, | ||
| 108 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 109 | 0, 0, IIO_ST('u', 8, 16, 4), 0), | ||
| 110 | .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), | ||
| 111 | }, | ||
| 112 | [ID_AD7495] = { | ||
| 113 | .channel[0] = IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, | ||
| 114 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 115 | 0, 0, IIO_ST('u', 12, 16, 0), 0), | ||
| 116 | .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), | ||
| 117 | .int_vref_mv = 2500, | ||
| 118 | }, | ||
| 119 | }; | ||
| 120 | |||
| 121 | static const struct iio_info ad7476_info = { | ||
| 122 | .driver_module = THIS_MODULE, | ||
| 123 | .read_raw = &ad7476_read_raw, | ||
| 124 | }; | ||
| 125 | |||
| 126 | static int __devinit ad7476_probe(struct spi_device *spi) | ||
| 127 | { | ||
| 128 | struct ad7476_platform_data *pdata = spi->dev.platform_data; | ||
| 129 | struct ad7476_state *st; | ||
| 130 | struct iio_dev *indio_dev; | ||
| 131 | int ret, voltage_uv = 0; | ||
| 132 | bool reg_done = false; | ||
| 133 | struct regulator *reg; | ||
| 134 | |||
| 135 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
| 136 | if (indio_dev == NULL) { | ||
| 137 | ret = -ENOMEM; | ||
| 138 | goto error_ret; | ||
| 139 | } | ||
| 140 | st = iio_priv(indio_dev); | ||
| 141 | reg = regulator_get(&spi->dev, "vcc"); | ||
| 142 | if (!IS_ERR(reg)) { | ||
| 143 | ret = regulator_enable(reg); | ||
| 144 | if (ret) | ||
| 145 | goto error_put_reg; | ||
| 146 | |||
| 147 | voltage_uv = regulator_get_voltage(reg); | ||
| 148 | } | ||
| 149 | st->reg = reg; | ||
| 150 | st->chip_info = | ||
| 151 | &ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data]; | ||
| 152 | |||
| 153 | if (st->chip_info->int_vref_mv) | ||
| 154 | st->int_vref_mv = st->chip_info->int_vref_mv; | ||
| 155 | else if (pdata && pdata->vref_mv) | ||
| 156 | st->int_vref_mv = pdata->vref_mv; | ||
| 157 | else if (voltage_uv) | ||
| 158 | st->int_vref_mv = voltage_uv / 1000; | ||
| 159 | else | ||
| 160 | dev_warn(&spi->dev, "reference voltage unspecified\n"); | ||
| 161 | |||
| 162 | spi_set_drvdata(spi, indio_dev); | ||
| 163 | |||
| 164 | st->spi = spi; | ||
| 165 | |||
| 166 | /* Establish that the iio_dev is a child of the spi device */ | ||
| 167 | indio_dev->dev.parent = &spi->dev; | ||
| 168 | indio_dev->name = spi_get_device_id(spi)->name; | ||
| 169 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 170 | indio_dev->channels = st->chip_info->channel; | ||
| 171 | indio_dev->num_channels = 2; | ||
| 172 | indio_dev->info = &ad7476_info; | ||
| 173 | /* Setup default message */ | ||
| 174 | |||
| 175 | st->xfer.rx_buf = &st->data; | ||
| 176 | st->xfer.len = st->chip_info->channel[0].scan_type.storagebits / 8; | ||
| 177 | |||
| 178 | spi_message_init(&st->msg); | ||
| 179 | spi_message_add_tail(&st->xfer, &st->msg); | ||
| 180 | |||
| 181 | ret = ad7476_register_ring_funcs_and_init(indio_dev); | ||
| 182 | if (ret) | ||
| 183 | goto error_disable_reg; | ||
| 184 | |||
| 185 | ret = iio_device_register(indio_dev); | ||
| 186 | if (ret) | ||
| 187 | goto error_disable_reg; | ||
| 188 | |||
| 189 | ret = iio_ring_buffer_register_ex(indio_dev->ring, 0, | ||
| 190 | st->chip_info->channel, | ||
| 191 | ARRAY_SIZE(st->chip_info->channel)); | ||
| 192 | if (ret) | ||
| 193 | goto error_cleanup_ring; | ||
| 194 | return 0; | ||
| 195 | |||
| 196 | error_cleanup_ring: | ||
| 197 | ad7476_ring_cleanup(indio_dev); | ||
| 198 | iio_device_unregister(indio_dev); | ||
| 199 | error_disable_reg: | ||
| 200 | if (!IS_ERR(reg)) | ||
| 201 | regulator_disable(st->reg); | ||
| 202 | error_put_reg: | ||
| 203 | if (!IS_ERR(reg)) | ||
| 204 | regulator_put(reg); | ||
| 205 | if (!reg_done) | ||
| 206 | iio_free_device(indio_dev); | ||
| 207 | error_ret: | ||
| 208 | return ret; | ||
| 209 | } | ||
| 210 | |||
| 211 | static int ad7476_remove(struct spi_device *spi) | ||
| 212 | { | ||
| 213 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 214 | struct ad7476_state *st = iio_priv(indio_dev); | ||
| 215 | /* copy needed as st will have been freed */ | ||
| 216 | struct regulator *reg = st->reg; | ||
| 217 | |||
| 218 | iio_ring_buffer_unregister(indio_dev->ring); | ||
| 219 | ad7476_ring_cleanup(indio_dev); | ||
| 220 | iio_device_unregister(indio_dev); | ||
| 221 | if (!IS_ERR(reg)) { | ||
| 222 | regulator_disable(reg); | ||
| 223 | regulator_put(reg); | ||
| 224 | } | ||
| 225 | |||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | |||
| 229 | static const struct spi_device_id ad7476_id[] = { | ||
| 230 | {"ad7466", ID_AD7466}, | ||
| 231 | {"ad7467", ID_AD7467}, | ||
| 232 | {"ad7468", ID_AD7468}, | ||
| 233 | {"ad7475", ID_AD7475}, | ||
| 234 | {"ad7476", ID_AD7476}, | ||
| 235 | {"ad7476a", ID_AD7476}, | ||
| 236 | {"ad7477", ID_AD7477}, | ||
| 237 | {"ad7477a", ID_AD7477}, | ||
| 238 | {"ad7478", ID_AD7478}, | ||
| 239 | {"ad7478a", ID_AD7478}, | ||
| 240 | {"ad7495", ID_AD7495}, | ||
| 241 | {} | ||
| 242 | }; | ||
| 243 | |||
| 244 | static struct spi_driver ad7476_driver = { | ||
| 245 | .driver = { | ||
| 246 | .name = "ad7476", | ||
| 247 | .bus = &spi_bus_type, | ||
| 248 | .owner = THIS_MODULE, | ||
| 249 | }, | ||
| 250 | .probe = ad7476_probe, | ||
| 251 | .remove = __devexit_p(ad7476_remove), | ||
| 252 | .id_table = ad7476_id, | ||
| 253 | }; | ||
| 254 | |||
| 255 | static int __init ad7476_init(void) | ||
| 256 | { | ||
| 257 | return spi_register_driver(&ad7476_driver); | ||
| 258 | } | ||
| 259 | module_init(ad7476_init); | ||
| 260 | |||
| 261 | static void __exit ad7476_exit(void) | ||
| 262 | { | ||
| 263 | spi_unregister_driver(&ad7476_driver); | ||
| 264 | } | ||
| 265 | module_exit(ad7476_exit); | ||
| 266 | |||
| 267 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
| 268 | MODULE_DESCRIPTION("Analog Devices AD7475/6/7/8(A) AD7466/7/8 ADC"); | ||
| 269 | MODULE_LICENSE("GPL v2"); | ||
| 270 | MODULE_ALIAS("spi:ad7476"); | ||
diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c new file mode 100644 index 00000000000..a92fc5a1a60 --- /dev/null +++ b/drivers/staging/iio/adc/ad7476_ring.c | |||
| @@ -0,0 +1,165 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2010 Analog Devices Inc. | ||
| 3 | * Copyright (C) 2008 Jonathan Cameron | ||
| 4 | * | ||
| 5 | * Licensed under the GPL-2 or later. | ||
| 6 | * | ||
| 7 | * ad7476_ring.c | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/interrupt.h> | ||
| 11 | #include <linux/device.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/sysfs.h> | ||
| 15 | #include <linux/spi/spi.h> | ||
| 16 | |||
| 17 | #include "../iio.h" | ||
| 18 | #include "../ring_generic.h" | ||
| 19 | #include "../ring_sw.h" | ||
| 20 | #include "../trigger.h" | ||
| 21 | #include "../sysfs.h" | ||
| 22 | |||
| 23 | #include "ad7476.h" | ||
| 24 | |||
| 25 | int ad7476_scan_from_ring(struct iio_dev *indio_dev) | ||
| 26 | { | ||
| 27 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 28 | int ret; | ||
| 29 | u8 *ring_data; | ||
| 30 | |||
| 31 | ring_data = kmalloc(ring->access->get_bytes_per_datum(ring), | ||
| 32 | GFP_KERNEL); | ||
| 33 | if (ring_data == NULL) { | ||
| 34 | ret = -ENOMEM; | ||
| 35 | goto error_ret; | ||
| 36 | } | ||
| 37 | ret = ring->access->read_last(ring, ring_data); | ||
| 38 | if (ret) | ||
| 39 | goto error_free_ring_data; | ||
| 40 | |||
| 41 | ret = (ring_data[0] << 8) | ring_data[1]; | ||
| 42 | |||
| 43 | error_free_ring_data: | ||
| 44 | kfree(ring_data); | ||
| 45 | error_ret: | ||
| 46 | return ret; | ||
| 47 | } | ||
| 48 | |||
| 49 | /** | ||
| 50 | * ad7476_ring_preenable() setup the parameters of the ring before enabling | ||
| 51 | * | ||
| 52 | * The complex nature of the setting of the nuber of bytes per datum is due | ||
| 53 | * to this driver currently ensuring that the timestamp is stored at an 8 | ||
| 54 | * byte boundary. | ||
| 55 | **/ | ||
| 56 | static int ad7476_ring_preenable(struct iio_dev *indio_dev) | ||
| 57 | { | ||
| 58 | struct ad7476_state *st = iio_priv(indio_dev); | ||
| 59 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 60 | |||
| 61 | st->d_size = ring->scan_count * | ||
| 62 | st->chip_info->channel[0].scan_type.storagebits / 8; | ||
| 63 | |||
| 64 | if (ring->scan_timestamp) { | ||
| 65 | st->d_size += sizeof(s64); | ||
| 66 | |||
| 67 | if (st->d_size % sizeof(s64)) | ||
| 68 | st->d_size += sizeof(s64) - (st->d_size % sizeof(s64)); | ||
| 69 | } | ||
| 70 | |||
| 71 | if (indio_dev->ring->access->set_bytes_per_datum) | ||
| 72 | indio_dev->ring->access->set_bytes_per_datum(indio_dev->ring, | ||
| 73 | st->d_size); | ||
| 74 | |||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | static irqreturn_t ad7476_trigger_handler(int irq, void *p) | ||
| 79 | { | ||
| 80 | struct iio_poll_func *pf = p; | ||
| 81 | struct iio_dev *indio_dev = pf->private_data; | ||
| 82 | struct ad7476_state *st = iio_priv(indio_dev); | ||
| 83 | s64 time_ns; | ||
| 84 | __u8 *rxbuf; | ||
| 85 | int b_sent; | ||
| 86 | |||
| 87 | rxbuf = kzalloc(st->d_size, GFP_KERNEL); | ||
| 88 | if (rxbuf == NULL) | ||
| 89 | return -ENOMEM; | ||
| 90 | |||
| 91 | b_sent = spi_read(st->spi, rxbuf, | ||
| 92 | st->chip_info->channel[0].scan_type.storagebits / 8); | ||
| 93 | if (b_sent < 0) | ||
| 94 | goto done; | ||
| 95 | |||
| 96 | time_ns = iio_get_time_ns(); | ||
| 97 | |||
| 98 | if (indio_dev->ring->scan_timestamp) | ||
| 99 | memcpy(rxbuf + st->d_size - sizeof(s64), | ||
| 100 | &time_ns, sizeof(time_ns)); | ||
| 101 | |||
| 102 | indio_dev->ring->access->store_to(indio_dev->ring, rxbuf, time_ns); | ||
| 103 | done: | ||
| 104 | iio_trigger_notify_done(indio_dev->trig); | ||
| 105 | kfree(rxbuf); | ||
| 106 | |||
| 107 | return IRQ_HANDLED; | ||
| 108 | } | ||
| 109 | |||
| 110 | static const struct iio_ring_setup_ops ad7476_ring_setup_ops = { | ||
| 111 | .preenable = &ad7476_ring_preenable, | ||
| 112 | .postenable = &iio_triggered_ring_postenable, | ||
| 113 | .predisable = &iio_triggered_ring_predisable, | ||
| 114 | }; | ||
| 115 | |||
| 116 | int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) | ||
| 117 | { | ||
| 118 | struct ad7476_state *st = iio_priv(indio_dev); | ||
| 119 | int ret = 0; | ||
| 120 | |||
| 121 | indio_dev->ring = iio_sw_rb_allocate(indio_dev); | ||
| 122 | if (!indio_dev->ring) { | ||
| 123 | ret = -ENOMEM; | ||
| 124 | goto error_ret; | ||
| 125 | } | ||
| 126 | /* Effectively select the ring buffer implementation */ | ||
| 127 | indio_dev->ring->access = &ring_sw_access_funcs; | ||
| 128 | indio_dev->pollfunc | ||
| 129 | = iio_alloc_pollfunc(NULL, | ||
| 130 | &ad7476_trigger_handler, | ||
| 131 | IRQF_ONESHOT, | ||
| 132 | indio_dev, | ||
| 133 | "%s_consumer%d", | ||
| 134 | spi_get_device_id(st->spi)->name, | ||
| 135 | indio_dev->id); | ||
| 136 | if (indio_dev->pollfunc == NULL) { | ||
| 137 | ret = -ENOMEM; | ||
| 138 | goto error_deallocate_sw_rb; | ||
| 139 | } | ||
| 140 | |||
| 141 | /* Ring buffer functions - here trigger setup related */ | ||
| 142 | indio_dev->ring->setup_ops = &ad7476_ring_setup_ops; | ||
| 143 | indio_dev->ring->scan_timestamp = true; | ||
| 144 | |||
| 145 | /* Flag that polled ring buffering is possible */ | ||
| 146 | indio_dev->modes |= INDIO_RING_TRIGGERED; | ||
| 147 | return 0; | ||
| 148 | |||
| 149 | error_deallocate_sw_rb: | ||
| 150 | iio_sw_rb_free(indio_dev->ring); | ||
| 151 | error_ret: | ||
| 152 | return ret; | ||
| 153 | } | ||
| 154 | |||
| 155 | void ad7476_ring_cleanup(struct iio_dev *indio_dev) | ||
| 156 | { | ||
| 157 | /* ensure that the trigger has been detached */ | ||
| 158 | if (indio_dev->trig) { | ||
| 159 | iio_put_trigger(indio_dev->trig); | ||
| 160 | iio_trigger_dettach_poll_func(indio_dev->trig, | ||
| 161 | indio_dev->pollfunc); | ||
| 162 | } | ||
| 163 | iio_dealloc_pollfunc(indio_dev->pollfunc); | ||
| 164 | iio_sw_rb_free(indio_dev->ring); | ||
| 165 | } | ||
diff --git a/drivers/staging/iio/adc/ad7745.c b/drivers/staging/iio/adc/ad7745.c new file mode 100644 index 00000000000..4c13f26aa9a --- /dev/null +++ b/drivers/staging/iio/adc/ad7745.c | |||
| @@ -0,0 +1,674 @@ | |||
| 1 | /* | ||
| 2 | * AD774X capacitive sensor driver supporting AD7745/6/7 | ||
| 3 | * | ||
| 4 | * Copyright 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/gpio.h> | ||
| 11 | #include <linux/device.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/sysfs.h> | ||
| 15 | #include <linux/list.h> | ||
| 16 | #include <linux/i2c.h> | ||
| 17 | |||
| 18 | #include "../iio.h" | ||
| 19 | #include "../sysfs.h" | ||
| 20 | |||
| 21 | /* | ||
| 22 | * AD774X registers definition | ||
| 23 | */ | ||
| 24 | |||
| 25 | #define AD774X_STATUS 0 | ||
| 26 | #define AD774X_STATUS_RDY (1 << 2) | ||
| 27 | #define AD774X_STATUS_RDYVT (1 << 1) | ||
| 28 | #define AD774X_STATUS_RDYCAP (1 << 0) | ||
| 29 | #define AD774X_CAP_DATA_HIGH 1 | ||
| 30 | #define AD774X_CAP_DATA_MID 2 | ||
| 31 | #define AD774X_CAP_DATA_LOW 3 | ||
| 32 | #define AD774X_VT_DATA_HIGH 4 | ||
| 33 | #define AD774X_VT_DATA_MID 5 | ||
| 34 | #define AD774X_VT_DATA_LOW 6 | ||
| 35 | #define AD774X_CAP_SETUP 7 | ||
| 36 | #define AD774X_VT_SETUP 8 | ||
| 37 | #define AD774X_EXEC_SETUP 9 | ||
| 38 | #define AD774X_CFG 10 | ||
| 39 | #define AD774X_CAPDACA 11 | ||
| 40 | #define AD774X_CAPDACB 12 | ||
| 41 | #define AD774X_CAPDAC_EN (1 << 7) | ||
| 42 | #define AD774X_CAP_OFFH 13 | ||
| 43 | #define AD774X_CAP_OFFL 14 | ||
| 44 | #define AD774X_CAP_GAINH 15 | ||
| 45 | #define AD774X_CAP_GAINL 16 | ||
| 46 | #define AD774X_VOLT_GAINH 17 | ||
| 47 | #define AD774X_VOLT_GAINL 18 | ||
| 48 | |||
| 49 | #define AD774X_MAX_CONV_MODE 6 | ||
| 50 | |||
| 51 | /* | ||
| 52 | * struct ad774x_chip_info - chip specifc information | ||
| 53 | */ | ||
| 54 | |||
| 55 | struct ad774x_chip_info { | ||
| 56 | struct i2c_client *client; | ||
| 57 | bool inter; | ||
| 58 | u16 cap_offs; /* Capacitive offset */ | ||
| 59 | u16 cap_gain; /* Capacitive gain calibration */ | ||
| 60 | u16 volt_gain; /* Voltage gain calibration */ | ||
| 61 | u8 cap_setup; | ||
| 62 | u8 vt_setup; | ||
| 63 | u8 exec_setup; | ||
| 64 | |||
| 65 | char *conversion_mode; | ||
| 66 | }; | ||
| 67 | |||
| 68 | struct ad774x_conversion_mode { | ||
| 69 | char *name; | ||
| 70 | u8 reg_cfg; | ||
| 71 | }; | ||
| 72 | |||
| 73 | static struct ad774x_conversion_mode | ||
| 74 | ad774x_conv_mode_table[AD774X_MAX_CONV_MODE] = { | ||
| 75 | { "idle", 0 }, | ||
| 76 | { "continuous-conversion", 1 }, | ||
| 77 | { "single-conversion", 2 }, | ||
| 78 | { "power-down", 3 }, | ||
| 79 | { "offset-calibration", 5 }, | ||
| 80 | { "gain-calibration", 6 }, | ||
| 81 | }; | ||
| 82 | |||
| 83 | /* | ||
| 84 | * ad774x register access by I2C | ||
| 85 | */ | ||
| 86 | |||
| 87 | static int ad774x_i2c_read(struct ad774x_chip_info *chip, u8 reg, u8 *data, int len) | ||
| 88 | { | ||
| 89 | struct i2c_client *client = chip->client; | ||
| 90 | int ret; | ||
| 91 | |||
| 92 | ret = i2c_master_send(client, ®, 1); | ||
| 93 | if (ret < 0) { | ||
| 94 | dev_err(&client->dev, "I2C write error\n"); | ||
| 95 | return ret; | ||
| 96 | } | ||
| 97 | |||
| 98 | ret = i2c_master_recv(client, data, len); | ||
| 99 | if (ret < 0) { | ||
| 100 | dev_err(&client->dev, "I2C read error\n"); | ||
| 101 | return ret; | ||
| 102 | } | ||
| 103 | |||
| 104 | return ret; | ||
| 105 | } | ||
| 106 | |||
| 107 | static int ad774x_i2c_write(struct ad774x_chip_info *chip, u8 reg, u8 data) | ||
| 108 | { | ||
| 109 | struct i2c_client *client = chip->client; | ||
| 110 | int ret; | ||
| 111 | |||
| 112 | u8 tx[2] = { | ||
| 113 | reg, | ||
| 114 | data, | ||
| 115 | }; | ||
| 116 | |||
| 117 | ret = i2c_master_send(client, tx, 2); | ||
| 118 | if (ret < 0) | ||
| 119 | dev_err(&client->dev, "I2C write error\n"); | ||
| 120 | |||
| 121 | return ret; | ||
| 122 | } | ||
| 123 | |||
| 124 | /* | ||
| 125 | * sysfs nodes | ||
| 126 | */ | ||
| 127 | |||
| 128 | #define IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(_show) \ | ||
| 129 | IIO_DEVICE_ATTR(available_conversion_modes, S_IRUGO, _show, NULL, 0) | ||
| 130 | #define IIO_DEV_ATTR_CONVERSION_MODE(_mode, _show, _store) \ | ||
| 131 | IIO_DEVICE_ATTR(conversion_mode, _mode, _show, _store, 0) | ||
| 132 | #define IIO_DEV_ATTR_CAP_SETUP(_mode, _show, _store) \ | ||
| 133 | IIO_DEVICE_ATTR(cap_setup, _mode, _show, _store, 0) | ||
| 134 | #define IIO_DEV_ATTR_VT_SETUP(_mode, _show, _store) \ | ||
| 135 | IIO_DEVICE_ATTR(in0_setup, _mode, _show, _store, 0) | ||
| 136 | #define IIO_DEV_ATTR_EXEC_SETUP(_mode, _show, _store) \ | ||
| 137 | IIO_DEVICE_ATTR(exec_setup, _mode, _show, _store, 0) | ||
| 138 | #define IIO_DEV_ATTR_VOLT_GAIN(_mode, _show, _store) \ | ||
| 139 | IIO_DEVICE_ATTR(in0_gain, _mode, _show, _store, 0) | ||
| 140 | #define IIO_DEV_ATTR_CAP_OFFS(_mode, _show, _store) \ | ||
| 141 | IIO_DEVICE_ATTR(cap_offs, _mode, _show, _store, 0) | ||
| 142 | #define IIO_DEV_ATTR_CAP_GAIN(_mode, _show, _store) \ | ||
| 143 | IIO_DEVICE_ATTR(cap_gain, _mode, _show, _store, 0) | ||
| 144 | #define IIO_DEV_ATTR_CAP_DATA(_show) \ | ||
| 145 | IIO_DEVICE_ATTR(cap0_raw, S_IRUGO, _show, NULL, 0) | ||
| 146 | #define IIO_DEV_ATTR_VT_DATA(_show) \ | ||
| 147 | IIO_DEVICE_ATTR(in0_raw, S_IRUGO, _show, NULL, 0) | ||
| 148 | |||
| 149 | static ssize_t ad774x_show_conversion_modes(struct device *dev, | ||
| 150 | struct device_attribute *attr, | ||
| 151 | char *buf) | ||
| 152 | { | ||
| 153 | int i; | ||
| 154 | int len = 0; | ||
| 155 | |||
| 156 | for (i = 0; i < AD774X_MAX_CONV_MODE; i++) | ||
| 157 | len += sprintf(buf + len, "%s ", ad774x_conv_mode_table[i].name); | ||
| 158 | |||
| 159 | len += sprintf(buf + len, "\n"); | ||
| 160 | |||
| 161 | return len; | ||
| 162 | } | ||
| 163 | |||
| 164 | static IIO_DEV_ATTR_AVAIL_CONVERSION_MODES(ad774x_show_conversion_modes); | ||
| 165 | |||
| 166 | static ssize_t ad774x_show_conversion_mode(struct device *dev, | ||
| 167 | struct device_attribute *attr, | ||
| 168 | char *buf) | ||
| 169 | { | ||
| 170 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 171 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 172 | |||
| 173 | return sprintf(buf, "%s\n", chip->conversion_mode); | ||
| 174 | } | ||
| 175 | |||
| 176 | static ssize_t ad774x_store_conversion_mode(struct device *dev, | ||
| 177 | struct device_attribute *attr, | ||
| 178 | const char *buf, | ||
| 179 | size_t len) | ||
| 180 | { | ||
| 181 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 182 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 183 | u8 cfg; | ||
| 184 | int i; | ||
| 185 | |||
| 186 | ad774x_i2c_read(chip, AD774X_CFG, &cfg, 1); | ||
| 187 | |||
| 188 | for (i = 0; i < AD774X_MAX_CONV_MODE; i++) { | ||
| 189 | if (strncmp(buf, ad774x_conv_mode_table[i].name, | ||
| 190 | strlen(ad774x_conv_mode_table[i].name) - 1) == 0) { | ||
| 191 | chip->conversion_mode = ad774x_conv_mode_table[i].name; | ||
| 192 | cfg |= 0x18 | ad774x_conv_mode_table[i].reg_cfg; | ||
| 193 | ad774x_i2c_write(chip, AD774X_CFG, cfg); | ||
| 194 | return len; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | |||
| 198 | dev_err(dev, "not supported conversion mode\n"); | ||
| 199 | |||
| 200 | return -EINVAL; | ||
| 201 | } | ||
| 202 | |||
| 203 | static IIO_DEV_ATTR_CONVERSION_MODE(S_IRUGO | S_IWUSR, | ||
| 204 | ad774x_show_conversion_mode, | ||
| 205 | ad774x_store_conversion_mode); | ||
| 206 | |||
| 207 | static ssize_t ad774x_show_dac_value(struct device *dev, | ||
| 208 | struct device_attribute *attr, | ||
| 209 | char *buf) | ||
| 210 | { | ||
| 211 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 212 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 213 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 214 | u8 data; | ||
| 215 | |||
| 216 | ad774x_i2c_read(chip, this_attr->address, &data, 1); | ||
| 217 | |||
| 218 | return sprintf(buf, "%02x\n", data & 0x7F); | ||
| 219 | } | ||
| 220 | |||
| 221 | static ssize_t ad774x_store_dac_value(struct device *dev, | ||
| 222 | struct device_attribute *attr, | ||
| 223 | const char *buf, | ||
| 224 | size_t len) | ||
| 225 | { | ||
| 226 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 227 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 228 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 229 | unsigned long data; | ||
| 230 | int ret; | ||
| 231 | |||
| 232 | ret = strict_strtoul(buf, 10, &data); | ||
| 233 | |||
| 234 | if (!ret) { | ||
| 235 | ad774x_i2c_write(chip, this_attr->address, | ||
| 236 | (data ? AD774X_CAPDAC_EN : 0) | (data & 0x7F)); | ||
| 237 | return len; | ||
| 238 | } | ||
| 239 | |||
| 240 | return -EINVAL; | ||
| 241 | } | ||
| 242 | |||
| 243 | static IIO_DEVICE_ATTR(capdac0_raw, S_IRUGO | S_IWUSR, | ||
| 244 | ad774x_show_dac_value, | ||
| 245 | ad774x_store_dac_value, | ||
| 246 | AD774X_CAPDACA); | ||
| 247 | |||
| 248 | static IIO_DEVICE_ATTR(capdac1_raw, S_IRUGO | S_IWUSR, | ||
| 249 | ad774x_show_dac_value, | ||
| 250 | ad774x_store_dac_value, | ||
| 251 | AD774X_CAPDACB); | ||
| 252 | |||
| 253 | static ssize_t ad774x_show_cap_setup(struct device *dev, | ||
| 254 | struct device_attribute *attr, | ||
| 255 | char *buf) | ||
| 256 | { | ||
| 257 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 258 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 259 | |||
| 260 | return sprintf(buf, "0x%02x\n", chip->cap_setup); | ||
| 261 | } | ||
| 262 | |||
| 263 | static ssize_t ad774x_store_cap_setup(struct device *dev, | ||
| 264 | struct device_attribute *attr, | ||
| 265 | const char *buf, | ||
| 266 | size_t len) | ||
| 267 | { | ||
| 268 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 269 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 270 | unsigned long data; | ||
| 271 | int ret; | ||
| 272 | |||
| 273 | ret = strict_strtoul(buf, 10, &data); | ||
| 274 | |||
| 275 | if ((!ret) && (data < 0x100)) { | ||
| 276 | ad774x_i2c_write(chip, AD774X_CAP_SETUP, data); | ||
| 277 | chip->cap_setup = data; | ||
| 278 | return len; | ||
| 279 | } | ||
| 280 | |||
| 281 | return -EINVAL; | ||
| 282 | } | ||
| 283 | |||
| 284 | static IIO_DEV_ATTR_CAP_SETUP(S_IRUGO | S_IWUSR, | ||
| 285 | ad774x_show_cap_setup, | ||
| 286 | ad774x_store_cap_setup); | ||
| 287 | |||
| 288 | static ssize_t ad774x_show_vt_setup(struct device *dev, | ||
| 289 | struct device_attribute *attr, | ||
| 290 | char *buf) | ||
| 291 | { | ||
| 292 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 293 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 294 | |||
| 295 | return sprintf(buf, "0x%02x\n", chip->vt_setup); | ||
| 296 | } | ||
| 297 | |||
| 298 | static ssize_t ad774x_store_vt_setup(struct device *dev, | ||
| 299 | struct device_attribute *attr, | ||
| 300 | const char *buf, | ||
| 301 | size_t len) | ||
| 302 | { | ||
| 303 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 304 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 305 | unsigned long data; | ||
| 306 | int ret; | ||
| 307 | |||
| 308 | ret = strict_strtoul(buf, 10, &data); | ||
| 309 | |||
| 310 | if ((!ret) && (data < 0x100)) { | ||
| 311 | ad774x_i2c_write(chip, AD774X_VT_SETUP, data); | ||
| 312 | chip->vt_setup = data; | ||
| 313 | return len; | ||
| 314 | } | ||
| 315 | |||
| 316 | return -EINVAL; | ||
| 317 | } | ||
| 318 | |||
| 319 | static IIO_DEV_ATTR_VT_SETUP(S_IRUGO | S_IWUSR, | ||
| 320 | ad774x_show_vt_setup, | ||
| 321 | ad774x_store_vt_setup); | ||
| 322 | |||
| 323 | static ssize_t ad774x_show_exec_setup(struct device *dev, | ||
| 324 | struct device_attribute *attr, | ||
| 325 | char *buf) | ||
| 326 | { | ||
| 327 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 328 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 329 | |||
| 330 | return sprintf(buf, "0x%02x\n", chip->exec_setup); | ||
| 331 | } | ||
| 332 | |||
| 333 | static ssize_t ad774x_store_exec_setup(struct device *dev, | ||
| 334 | struct device_attribute *attr, | ||
| 335 | const char *buf, | ||
| 336 | size_t len) | ||
| 337 | { | ||
| 338 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 339 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 340 | unsigned long data; | ||
| 341 | int ret; | ||
| 342 | |||
| 343 | ret = strict_strtoul(buf, 10, &data); | ||
| 344 | |||
| 345 | if ((!ret) && (data < 0x100)) { | ||
| 346 | ad774x_i2c_write(chip, AD774X_EXEC_SETUP, data); | ||
| 347 | chip->exec_setup = data; | ||
| 348 | return len; | ||
| 349 | } | ||
| 350 | |||
| 351 | return -EINVAL; | ||
| 352 | } | ||
| 353 | |||
| 354 | static IIO_DEV_ATTR_EXEC_SETUP(S_IRUGO | S_IWUSR, | ||
| 355 | ad774x_show_exec_setup, | ||
| 356 | ad774x_store_exec_setup); | ||
| 357 | |||
| 358 | static ssize_t ad774x_show_volt_gain(struct device *dev, | ||
| 359 | struct device_attribute *attr, | ||
| 360 | char *buf) | ||
| 361 | { | ||
| 362 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 363 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 364 | |||
| 365 | return sprintf(buf, "%d\n", chip->volt_gain); | ||
| 366 | } | ||
| 367 | |||
| 368 | static ssize_t ad774x_store_volt_gain(struct device *dev, | ||
| 369 | struct device_attribute *attr, | ||
| 370 | const char *buf, | ||
| 371 | size_t len) | ||
| 372 | { | ||
| 373 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 374 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 375 | unsigned long data; | ||
| 376 | int ret; | ||
| 377 | |||
| 378 | ret = strict_strtoul(buf, 10, &data); | ||
| 379 | |||
| 380 | if ((!ret) && (data < 0x10000)) { | ||
| 381 | ad774x_i2c_write(chip, AD774X_VOLT_GAINH, data >> 8); | ||
| 382 | ad774x_i2c_write(chip, AD774X_VOLT_GAINL, data); | ||
| 383 | chip->volt_gain = data; | ||
| 384 | return len; | ||
| 385 | } | ||
| 386 | |||
| 387 | return -EINVAL; | ||
| 388 | } | ||
| 389 | |||
| 390 | static IIO_DEV_ATTR_VOLT_GAIN(S_IRUGO | S_IWUSR, | ||
| 391 | ad774x_show_volt_gain, | ||
| 392 | ad774x_store_volt_gain); | ||
| 393 | |||
| 394 | static ssize_t ad774x_show_cap_data(struct device *dev, | ||
| 395 | struct device_attribute *attr, | ||
| 396 | char *buf) | ||
| 397 | { | ||
| 398 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 399 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 400 | unsigned long data; | ||
| 401 | char tmp[3]; | ||
| 402 | |||
| 403 | ad774x_i2c_read(chip, AD774X_CAP_DATA_HIGH, tmp, 3); | ||
| 404 | data = ((int)tmp[0] << 16) | ((int)tmp[1] << 8) | (int)tmp[2]; | ||
| 405 | |||
| 406 | return sprintf(buf, "%ld\n", data); | ||
| 407 | } | ||
| 408 | |||
| 409 | static IIO_DEV_ATTR_CAP_DATA(ad774x_show_cap_data); | ||
| 410 | |||
| 411 | static ssize_t ad774x_show_vt_data(struct device *dev, | ||
| 412 | struct device_attribute *attr, | ||
| 413 | char *buf) | ||
| 414 | { | ||
| 415 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 416 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 417 | unsigned long data; | ||
| 418 | char tmp[3]; | ||
| 419 | |||
| 420 | ad774x_i2c_read(chip, AD774X_VT_DATA_HIGH, tmp, 3); | ||
| 421 | data = ((int)tmp[0] << 16) | ((int)tmp[1] << 8) | (int)tmp[2]; | ||
| 422 | |||
| 423 | return sprintf(buf, "%ld\n", data); | ||
| 424 | } | ||
| 425 | |||
| 426 | static IIO_DEV_ATTR_VT_DATA(ad774x_show_vt_data); | ||
| 427 | |||
| 428 | static ssize_t ad774x_show_cap_offs(struct device *dev, | ||
| 429 | struct device_attribute *attr, | ||
| 430 | char *buf) | ||
| 431 | { | ||
| 432 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 433 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 434 | |||
| 435 | return sprintf(buf, "%d\n", chip->cap_offs); | ||
| 436 | } | ||
| 437 | |||
| 438 | static ssize_t ad774x_store_cap_offs(struct device *dev, | ||
| 439 | struct device_attribute *attr, | ||
| 440 | const char *buf, | ||
| 441 | size_t len) | ||
| 442 | { | ||
| 443 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 444 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 445 | unsigned long data; | ||
| 446 | int ret; | ||
| 447 | |||
| 448 | ret = strict_strtoul(buf, 10, &data); | ||
| 449 | |||
| 450 | if ((!ret) && (data < 0x10000)) { | ||
| 451 | ad774x_i2c_write(chip, AD774X_CAP_OFFH, data >> 8); | ||
| 452 | ad774x_i2c_write(chip, AD774X_CAP_OFFL, data); | ||
| 453 | chip->cap_offs = data; | ||
| 454 | return len; | ||
| 455 | } | ||
| 456 | |||
| 457 | return -EINVAL; | ||
| 458 | } | ||
| 459 | |||
| 460 | static IIO_DEV_ATTR_CAP_OFFS(S_IRUGO | S_IWUSR, | ||
| 461 | ad774x_show_cap_offs, | ||
| 462 | ad774x_store_cap_offs); | ||
| 463 | |||
| 464 | static ssize_t ad774x_show_cap_gain(struct device *dev, | ||
| 465 | struct device_attribute *attr, | ||
| 466 | char *buf) | ||
| 467 | { | ||
| 468 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 469 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 470 | |||
| 471 | return sprintf(buf, "%d\n", chip->cap_gain); | ||
| 472 | } | ||
| 473 | |||
| 474 | static ssize_t ad774x_store_cap_gain(struct device *dev, | ||
| 475 | struct device_attribute *attr, | ||
| 476 | const char *buf, | ||
| 477 | size_t len) | ||
| 478 | { | ||
| 479 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 480 | struct ad774x_chip_info *chip = iio_priv(dev_info); | ||
| 481 | unsigned long data; | ||
| 482 | int ret; | ||
| 483 | |||
| 484 | ret = strict_strtoul(buf, 10, &data); | ||
| 485 | |||
| 486 | if ((!ret) && (data < 0x10000)) { | ||
| 487 | ad774x_i2c_write(chip, AD774X_CAP_GAINH, data >> 8); | ||
| 488 | ad774x_i2c_write(chip, AD774X_CAP_GAINL, data); | ||
| 489 | chip->cap_gain = data; | ||
| 490 | return len; | ||
| 491 | } | ||
| 492 | |||
| 493 | return -EINVAL; | ||
| 494 | } | ||
| 495 | |||
| 496 | static IIO_DEV_ATTR_CAP_GAIN(S_IRUGO | S_IWUSR, | ||
| 497 | ad774x_show_cap_gain, | ||
| 498 | ad774x_store_cap_gain); | ||
| 499 | |||
| 500 | static struct attribute *ad774x_attributes[] = { | ||
| 501 | &iio_dev_attr_available_conversion_modes.dev_attr.attr, | ||
| 502 | &iio_dev_attr_conversion_mode.dev_attr.attr, | ||
| 503 | &iio_dev_attr_cap_setup.dev_attr.attr, | ||
| 504 | &iio_dev_attr_in0_setup.dev_attr.attr, | ||
| 505 | &iio_dev_attr_exec_setup.dev_attr.attr, | ||
| 506 | &iio_dev_attr_cap_offs.dev_attr.attr, | ||
| 507 | &iio_dev_attr_cap_gain.dev_attr.attr, | ||
| 508 | &iio_dev_attr_in0_gain.dev_attr.attr, | ||
| 509 | &iio_dev_attr_in0_raw.dev_attr.attr, | ||
| 510 | &iio_dev_attr_cap0_raw.dev_attr.attr, | ||
| 511 | &iio_dev_attr_capdac0_raw.dev_attr.attr, | ||
| 512 | &iio_dev_attr_capdac1_raw.dev_attr.attr, | ||
| 513 | NULL, | ||
| 514 | }; | ||
| 515 | |||
| 516 | static const struct attribute_group ad774x_attribute_group = { | ||
| 517 | .attrs = ad774x_attributes, | ||
| 518 | }; | ||
| 519 | |||
| 520 | /* | ||
| 521 | * data ready events | ||
| 522 | */ | ||
| 523 | |||
| 524 | #define IIO_EVENT_CODE_CAP_RDY 0 | ||
| 525 | #define IIO_EVENT_CODE_VT_RDY 1 | ||
| 526 | |||
| 527 | #define IIO_EVENT_ATTR_CAP_RDY_SH(_evlist, _show, _store, _mask) \ | ||
| 528 | IIO_EVENT_ATTR_SH(cap_rdy, _evlist, _show, _store, _mask) | ||
| 529 | |||
| 530 | #define IIO_EVENT_ATTR_VT_RDY_SH(_evlist, _show, _store, _mask) \ | ||
| 531 | IIO_EVENT_ATTR_SH(vt_rdy, _evlist, _show, _store, _mask) | ||
| 532 | |||
| 533 | static irqreturn_t ad774x_event_handler(int irq, void *private) | ||
| 534 | { | ||
| 535 | struct iio_dev *indio_dev = private; | ||
| 536 | struct ad774x_chip_info *chip = iio_priv(indio_dev); | ||
| 537 | u8 int_status; | ||
| 538 | |||
| 539 | ad774x_i2c_read(chip, AD774X_STATUS, &int_status, 1); | ||
| 540 | |||
| 541 | if (int_status & AD774X_STATUS_RDYCAP) | ||
| 542 | iio_push_event(indio_dev, 0, | ||
| 543 | IIO_EVENT_CODE_CAP_RDY, | ||
| 544 | iio_get_time_ns()); | ||
| 545 | |||
| 546 | if (int_status & AD774X_STATUS_RDYVT) | ||
| 547 | iio_push_event(indio_dev, 0, | ||
| 548 | IIO_EVENT_CODE_VT_RDY, | ||
| 549 | iio_get_time_ns()); | ||
| 550 | |||
| 551 | return IRQ_HANDLED; | ||
| 552 | } | ||
| 553 | |||
| 554 | static IIO_CONST_ATTR(cap_rdy_en, "1"); | ||
| 555 | static IIO_CONST_ATTR(vt_rdy_en, "1"); | ||
| 556 | |||
| 557 | static struct attribute *ad774x_event_attributes[] = { | ||
| 558 | &iio_const_attr_cap_rdy_en.dev_attr.attr, | ||
| 559 | &iio_const_attr_vt_rdy_en.dev_attr.attr, | ||
| 560 | NULL, | ||
| 561 | }; | ||
| 562 | |||
| 563 | static struct attribute_group ad774x_event_attribute_group = { | ||
| 564 | .attrs = ad774x_event_attributes, | ||
| 565 | }; | ||
| 566 | |||
| 567 | static const struct iio_info ad774x_info = { | ||
| 568 | .attrs = &ad774x_event_attribute_group, | ||
| 569 | .event_attrs = &ad774x_event_attribute_group, | ||
| 570 | .num_interrupt_lines = 1, | ||
| 571 | .driver_module = THIS_MODULE, | ||
| 572 | }; | ||
| 573 | /* | ||
| 574 | * device probe and remove | ||
| 575 | */ | ||
| 576 | |||
| 577 | static int __devinit ad774x_probe(struct i2c_client *client, | ||
| 578 | const struct i2c_device_id *id) | ||
| 579 | { | ||
| 580 | int ret = 0, regdone = 0; | ||
| 581 | struct ad774x_chip_info *chip; | ||
| 582 | struct iio_dev *indio_dev; | ||
| 583 | |||
| 584 | indio_dev = iio_allocate_device(sizeof(*chip)); | ||
| 585 | if (indio_dev == NULL) { | ||
| 586 | ret = -ENOMEM; | ||
| 587 | goto error_ret; | ||
| 588 | } | ||
| 589 | chip = iio_priv(indio_dev); | ||
| 590 | /* this is only used for device removal purposes */ | ||
| 591 | i2c_set_clientdata(client, indio_dev); | ||
| 592 | |||
| 593 | chip->client = client; | ||
| 594 | |||
| 595 | /* Establish that the iio_dev is a child of the i2c device */ | ||
| 596 | indio_dev->name = id->name; | ||
| 597 | indio_dev->dev.parent = &client->dev; | ||
| 598 | indio_dev->info = &ad774x_info; | ||
| 599 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 600 | |||
| 601 | ret = iio_device_register(indio_dev); | ||
| 602 | if (ret) | ||
| 603 | goto error_free_dev; | ||
| 604 | regdone = 1; | ||
| 605 | |||
| 606 | if (client->irq) { | ||
| 607 | ret = request_threaded_irq(client->irq, | ||
| 608 | NULL, | ||
| 609 | &ad774x_event_handler, | ||
| 610 | IRQF_TRIGGER_FALLING, | ||
| 611 | "ad774x", | ||
| 612 | indio_dev); | ||
| 613 | if (ret) | ||
| 614 | goto error_free_dev; | ||
| 615 | } | ||
| 616 | |||
| 617 | dev_err(&client->dev, "%s capacitive sensor registered, irq: %d\n", id->name, client->irq); | ||
| 618 | |||
| 619 | return 0; | ||
| 620 | |||
| 621 | error_free_dev: | ||
| 622 | if (regdone) | ||
| 623 | free_irq(client->irq, indio_dev); | ||
| 624 | else | ||
| 625 | iio_free_device(indio_dev); | ||
| 626 | error_ret: | ||
| 627 | return ret; | ||
| 628 | } | ||
| 629 | |||
| 630 | static int __devexit ad774x_remove(struct i2c_client *client) | ||
| 631 | { | ||
| 632 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | ||
| 633 | |||
| 634 | if (client->irq) | ||
| 635 | free_irq(client->irq, indio_dev); | ||
| 636 | iio_device_unregister(indio_dev); | ||
| 637 | |||
| 638 | return 0; | ||
| 639 | } | ||
| 640 | |||
| 641 | static const struct i2c_device_id ad774x_id[] = { | ||
| 642 | { "ad7745", 0 }, | ||
| 643 | { "ad7746", 0 }, | ||
| 644 | { "ad7747", 0 }, | ||
| 645 | {} | ||
| 646 | }; | ||
| 647 | |||
| 648 | MODULE_DEVICE_TABLE(i2c, ad774x_id); | ||
| 649 | |||
| 650 | static struct i2c_driver ad774x_driver = { | ||
| 651 | .driver = { | ||
| 652 | .name = "ad774x", | ||
| 653 | }, | ||
| 654 | .probe = ad774x_probe, | ||
| 655 | .remove = __devexit_p(ad774x_remove), | ||
| 656 | .id_table = ad774x_id, | ||
| 657 | }; | ||
| 658 | |||
| 659 | static __init int ad774x_init(void) | ||
| 660 | { | ||
| 661 | return i2c_add_driver(&ad774x_driver); | ||
| 662 | } | ||
| 663 | |||
| 664 | static __exit void ad774x_exit(void) | ||
| 665 | { | ||
| 666 | i2c_del_driver(&ad774x_driver); | ||
| 667 | } | ||
| 668 | |||
| 669 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | ||
| 670 | MODULE_DESCRIPTION("Analog Devices ad7745/6/7 capacitive sensor driver"); | ||
| 671 | MODULE_LICENSE("GPL v2"); | ||
| 672 | |||
| 673 | module_init(ad774x_init); | ||
| 674 | module_exit(ad774x_exit); | ||
diff --git a/drivers/staging/iio/adc/ad7793.c b/drivers/staging/iio/adc/ad7793.c new file mode 100644 index 00000000000..90f6c039d6c --- /dev/null +++ b/drivers/staging/iio/adc/ad7793.c | |||
| @@ -0,0 +1,987 @@ | |||
| 1 | /* | ||
| 2 | * AD7792/AD7793 SPI ADC driver | ||
| 3 | * | ||
| 4 | * Copyright 2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/device.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/sysfs.h> | ||
| 14 | #include <linux/spi/spi.h> | ||
| 15 | #include <linux/regulator/consumer.h> | ||
| 16 | #include <linux/err.h> | ||
| 17 | #include <linux/sched.h> | ||
| 18 | #include <linux/delay.h> | ||
| 19 | |||
| 20 | #include "../iio.h" | ||
| 21 | #include "../sysfs.h" | ||
| 22 | #include "../ring_generic.h" | ||
| 23 | #include "../ring_sw.h" | ||
| 24 | #include "../trigger.h" | ||
| 25 | #include "adc.h" | ||
| 26 | |||
| 27 | #include "ad7793.h" | ||
| 28 | |||
| 29 | /* NOTE: | ||
| 30 | * The AD7792/AD7793 features a dual use data out ready DOUT/RDY output. | ||
| 31 | * In order to avoid contentions on the SPI bus, it's therefore necessary | ||
| 32 | * to use spi bus locking. | ||
| 33 | * | ||
| 34 | * The DOUT/RDY output must also be wired to an interrupt capable GPIO. | ||
| 35 | */ | ||
| 36 | |||
| 37 | struct ad7793_chip_info { | ||
| 38 | struct iio_chan_spec channel[7]; | ||
| 39 | }; | ||
| 40 | |||
| 41 | struct ad7793_state { | ||
| 42 | struct spi_device *spi; | ||
| 43 | struct iio_trigger *trig; | ||
| 44 | const struct ad7793_chip_info *chip_info; | ||
| 45 | struct regulator *reg; | ||
| 46 | struct ad7793_platform_data *pdata; | ||
| 47 | wait_queue_head_t wq_data_avail; | ||
| 48 | bool done; | ||
| 49 | bool irq_dis; | ||
| 50 | u16 int_vref_mv; | ||
| 51 | u16 mode; | ||
| 52 | u16 conf; | ||
| 53 | u32 scale_avail[8][2]; | ||
| 54 | u32 available_scan_masks[7]; | ||
| 55 | /* | ||
| 56 | * DMA (thus cache coherency maintenance) requires the | ||
| 57 | * transfer buffers to live in their own cache lines. | ||
| 58 | */ | ||
| 59 | u8 data[4] ____cacheline_aligned; | ||
| 60 | }; | ||
| 61 | |||
| 62 | enum ad7793_supported_device_ids { | ||
| 63 | ID_AD7792, | ||
| 64 | ID_AD7793, | ||
| 65 | }; | ||
| 66 | |||
| 67 | static int __ad7793_write_reg(struct ad7793_state *st, bool locked, | ||
| 68 | bool cs_change, unsigned char reg, | ||
| 69 | unsigned size, unsigned val) | ||
| 70 | { | ||
| 71 | u8 *data = st->data; | ||
| 72 | struct spi_transfer t = { | ||
| 73 | .tx_buf = data, | ||
| 74 | .len = size + 1, | ||
| 75 | .cs_change = cs_change, | ||
| 76 | }; | ||
| 77 | struct spi_message m; | ||
| 78 | |||
| 79 | data[0] = AD7793_COMM_WRITE | AD7793_COMM_ADDR(reg); | ||
| 80 | |||
| 81 | switch (size) { | ||
| 82 | case 3: | ||
| 83 | data[1] = val >> 16; | ||
| 84 | data[2] = val >> 8; | ||
| 85 | data[3] = val; | ||
| 86 | break; | ||
| 87 | case 2: | ||
| 88 | data[1] = val >> 8; | ||
| 89 | data[2] = val; | ||
| 90 | break; | ||
| 91 | case 1: | ||
| 92 | data[1] = val; | ||
| 93 | break; | ||
| 94 | default: | ||
| 95 | return -EINVAL; | ||
| 96 | } | ||
| 97 | |||
| 98 | spi_message_init(&m); | ||
| 99 | spi_message_add_tail(&t, &m); | ||
| 100 | |||
| 101 | if (locked) | ||
| 102 | return spi_sync_locked(st->spi, &m); | ||
| 103 | else | ||
| 104 | return spi_sync(st->spi, &m); | ||
| 105 | } | ||
| 106 | |||
| 107 | static int ad7793_write_reg(struct ad7793_state *st, | ||
| 108 | unsigned reg, unsigned size, unsigned val) | ||
| 109 | { | ||
| 110 | return __ad7793_write_reg(st, false, false, reg, size, val); | ||
| 111 | } | ||
| 112 | |||
| 113 | static int __ad7793_read_reg(struct ad7793_state *st, bool locked, | ||
| 114 | bool cs_change, unsigned char reg, | ||
| 115 | int *val, unsigned size) | ||
| 116 | { | ||
| 117 | u8 *data = st->data; | ||
| 118 | int ret; | ||
| 119 | struct spi_transfer t[] = { | ||
| 120 | { | ||
| 121 | .tx_buf = data, | ||
| 122 | .len = 1, | ||
| 123 | }, { | ||
| 124 | .rx_buf = data, | ||
| 125 | .len = size, | ||
| 126 | .cs_change = cs_change, | ||
| 127 | }, | ||
| 128 | }; | ||
| 129 | struct spi_message m; | ||
| 130 | |||
| 131 | data[0] = AD7793_COMM_READ | AD7793_COMM_ADDR(reg); | ||
| 132 | |||
| 133 | spi_message_init(&m); | ||
| 134 | spi_message_add_tail(&t[0], &m); | ||
| 135 | spi_message_add_tail(&t[1], &m); | ||
| 136 | |||
| 137 | if (locked) | ||
| 138 | ret = spi_sync_locked(st->spi, &m); | ||
| 139 | else | ||
| 140 | ret = spi_sync(st->spi, &m); | ||
| 141 | |||
| 142 | if (ret < 0) | ||
| 143 | return ret; | ||
| 144 | |||
| 145 | switch (size) { | ||
| 146 | case 3: | ||
| 147 | *val = data[0] << 16 | data[1] << 8 | data[2]; | ||
| 148 | break; | ||
| 149 | case 2: | ||
| 150 | *val = data[0] << 8 | data[1]; | ||
| 151 | break; | ||
| 152 | case 1: | ||
| 153 | *val = data[0]; | ||
| 154 | break; | ||
| 155 | default: | ||
| 156 | return -EINVAL; | ||
| 157 | } | ||
| 158 | |||
| 159 | return 0; | ||
| 160 | } | ||
| 161 | |||
| 162 | static int ad7793_read_reg(struct ad7793_state *st, | ||
| 163 | unsigned reg, int *val, unsigned size) | ||
| 164 | { | ||
| 165 | return __ad7793_read_reg(st, 0, 0, reg, val, size); | ||
| 166 | } | ||
| 167 | |||
| 168 | static int ad7793_read(struct ad7793_state *st, unsigned ch, | ||
| 169 | unsigned len, int *val) | ||
| 170 | { | ||
| 171 | int ret; | ||
| 172 | st->conf = (st->conf & ~AD7793_CONF_CHAN(-1)) | AD7793_CONF_CHAN(ch); | ||
| 173 | st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) | | ||
| 174 | AD7793_MODE_SEL(AD7793_MODE_SINGLE); | ||
| 175 | |||
| 176 | ad7793_write_reg(st, AD7793_REG_CONF, sizeof(st->conf), st->conf); | ||
| 177 | |||
| 178 | spi_bus_lock(st->spi->master); | ||
| 179 | st->done = false; | ||
| 180 | |||
| 181 | ret = __ad7793_write_reg(st, 1, 1, AD7793_REG_MODE, | ||
| 182 | sizeof(st->mode), st->mode); | ||
| 183 | if (ret < 0) | ||
| 184 | goto out; | ||
| 185 | |||
| 186 | st->irq_dis = false; | ||
| 187 | enable_irq(st->spi->irq); | ||
| 188 | wait_event_interruptible(st->wq_data_avail, st->done); | ||
| 189 | |||
| 190 | ret = __ad7793_read_reg(st, 1, 0, AD7793_REG_DATA, val, len); | ||
| 191 | out: | ||
| 192 | spi_bus_unlock(st->spi->master); | ||
| 193 | |||
| 194 | return ret; | ||
| 195 | } | ||
| 196 | |||
| 197 | static int ad7793_calibrate(struct ad7793_state *st, unsigned mode, unsigned ch) | ||
| 198 | { | ||
| 199 | int ret; | ||
| 200 | |||
| 201 | st->conf = (st->conf & ~AD7793_CONF_CHAN(-1)) | AD7793_CONF_CHAN(ch); | ||
| 202 | st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) | AD7793_MODE_SEL(mode); | ||
| 203 | |||
| 204 | ad7793_write_reg(st, AD7793_REG_CONF, sizeof(st->conf), st->conf); | ||
| 205 | |||
| 206 | spi_bus_lock(st->spi->master); | ||
| 207 | st->done = false; | ||
| 208 | |||
| 209 | ret = __ad7793_write_reg(st, 1, 1, AD7793_REG_MODE, | ||
| 210 | sizeof(st->mode), st->mode); | ||
| 211 | if (ret < 0) | ||
| 212 | goto out; | ||
| 213 | |||
| 214 | st->irq_dis = false; | ||
| 215 | enable_irq(st->spi->irq); | ||
| 216 | wait_event_interruptible(st->wq_data_avail, st->done); | ||
| 217 | |||
| 218 | st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) | | ||
| 219 | AD7793_MODE_SEL(AD7793_MODE_IDLE); | ||
| 220 | |||
| 221 | ret = __ad7793_write_reg(st, 1, 0, AD7793_REG_MODE, | ||
| 222 | sizeof(st->mode), st->mode); | ||
| 223 | out: | ||
| 224 | spi_bus_unlock(st->spi->master); | ||
| 225 | |||
| 226 | return ret; | ||
| 227 | } | ||
| 228 | |||
| 229 | static const u8 ad7793_calib_arr[6][2] = { | ||
| 230 | {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN1P_AIN1M}, | ||
| 231 | {AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN1P_AIN1M}, | ||
| 232 | {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN2P_AIN2M}, | ||
| 233 | {AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN2P_AIN2M}, | ||
| 234 | {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN3P_AIN3M}, | ||
| 235 | {AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN3P_AIN3M} | ||
| 236 | }; | ||
| 237 | |||
| 238 | static int ad7793_calibrate_all(struct ad7793_state *st) | ||
| 239 | { | ||
| 240 | int i, ret; | ||
| 241 | |||
| 242 | for (i = 0; i < ARRAY_SIZE(ad7793_calib_arr); i++) { | ||
| 243 | ret = ad7793_calibrate(st, ad7793_calib_arr[i][0], | ||
| 244 | ad7793_calib_arr[i][1]); | ||
| 245 | if (ret) | ||
| 246 | goto out; | ||
| 247 | } | ||
| 248 | |||
| 249 | return 0; | ||
| 250 | out: | ||
| 251 | dev_err(&st->spi->dev, "Calibration failed\n"); | ||
| 252 | return ret; | ||
| 253 | } | ||
| 254 | |||
| 255 | static int ad7793_setup(struct ad7793_state *st) | ||
| 256 | { | ||
| 257 | int i, ret = -1; | ||
| 258 | unsigned long long scale_uv; | ||
| 259 | u32 id; | ||
| 260 | |||
| 261 | /* reset the serial interface */ | ||
| 262 | ret = spi_write(st->spi, (u8 *)&ret, sizeof(ret)); | ||
| 263 | if (ret < 0) | ||
| 264 | goto out; | ||
| 265 | msleep(1); /* Wait for at least 500us */ | ||
| 266 | |||
| 267 | /* write/read test for device presence */ | ||
| 268 | ret = ad7793_read_reg(st, AD7793_REG_ID, &id, 1); | ||
| 269 | if (ret) | ||
| 270 | goto out; | ||
| 271 | |||
| 272 | id &= AD7793_ID_MASK; | ||
| 273 | |||
| 274 | if (!((id == AD7792_ID) || (id == AD7793_ID))) { | ||
| 275 | dev_err(&st->spi->dev, "device ID query failed\n"); | ||
| 276 | goto out; | ||
| 277 | } | ||
| 278 | |||
| 279 | st->mode = (st->pdata->mode & ~AD7793_MODE_SEL(-1)) | | ||
| 280 | AD7793_MODE_SEL(AD7793_MODE_IDLE); | ||
| 281 | st->conf = st->pdata->conf & ~AD7793_CONF_CHAN(-1); | ||
| 282 | |||
| 283 | ret = ad7793_write_reg(st, AD7793_REG_MODE, sizeof(st->mode), st->mode); | ||
| 284 | if (ret) | ||
| 285 | goto out; | ||
| 286 | |||
| 287 | ret = ad7793_write_reg(st, AD7793_REG_CONF, sizeof(st->conf), st->conf); | ||
| 288 | if (ret) | ||
| 289 | goto out; | ||
| 290 | |||
| 291 | ret = ad7793_write_reg(st, AD7793_REG_IO, | ||
| 292 | sizeof(st->pdata->io), st->pdata->io); | ||
| 293 | if (ret) | ||
| 294 | goto out; | ||
| 295 | |||
| 296 | ret = ad7793_calibrate_all(st); | ||
| 297 | if (ret) | ||
| 298 | goto out; | ||
| 299 | |||
| 300 | /* Populate available ADC input ranges */ | ||
| 301 | for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) { | ||
| 302 | scale_uv = ((u64)st->int_vref_mv * 100000000) | ||
| 303 | >> (st->chip_info->channel[0].scan_type.realbits - | ||
| 304 | (!!(st->conf & AD7793_CONF_UNIPOLAR) ? 0 : 1)); | ||
| 305 | scale_uv >>= i; | ||
| 306 | |||
| 307 | st->scale_avail[i][1] = do_div(scale_uv, 100000000) * 10; | ||
| 308 | st->scale_avail[i][0] = scale_uv; | ||
| 309 | } | ||
| 310 | |||
| 311 | return 0; | ||
| 312 | out: | ||
| 313 | dev_err(&st->spi->dev, "setup failed\n"); | ||
| 314 | return ret; | ||
| 315 | } | ||
| 316 | |||
| 317 | static int ad7793_scan_from_ring(struct ad7793_state *st, unsigned ch, int *val) | ||
| 318 | { | ||
| 319 | struct iio_ring_buffer *ring = iio_priv_to_dev(st)->ring; | ||
| 320 | int ret; | ||
| 321 | s64 dat64[2]; | ||
| 322 | u32 *dat32 = (u32 *)dat64; | ||
| 323 | |||
| 324 | if (!(ring->scan_mask & (1 << ch))) | ||
| 325 | return -EBUSY; | ||
| 326 | |||
| 327 | ret = ring->access->read_last(ring, (u8 *) &dat64); | ||
| 328 | if (ret) | ||
| 329 | return ret; | ||
| 330 | |||
| 331 | *val = *dat32; | ||
| 332 | |||
| 333 | return 0; | ||
| 334 | } | ||
| 335 | |||
| 336 | static int ad7793_ring_preenable(struct iio_dev *indio_dev) | ||
| 337 | { | ||
| 338 | struct ad7793_state *st = iio_priv(indio_dev); | ||
| 339 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 340 | size_t d_size; | ||
| 341 | unsigned channel; | ||
| 342 | |||
| 343 | if (!ring->scan_count) | ||
| 344 | return -EINVAL; | ||
| 345 | |||
| 346 | channel = __ffs(ring->scan_mask); | ||
| 347 | |||
| 348 | d_size = ring->scan_count * | ||
| 349 | indio_dev->channels[0].scan_type.storagebits / 8; | ||
| 350 | |||
| 351 | if (ring->scan_timestamp) { | ||
| 352 | d_size += sizeof(s64); | ||
| 353 | |||
| 354 | if (d_size % sizeof(s64)) | ||
| 355 | d_size += sizeof(s64) - (d_size % sizeof(s64)); | ||
| 356 | } | ||
| 357 | |||
| 358 | if (indio_dev->ring->access->set_bytes_per_datum) | ||
| 359 | indio_dev->ring->access->set_bytes_per_datum(indio_dev->ring, | ||
| 360 | d_size); | ||
| 361 | |||
| 362 | st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) | | ||
| 363 | AD7793_MODE_SEL(AD7793_MODE_CONT); | ||
| 364 | st->conf = (st->conf & ~AD7793_CONF_CHAN(-1)) | | ||
| 365 | AD7793_CONF_CHAN(indio_dev->channels[channel].address); | ||
| 366 | |||
| 367 | ad7793_write_reg(st, AD7793_REG_CONF, sizeof(st->conf), st->conf); | ||
| 368 | |||
| 369 | spi_bus_lock(st->spi->master); | ||
| 370 | __ad7793_write_reg(st, 1, 1, AD7793_REG_MODE, | ||
| 371 | sizeof(st->mode), st->mode); | ||
| 372 | |||
| 373 | st->irq_dis = false; | ||
| 374 | enable_irq(st->spi->irq); | ||
| 375 | |||
| 376 | return 0; | ||
| 377 | } | ||
| 378 | |||
| 379 | static int ad7793_ring_postdisable(struct iio_dev *indio_dev) | ||
| 380 | { | ||
| 381 | struct ad7793_state *st = iio_priv(indio_dev); | ||
| 382 | |||
| 383 | st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) | | ||
| 384 | AD7793_MODE_SEL(AD7793_MODE_IDLE); | ||
| 385 | |||
| 386 | st->done = false; | ||
| 387 | wait_event_interruptible(st->wq_data_avail, st->done); | ||
| 388 | |||
| 389 | if (!st->irq_dis) | ||
| 390 | disable_irq_nosync(st->spi->irq); | ||
| 391 | |||
| 392 | __ad7793_write_reg(st, 1, 0, AD7793_REG_MODE, | ||
| 393 | sizeof(st->mode), st->mode); | ||
| 394 | |||
| 395 | return spi_bus_unlock(st->spi->master); | ||
| 396 | } | ||
| 397 | |||
| 398 | /** | ||
| 399 | * ad7793_trigger_handler() bh of trigger launched polling to ring buffer | ||
| 400 | **/ | ||
| 401 | |||
| 402 | static irqreturn_t ad7793_trigger_handler(int irq, void *p) | ||
| 403 | { | ||
| 404 | struct iio_poll_func *pf = p; | ||
| 405 | struct iio_dev *indio_dev = pf->private_data; | ||
| 406 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 407 | struct ad7793_state *st = iio_priv(indio_dev); | ||
| 408 | s64 dat64[2]; | ||
| 409 | s32 *dat32 = (s32 *)dat64; | ||
| 410 | |||
| 411 | if (ring->scan_count) | ||
| 412 | __ad7793_read_reg(st, 1, 1, AD7793_REG_DATA, | ||
| 413 | dat32, | ||
| 414 | indio_dev->channels[0].scan_type.realbits/8); | ||
| 415 | |||
| 416 | /* Guaranteed to be aligned with 8 byte boundary */ | ||
| 417 | if (ring->scan_timestamp) | ||
| 418 | dat64[1] = pf->timestamp; | ||
| 419 | |||
| 420 | ring->access->store_to(ring, (u8 *)dat64, pf->timestamp); | ||
| 421 | |||
| 422 | iio_trigger_notify_done(indio_dev->trig); | ||
| 423 | st->irq_dis = false; | ||
| 424 | enable_irq(st->spi->irq); | ||
| 425 | |||
| 426 | return IRQ_HANDLED; | ||
| 427 | } | ||
| 428 | |||
| 429 | static const struct iio_ring_setup_ops ad7793_ring_setup_ops = { | ||
| 430 | .preenable = &ad7793_ring_preenable, | ||
| 431 | .postenable = &iio_triggered_ring_postenable, | ||
| 432 | .predisable = &iio_triggered_ring_predisable, | ||
| 433 | .postdisable = &ad7793_ring_postdisable, | ||
| 434 | }; | ||
| 435 | |||
| 436 | static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev) | ||
| 437 | { | ||
| 438 | int ret; | ||
| 439 | |||
| 440 | indio_dev->ring = iio_sw_rb_allocate(indio_dev); | ||
| 441 | if (!indio_dev->ring) { | ||
| 442 | ret = -ENOMEM; | ||
| 443 | goto error_ret; | ||
| 444 | } | ||
| 445 | /* Effectively select the ring buffer implementation */ | ||
| 446 | indio_dev->ring->access = &ring_sw_access_funcs; | ||
| 447 | indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, | ||
| 448 | &ad7793_trigger_handler, | ||
| 449 | IRQF_ONESHOT, | ||
| 450 | indio_dev, | ||
| 451 | "ad7793_consumer%d", | ||
| 452 | indio_dev->id); | ||
| 453 | if (indio_dev->pollfunc == NULL) { | ||
| 454 | ret = -ENOMEM; | ||
| 455 | goto error_deallocate_sw_rb; | ||
| 456 | } | ||
| 457 | |||
| 458 | /* Ring buffer functions - here trigger setup related */ | ||
| 459 | indio_dev->ring->setup_ops = &ad7793_ring_setup_ops; | ||
| 460 | |||
| 461 | /* Flag that polled ring buffering is possible */ | ||
| 462 | indio_dev->modes |= INDIO_RING_TRIGGERED; | ||
| 463 | return 0; | ||
| 464 | |||
| 465 | error_deallocate_sw_rb: | ||
| 466 | iio_sw_rb_free(indio_dev->ring); | ||
| 467 | error_ret: | ||
| 468 | return ret; | ||
| 469 | } | ||
| 470 | |||
| 471 | static void ad7793_ring_cleanup(struct iio_dev *indio_dev) | ||
| 472 | { | ||
| 473 | /* ensure that the trigger has been detached */ | ||
| 474 | if (indio_dev->trig) { | ||
| 475 | iio_put_trigger(indio_dev->trig); | ||
| 476 | iio_trigger_dettach_poll_func(indio_dev->trig, | ||
| 477 | indio_dev->pollfunc); | ||
| 478 | } | ||
| 479 | iio_dealloc_pollfunc(indio_dev->pollfunc); | ||
| 480 | iio_sw_rb_free(indio_dev->ring); | ||
| 481 | } | ||
| 482 | |||
| 483 | /** | ||
| 484 | * ad7793_data_rdy_trig_poll() the event handler for the data rdy trig | ||
| 485 | **/ | ||
| 486 | static irqreturn_t ad7793_data_rdy_trig_poll(int irq, void *private) | ||
| 487 | { | ||
| 488 | struct ad7793_state *st = iio_priv(private); | ||
| 489 | |||
| 490 | st->done = true; | ||
| 491 | wake_up_interruptible(&st->wq_data_avail); | ||
| 492 | disable_irq_nosync(irq); | ||
| 493 | st->irq_dis = true; | ||
| 494 | iio_trigger_poll(st->trig, iio_get_time_ns()); | ||
| 495 | |||
| 496 | return IRQ_HANDLED; | ||
| 497 | } | ||
| 498 | |||
| 499 | static int ad7793_probe_trigger(struct iio_dev *indio_dev) | ||
| 500 | { | ||
| 501 | struct ad7793_state *st = iio_priv(indio_dev); | ||
| 502 | int ret; | ||
| 503 | |||
| 504 | st->trig = iio_allocate_trigger("%s-dev%d", | ||
| 505 | spi_get_device_id(st->spi)->name, | ||
| 506 | indio_dev->id); | ||
| 507 | if (st->trig == NULL) { | ||
| 508 | ret = -ENOMEM; | ||
| 509 | goto error_ret; | ||
| 510 | } | ||
| 511 | |||
| 512 | ret = request_irq(st->spi->irq, | ||
| 513 | ad7793_data_rdy_trig_poll, | ||
| 514 | IRQF_TRIGGER_LOW, | ||
| 515 | spi_get_device_id(st->spi)->name, | ||
| 516 | indio_dev); | ||
| 517 | if (ret) | ||
| 518 | goto error_free_trig; | ||
| 519 | |||
| 520 | disable_irq_nosync(st->spi->irq); | ||
| 521 | st->irq_dis = true; | ||
| 522 | st->trig->dev.parent = &st->spi->dev; | ||
| 523 | st->trig->owner = THIS_MODULE; | ||
| 524 | st->trig->private_data = indio_dev; | ||
| 525 | |||
| 526 | ret = iio_trigger_register(st->trig); | ||
| 527 | |||
| 528 | /* select default trigger */ | ||
| 529 | indio_dev->trig = st->trig; | ||
| 530 | if (ret) | ||
| 531 | goto error_free_irq; | ||
| 532 | |||
| 533 | return 0; | ||
| 534 | |||
| 535 | error_free_irq: | ||
| 536 | free_irq(st->spi->irq, indio_dev); | ||
| 537 | error_free_trig: | ||
| 538 | iio_free_trigger(st->trig); | ||
| 539 | error_ret: | ||
| 540 | return ret; | ||
| 541 | } | ||
| 542 | |||
| 543 | static void ad7793_remove_trigger(struct iio_dev *indio_dev) | ||
| 544 | { | ||
| 545 | struct ad7793_state *st = iio_priv(indio_dev); | ||
| 546 | |||
| 547 | iio_trigger_unregister(st->trig); | ||
| 548 | free_irq(st->spi->irq, indio_dev); | ||
| 549 | iio_free_trigger(st->trig); | ||
| 550 | } | ||
| 551 | |||
| 552 | static const u16 sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, 33, 19, | ||
| 553 | 17, 16, 12, 10, 8, 6, 4}; | ||
| 554 | |||
| 555 | static ssize_t ad7793_read_frequency(struct device *dev, | ||
| 556 | struct device_attribute *attr, | ||
| 557 | char *buf) | ||
| 558 | { | ||
| 559 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 560 | struct ad7793_state *st = iio_priv(indio_dev); | ||
| 561 | |||
| 562 | return sprintf(buf, "%d\n", | ||
| 563 | sample_freq_avail[AD7793_MODE_RATE(st->mode)]); | ||
| 564 | } | ||
| 565 | |||
| 566 | static ssize_t ad7793_write_frequency(struct device *dev, | ||
| 567 | struct device_attribute *attr, | ||
| 568 | const char *buf, | ||
| 569 | size_t len) | ||
| 570 | { | ||
| 571 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 572 | struct ad7793_state *st = iio_priv(indio_dev); | ||
| 573 | long lval; | ||
| 574 | int i, ret; | ||
| 575 | |||
| 576 | mutex_lock(&indio_dev->mlock); | ||
| 577 | if (iio_ring_enabled(indio_dev)) { | ||
| 578 | mutex_unlock(&indio_dev->mlock); | ||
| 579 | return -EBUSY; | ||
| 580 | } | ||
| 581 | mutex_unlock(&indio_dev->mlock); | ||
| 582 | |||
| 583 | ret = strict_strtol(buf, 10, &lval); | ||
| 584 | if (ret) | ||
| 585 | return ret; | ||
| 586 | |||
| 587 | ret = -EINVAL; | ||
| 588 | |||
| 589 | for (i = 0; i < ARRAY_SIZE(sample_freq_avail); i++) | ||
| 590 | if (lval == sample_freq_avail[i]) { | ||
| 591 | mutex_lock(&indio_dev->mlock); | ||
| 592 | st->mode &= ~AD7793_MODE_RATE(-1); | ||
| 593 | st->mode |= AD7793_MODE_RATE(i); | ||
| 594 | ad7793_write_reg(st, AD7793_REG_MODE, | ||
| 595 | sizeof(st->mode), st->mode); | ||
| 596 | mutex_unlock(&indio_dev->mlock); | ||
| 597 | ret = 0; | ||
| 598 | } | ||
| 599 | |||
| 600 | return ret ? ret : len; | ||
| 601 | } | ||
| 602 | |||
| 603 | static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, | ||
| 604 | ad7793_read_frequency, | ||
| 605 | ad7793_write_frequency); | ||
| 606 | |||
| 607 | static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( | ||
| 608 | "470 242 123 62 50 39 33 19 17 16 12 10 8 6 4"); | ||
| 609 | |||
| 610 | static ssize_t ad7793_show_scale_available(struct device *dev, | ||
| 611 | struct device_attribute *attr, char *buf) | ||
| 612 | { | ||
| 613 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 614 | struct ad7793_state *st = iio_priv(indio_dev); | ||
| 615 | int i, len = 0; | ||
| 616 | |||
| 617 | for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) | ||
| 618 | len += sprintf(buf + len, "%d.%09u ", st->scale_avail[i][0], | ||
| 619 | st->scale_avail[i][1]); | ||
| 620 | |||
| 621 | len += sprintf(buf + len, "\n"); | ||
| 622 | |||
| 623 | return len; | ||
| 624 | } | ||
| 625 | |||
| 626 | static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available, in-in_scale_available, | ||
| 627 | S_IRUGO, ad7793_show_scale_available, NULL, 0); | ||
| 628 | |||
| 629 | static struct attribute *ad7793_attributes[] = { | ||
| 630 | &iio_dev_attr_sampling_frequency.dev_attr.attr, | ||
| 631 | &iio_const_attr_sampling_frequency_available.dev_attr.attr, | ||
| 632 | &iio_dev_attr_in_m_in_scale_available.dev_attr.attr, | ||
| 633 | NULL | ||
| 634 | }; | ||
| 635 | |||
| 636 | static const struct attribute_group ad7793_attribute_group = { | ||
| 637 | .attrs = ad7793_attributes, | ||
| 638 | }; | ||
| 639 | |||
| 640 | static int ad7793_read_raw(struct iio_dev *indio_dev, | ||
| 641 | struct iio_chan_spec const *chan, | ||
| 642 | int *val, | ||
| 643 | int *val2, | ||
| 644 | long m) | ||
| 645 | { | ||
| 646 | struct ad7793_state *st = iio_priv(indio_dev); | ||
| 647 | int ret, smpl = 0; | ||
| 648 | unsigned long long scale_uv; | ||
| 649 | bool unipolar = !!(st->conf & AD7793_CONF_UNIPOLAR); | ||
| 650 | |||
| 651 | switch (m) { | ||
| 652 | case 0: | ||
| 653 | mutex_lock(&indio_dev->mlock); | ||
| 654 | if (iio_ring_enabled(indio_dev)) | ||
| 655 | ret = ad7793_scan_from_ring(st, | ||
| 656 | chan->scan_index, &smpl); | ||
| 657 | else | ||
| 658 | ret = ad7793_read(st, chan->address, | ||
| 659 | chan->scan_type.realbits / 8, &smpl); | ||
| 660 | mutex_unlock(&indio_dev->mlock); | ||
| 661 | |||
| 662 | if (ret < 0) | ||
| 663 | return ret; | ||
| 664 | |||
| 665 | *val = (smpl >> chan->scan_type.shift) & | ||
| 666 | ((1 << (chan->scan_type.realbits)) - 1); | ||
| 667 | |||
| 668 | if (!unipolar) | ||
| 669 | *val -= (1 << (chan->scan_type.realbits - 1)); | ||
| 670 | |||
| 671 | return IIO_VAL_INT; | ||
| 672 | |||
| 673 | case (1 << IIO_CHAN_INFO_SCALE_SHARED): | ||
| 674 | *val = st->scale_avail[(st->conf >> 8) & 0x7][0]; | ||
| 675 | *val2 = st->scale_avail[(st->conf >> 8) & 0x7][1]; | ||
| 676 | |||
| 677 | return IIO_VAL_INT_PLUS_NANO; | ||
| 678 | |||
| 679 | case (1 << IIO_CHAN_INFO_SCALE_SEPARATE): | ||
| 680 | switch (chan->type) { | ||
| 681 | case IIO_IN: | ||
| 682 | /* 1170mV / 2^23 * 6 */ | ||
| 683 | scale_uv = (1170ULL * 100000000ULL * 6ULL) | ||
| 684 | >> (chan->scan_type.realbits - | ||
| 685 | (unipolar ? 0 : 1)); | ||
| 686 | break; | ||
| 687 | case IIO_TEMP: | ||
| 688 | /* Always uses unity gain and internal ref */ | ||
| 689 | scale_uv = (2500ULL * 100000000ULL) | ||
| 690 | >> (chan->scan_type.realbits - | ||
| 691 | (unipolar ? 0 : 1)); | ||
| 692 | break; | ||
| 693 | default: | ||
| 694 | return -EINVAL; | ||
| 695 | } | ||
| 696 | |||
| 697 | *val2 = do_div(scale_uv, 100000000) * 10; | ||
| 698 | *val = scale_uv; | ||
| 699 | |||
| 700 | return IIO_VAL_INT_PLUS_NANO; | ||
| 701 | } | ||
| 702 | return -EINVAL; | ||
| 703 | } | ||
| 704 | |||
| 705 | static int ad7793_write_raw(struct iio_dev *indio_dev, | ||
| 706 | struct iio_chan_spec const *chan, | ||
| 707 | int val, | ||
| 708 | int val2, | ||
| 709 | long mask) | ||
| 710 | { | ||
| 711 | struct ad7793_state *st = iio_priv(indio_dev); | ||
| 712 | int ret, i; | ||
| 713 | unsigned int tmp; | ||
| 714 | |||
| 715 | mutex_lock(&indio_dev->mlock); | ||
| 716 | if (iio_ring_enabled(indio_dev)) { | ||
| 717 | mutex_unlock(&indio_dev->mlock); | ||
| 718 | return -EBUSY; | ||
| 719 | } | ||
| 720 | |||
| 721 | switch (mask) { | ||
| 722 | case (1 << IIO_CHAN_INFO_SCALE_SHARED): | ||
| 723 | ret = -EINVAL; | ||
| 724 | for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) | ||
| 725 | if (val2 == st->scale_avail[i][1]) { | ||
| 726 | tmp = st->conf; | ||
| 727 | st->conf &= ~AD7793_CONF_GAIN(-1); | ||
| 728 | st->conf |= AD7793_CONF_GAIN(i); | ||
| 729 | |||
| 730 | if (tmp != st->conf) { | ||
| 731 | ad7793_write_reg(st, AD7793_REG_CONF, | ||
| 732 | sizeof(st->conf), | ||
| 733 | st->conf); | ||
| 734 | ad7793_calibrate_all(st); | ||
| 735 | } | ||
| 736 | ret = 0; | ||
| 737 | } | ||
| 738 | |||
| 739 | default: | ||
| 740 | ret = -EINVAL; | ||
| 741 | } | ||
| 742 | |||
| 743 | mutex_unlock(&indio_dev->mlock); | ||
| 744 | return ret; | ||
| 745 | } | ||
| 746 | |||
| 747 | static int ad7793_validate_trigger(struct iio_dev *indio_dev, | ||
| 748 | struct iio_trigger *trig) | ||
| 749 | { | ||
| 750 | if (indio_dev->trig != trig) | ||
| 751 | return -EINVAL; | ||
| 752 | |||
| 753 | return 0; | ||
| 754 | } | ||
| 755 | |||
| 756 | static int ad7793_write_raw_get_fmt(struct iio_dev *indio_dev, | ||
| 757 | struct iio_chan_spec const *chan, | ||
| 758 | long mask) | ||
| 759 | { | ||
| 760 | return IIO_VAL_INT_PLUS_NANO; | ||
| 761 | } | ||
| 762 | |||
| 763 | static const struct iio_info ad7793_info = { | ||
| 764 | .read_raw = &ad7793_read_raw, | ||
| 765 | .write_raw = &ad7793_write_raw, | ||
| 766 | .write_raw_get_fmt = &ad7793_write_raw_get_fmt, | ||
| 767 | .attrs = &ad7793_attribute_group, | ||
| 768 | .validate_trigger = ad7793_validate_trigger, | ||
| 769 | .driver_module = THIS_MODULE, | ||
| 770 | }; | ||
| 771 | |||
| 772 | static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { | ||
| 773 | [ID_AD7793] = { | ||
| 774 | .channel[0] = IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 0, 0, | ||
| 775 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 776 | AD7793_CH_AIN1P_AIN1M, | ||
| 777 | 0, IIO_ST('s', 24, 32, 0), 0), | ||
| 778 | .channel[1] = IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 1, 1, | ||
| 779 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 780 | AD7793_CH_AIN2P_AIN2M, | ||
| 781 | 1, IIO_ST('s', 24, 32, 0), 0), | ||
| 782 | .channel[2] = IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 2, 2, | ||
| 783 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 784 | AD7793_CH_AIN3P_AIN3M, | ||
| 785 | 2, IIO_ST('s', 24, 32, 0), 0), | ||
| 786 | .channel[3] = IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, "shorted", 0, 0, | ||
| 787 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 788 | AD7793_CH_AIN1M_AIN1M, | ||
| 789 | 3, IIO_ST('s', 24, 32, 0), 0), | ||
| 790 | .channel[4] = IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, | ||
| 791 | (1 << IIO_CHAN_INFO_SCALE_SEPARATE), | ||
| 792 | AD7793_CH_TEMP, | ||
| 793 | 4, IIO_ST('s', 24, 32, 0), 0), | ||
| 794 | .channel[5] = IIO_CHAN(IIO_IN, 0, 1, 0, "supply", 4, 0, | ||
| 795 | (1 << IIO_CHAN_INFO_SCALE_SEPARATE), | ||
| 796 | AD7793_CH_AVDD_MONITOR, | ||
| 797 | 5, IIO_ST('s', 24, 32, 0), 0), | ||
| 798 | .channel[6] = IIO_CHAN_SOFT_TIMESTAMP(6), | ||
| 799 | }, | ||
| 800 | [ID_AD7792] = { | ||
| 801 | .channel[0] = IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 0, 0, | ||
| 802 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 803 | AD7793_CH_AIN1P_AIN1M, | ||
| 804 | 0, IIO_ST('s', 16, 32, 0), 0), | ||
| 805 | .channel[1] = IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 1, 1, | ||
| 806 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 807 | AD7793_CH_AIN2P_AIN2M, | ||
| 808 | 1, IIO_ST('s', 16, 32, 0), 0), | ||
| 809 | .channel[2] = IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 2, 2, | ||
| 810 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 811 | AD7793_CH_AIN3P_AIN3M, | ||
| 812 | 2, IIO_ST('s', 16, 32, 0), 0), | ||
| 813 | .channel[3] = IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, "shorted", 0, 0, | ||
| 814 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 815 | AD7793_CH_AIN1M_AIN1M, | ||
| 816 | 3, IIO_ST('s', 16, 32, 0), 0), | ||
| 817 | .channel[4] = IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, | ||
| 818 | (1 << IIO_CHAN_INFO_SCALE_SEPARATE), | ||
| 819 | AD7793_CH_TEMP, | ||
| 820 | 4, IIO_ST('s', 16, 32, 0), 0), | ||
| 821 | .channel[5] = IIO_CHAN(IIO_IN, 0, 1, 0, "supply", 4, 0, | ||
| 822 | (1 << IIO_CHAN_INFO_SCALE_SEPARATE), | ||
| 823 | AD7793_CH_AVDD_MONITOR, | ||
| 824 | 5, IIO_ST('s', 16, 32, 0), 0), | ||
| 825 | .channel[6] = IIO_CHAN_SOFT_TIMESTAMP(6), | ||
| 826 | }, | ||
| 827 | }; | ||
| 828 | |||
| 829 | static int __devinit ad7793_probe(struct spi_device *spi) | ||
| 830 | { | ||
| 831 | struct ad7793_platform_data *pdata = spi->dev.platform_data; | ||
| 832 | struct ad7793_state *st; | ||
| 833 | struct iio_dev *indio_dev; | ||
| 834 | int ret, i, voltage_uv = 0, regdone = 0; | ||
| 835 | |||
| 836 | if (!pdata) { | ||
| 837 | dev_err(&spi->dev, "no platform data?\n"); | ||
| 838 | return -ENODEV; | ||
| 839 | } | ||
| 840 | |||
| 841 | if (!spi->irq) { | ||
| 842 | dev_err(&spi->dev, "no IRQ?\n"); | ||
| 843 | return -ENODEV; | ||
| 844 | } | ||
| 845 | |||
| 846 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
| 847 | if (indio_dev == NULL) | ||
| 848 | return -ENOMEM; | ||
| 849 | |||
| 850 | st = iio_priv(indio_dev); | ||
| 851 | |||
| 852 | st->reg = regulator_get(&spi->dev, "vcc"); | ||
| 853 | if (!IS_ERR(st->reg)) { | ||
| 854 | ret = regulator_enable(st->reg); | ||
| 855 | if (ret) | ||
| 856 | goto error_put_reg; | ||
| 857 | |||
| 858 | voltage_uv = regulator_get_voltage(st->reg); | ||
| 859 | } | ||
| 860 | |||
| 861 | st->chip_info = | ||
| 862 | &ad7793_chip_info_tbl[spi_get_device_id(spi)->driver_data]; | ||
| 863 | |||
| 864 | st->pdata = pdata; | ||
| 865 | |||
| 866 | if (pdata && pdata->vref_mv) | ||
| 867 | st->int_vref_mv = pdata->vref_mv; | ||
| 868 | else if (voltage_uv) | ||
| 869 | st->int_vref_mv = voltage_uv / 1000; | ||
| 870 | else | ||
| 871 | st->int_vref_mv = 2500; /* Build-in ref */ | ||
| 872 | |||
| 873 | spi_set_drvdata(spi, indio_dev); | ||
| 874 | st->spi = spi; | ||
| 875 | |||
| 876 | indio_dev->dev.parent = &spi->dev; | ||
| 877 | indio_dev->name = spi_get_device_id(spi)->name; | ||
| 878 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 879 | indio_dev->channels = st->chip_info->channel; | ||
| 880 | indio_dev->available_scan_masks = st->available_scan_masks; | ||
| 881 | indio_dev->num_channels = 7; | ||
| 882 | indio_dev->info = &ad7793_info; | ||
| 883 | |||
| 884 | for (i = 0; i < indio_dev->num_channels; i++) | ||
| 885 | st->available_scan_masks[i] = (1 << i) | (1 << | ||
| 886 | indio_dev->channels[indio_dev->num_channels - 1]. | ||
| 887 | scan_index); | ||
| 888 | |||
| 889 | init_waitqueue_head(&st->wq_data_avail); | ||
| 890 | |||
| 891 | ret = ad7793_register_ring_funcs_and_init(indio_dev); | ||
| 892 | if (ret) | ||
| 893 | goto error_disable_reg; | ||
| 894 | |||
| 895 | ret = iio_device_register(indio_dev); | ||
| 896 | if (ret) | ||
| 897 | goto error_unreg_ring; | ||
| 898 | regdone = 1; | ||
| 899 | |||
| 900 | ret = ad7793_probe_trigger(indio_dev); | ||
| 901 | if (ret) | ||
| 902 | goto error_unreg_ring; | ||
| 903 | |||
| 904 | ret = iio_ring_buffer_register_ex(indio_dev->ring, 0, | ||
| 905 | indio_dev->channels, | ||
| 906 | indio_dev->num_channels); | ||
| 907 | if (ret) | ||
| 908 | goto error_remove_trigger; | ||
| 909 | |||
| 910 | ret = ad7793_setup(st); | ||
| 911 | if (ret) | ||
| 912 | goto error_uninitialize_ring; | ||
| 913 | |||
| 914 | return 0; | ||
| 915 | |||
| 916 | error_uninitialize_ring: | ||
| 917 | iio_ring_buffer_unregister(indio_dev->ring); | ||
| 918 | error_remove_trigger: | ||
| 919 | ad7793_remove_trigger(indio_dev); | ||
| 920 | error_unreg_ring: | ||
| 921 | ad7793_ring_cleanup(indio_dev); | ||
| 922 | error_disable_reg: | ||
| 923 | if (!IS_ERR(st->reg)) | ||
| 924 | regulator_disable(st->reg); | ||
| 925 | error_put_reg: | ||
| 926 | if (!IS_ERR(st->reg)) | ||
| 927 | regulator_put(st->reg); | ||
| 928 | |||
| 929 | if (regdone) | ||
| 930 | iio_device_unregister(indio_dev); | ||
| 931 | else | ||
| 932 | iio_free_device(indio_dev); | ||
| 933 | |||
| 934 | return ret; | ||
| 935 | } | ||
| 936 | |||
| 937 | static int ad7793_remove(struct spi_device *spi) | ||
| 938 | { | ||
| 939 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 940 | struct ad7793_state *st = iio_priv(indio_dev); | ||
| 941 | |||
| 942 | iio_ring_buffer_unregister(indio_dev->ring); | ||
| 943 | ad7793_remove_trigger(indio_dev); | ||
| 944 | ad7793_ring_cleanup(indio_dev); | ||
| 945 | |||
| 946 | if (!IS_ERR(st->reg)) { | ||
| 947 | regulator_disable(st->reg); | ||
| 948 | regulator_put(st->reg); | ||
| 949 | } | ||
| 950 | |||
| 951 | iio_device_unregister(indio_dev); | ||
| 952 | |||
| 953 | return 0; | ||
| 954 | } | ||
| 955 | |||
| 956 | static const struct spi_device_id ad7793_id[] = { | ||
| 957 | {"ad7792", ID_AD7792}, | ||
| 958 | {"ad7793", ID_AD7793}, | ||
| 959 | {} | ||
| 960 | }; | ||
| 961 | |||
| 962 | static struct spi_driver ad7793_driver = { | ||
| 963 | .driver = { | ||
| 964 | .name = "ad7793", | ||
| 965 | .bus = &spi_bus_type, | ||
| 966 | .owner = THIS_MODULE, | ||
| 967 | }, | ||
| 968 | .probe = ad7793_probe, | ||
| 969 | .remove = __devexit_p(ad7793_remove), | ||
| 970 | .id_table = ad7793_id, | ||
| 971 | }; | ||
| 972 | |||
| 973 | static int __init ad7793_init(void) | ||
| 974 | { | ||
| 975 | return spi_register_driver(&ad7793_driver); | ||
| 976 | } | ||
| 977 | module_init(ad7793_init); | ||
| 978 | |||
| 979 | static void __exit ad7793_exit(void) | ||
| 980 | { | ||
| 981 | spi_unregister_driver(&ad7793_driver); | ||
| 982 | } | ||
| 983 | module_exit(ad7793_exit); | ||
| 984 | |||
| 985 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
| 986 | MODULE_DESCRIPTION("Analog Devices AD7792/3 ADC"); | ||
| 987 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/adc/ad7793.h b/drivers/staging/iio/adc/ad7793.h new file mode 100644 index 00000000000..64f7d41dc45 --- /dev/null +++ b/drivers/staging/iio/adc/ad7793.h | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | /* | ||
| 2 | * AD7792/AD7793 SPI ADC driver | ||
| 3 | * | ||
| 4 | * Copyright 2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | #ifndef IIO_ADC_AD7793_H_ | ||
| 9 | #define IIO_ADC_AD7793_H_ | ||
| 10 | |||
| 11 | /* | ||
| 12 | * TODO: struct ad7793_platform_data needs to go into include/linux/iio | ||
| 13 | */ | ||
| 14 | |||
| 15 | /* Registers */ | ||
| 16 | #define AD7793_REG_COMM 0 /* Communications Register (WO, 8-bit) */ | ||
| 17 | #define AD7793_REG_STAT 0 /* Status Register (RO, 8-bit) */ | ||
| 18 | #define AD7793_REG_MODE 1 /* Mode Register (RW, 16-bit */ | ||
| 19 | #define AD7793_REG_CONF 2 /* Configuration Register (RW, 16-bit) */ | ||
| 20 | #define AD7793_REG_DATA 3 /* Data Register (RO, 16-/24-bit) */ | ||
| 21 | #define AD7793_REG_ID 4 /* ID Register (RO, 8-bit) */ | ||
| 22 | #define AD7793_REG_IO 5 /* IO Register (RO, 8-bit) */ | ||
| 23 | #define AD7793_REG_OFFSET 6 /* Offset Register (RW, 16-bit | ||
| 24 | * (AD7792)/24-bit (AD7793)) */ | ||
| 25 | #define AD7793_REG_FULLSALE 7 /* Full-Scale Register | ||
| 26 | * (RW, 16-bit (AD7792)/24-bit (AD7793)) */ | ||
| 27 | |||
| 28 | /* Communications Register Bit Designations (AD7793_REG_COMM) */ | ||
| 29 | #define AD7793_COMM_WEN (1 << 7) /* Write Enable */ | ||
| 30 | #define AD7793_COMM_WRITE (0 << 6) /* Write Operation */ | ||
| 31 | #define AD7793_COMM_READ (1 << 6) /* Read Operation */ | ||
| 32 | #define AD7793_COMM_ADDR(x) (((x) & 0x7) << 3) /* Register Address */ | ||
| 33 | #define AD7793_COMM_CREAD (1 << 2) /* Continuous Read of Data Register */ | ||
| 34 | |||
| 35 | /* Status Register Bit Designations (AD7793_REG_STAT) */ | ||
| 36 | #define AD7793_STAT_RDY (1 << 7) /* Ready */ | ||
| 37 | #define AD7793_STAT_ERR (1 << 6) /* Error (Overrange, Underrange) */ | ||
| 38 | #define AD7793_STAT_CH3 (1 << 2) /* Channel 3 */ | ||
| 39 | #define AD7793_STAT_CH2 (1 << 1) /* Channel 2 */ | ||
| 40 | #define AD7793_STAT_CH1 (1 << 0) /* Channel 1 */ | ||
| 41 | |||
| 42 | /* Mode Register Bit Designations (AD7793_REG_MODE) */ | ||
| 43 | #define AD7793_MODE_SEL(x) (((x) & 0x7) << 13) /* Operation Mode Select */ | ||
| 44 | #define AD7793_MODE_CLKSRC(x) (((x) & 0x3) << 6) /* ADC Clock Source Select */ | ||
| 45 | #define AD7793_MODE_RATE(x) ((x) & 0xF) /* Filter Update Rate Select */ | ||
| 46 | |||
| 47 | #define AD7793_MODE_CONT 0 /* Continuous Conversion Mode */ | ||
| 48 | #define AD7793_MODE_SINGLE 1 /* Single Conversion Mode */ | ||
| 49 | #define AD7793_MODE_IDLE 2 /* Idle Mode */ | ||
| 50 | #define AD7793_MODE_PWRDN 3 /* Power-Down Mode */ | ||
| 51 | #define AD7793_MODE_CAL_INT_ZERO 4 /* Internal Zero-Scale Calibration */ | ||
| 52 | #define AD7793_MODE_CAL_INT_FULL 5 /* Internal Full-Scale Calibration */ | ||
| 53 | #define AD7793_MODE_CAL_SYS_ZERO 6 /* System Zero-Scale Calibration */ | ||
| 54 | #define AD7793_MODE_CAL_SYS_FULL 7 /* System Full-Scale Calibration */ | ||
| 55 | |||
| 56 | #define AD7793_CLK_INT 0 /* Internal 64 kHz Clock not | ||
| 57 | * available at the CLK pin */ | ||
| 58 | #define AD7793_CLK_INT_CO 1 /* Internal 64 kHz Clock available | ||
| 59 | * at the CLK pin */ | ||
| 60 | #define AD7793_CLK_EXT 2 /* External 64 kHz Clock */ | ||
| 61 | #define AD7793_CLK_EXT_DIV2 3 /* External Clock divided by 2 */ | ||
| 62 | |||
| 63 | /* Configuration Register Bit Designations (AD7793_REG_CONF) */ | ||
| 64 | #define AD7793_CONF_VBIAS(x) (((x) & 0x3) << 14) /* Bias Voltage | ||
| 65 | * Generator Enable */ | ||
| 66 | #define AD7793_CONF_BO_EN (1 << 13) /* Burnout Current Enable */ | ||
| 67 | #define AD7793_CONF_UNIPOLAR (1 << 12) /* Unipolar/Bipolar Enable */ | ||
| 68 | #define AD7793_CONF_BOOST (1 << 11) /* Boost Enable */ | ||
| 69 | #define AD7793_CONF_GAIN(x) (((x) & 0x7) << 8) /* Gain Select */ | ||
| 70 | #define AD7793_CONF_REFSEL (1 << 7) /* INT/EXT Reference Select */ | ||
| 71 | #define AD7793_CONF_BUF (1 << 4) /* Buffered Mode Enable */ | ||
| 72 | #define AD7793_CONF_CHAN(x) ((x) & 0x7) /* Channel select */ | ||
| 73 | |||
| 74 | #define AD7793_CH_AIN1P_AIN1M 0 /* AIN1(+) - AIN1(-) */ | ||
| 75 | #define AD7793_CH_AIN2P_AIN2M 1 /* AIN2(+) - AIN2(-) */ | ||
| 76 | #define AD7793_CH_AIN3P_AIN3M 2 /* AIN3(+) - AIN3(-) */ | ||
| 77 | #define AD7793_CH_AIN1M_AIN1M 3 /* AIN1(-) - AIN1(-) */ | ||
| 78 | #define AD7793_CH_TEMP 6 /* Temp Sensor */ | ||
| 79 | #define AD7793_CH_AVDD_MONITOR 7 /* AVDD Monitor */ | ||
| 80 | |||
| 81 | /* ID Register Bit Designations (AD7793_REG_ID) */ | ||
| 82 | #define AD7792_ID 0xA | ||
| 83 | #define AD7793_ID 0xB | ||
| 84 | #define AD7793_ID_MASK 0xF | ||
| 85 | |||
| 86 | /* IO (Excitation Current Sources) Register Bit Designations (AD7793_REG_IO) */ | ||
| 87 | #define AD7793_IO_IEXC1_IOUT1_IEXC2_IOUT2 0 /* IEXC1 connect to IOUT1, | ||
| 88 | * IEXC2 connect to IOUT2 */ | ||
| 89 | #define AD7793_IO_IEXC1_IOUT2_IEXC2_IOUT1 1 /* IEXC1 connect to IOUT2, | ||
| 90 | * IEXC2 connect to IOUT1 */ | ||
| 91 | #define AD7793_IO_IEXC1_IEXC2_IOUT1 2 /* Both current sources | ||
| 92 | * IEXC1,2 connect to IOUT1 */ | ||
| 93 | #define AD7793_IO_IEXC1_IEXC2_IOUT2 3 /* Both current sources | ||
| 94 | * IEXC1,2 connect to IOUT2 */ | ||
| 95 | |||
| 96 | #define AD7793_IO_IXCEN_10uA (1 << 0) /* Excitation Current 10uA */ | ||
| 97 | #define AD7793_IO_IXCEN_210uA (2 << 0) /* Excitation Current 210uA */ | ||
| 98 | #define AD7793_IO_IXCEN_1mA (3 << 0) /* Excitation Current 1mA */ | ||
| 99 | |||
| 100 | struct ad7793_platform_data { | ||
| 101 | u16 vref_mv; | ||
| 102 | u16 mode; | ||
| 103 | u16 conf; | ||
| 104 | u8 io; | ||
| 105 | }; | ||
| 106 | |||
| 107 | #endif /* IIO_ADC_AD7793_H_ */ | ||
diff --git a/drivers/staging/iio/adc/ad7887.h b/drivers/staging/iio/adc/ad7887.h new file mode 100644 index 00000000000..837046c7b89 --- /dev/null +++ b/drivers/staging/iio/adc/ad7887.h | |||
| @@ -0,0 +1,105 @@ | |||
| 1 | /* | ||
| 2 | * AD7887 SPI ADC driver | ||
| 3 | * | ||
| 4 | * Copyright 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | #ifndef IIO_ADC_AD7887_H_ | ||
| 9 | #define IIO_ADC_AD7887_H_ | ||
| 10 | |||
| 11 | #define AD7887_REF_DIS (1 << 5) /* on-chip reference disable */ | ||
| 12 | #define AD7887_DUAL (1 << 4) /* dual-channel mode */ | ||
| 13 | #define AD7887_CH_AIN1 (1 << 3) /* convert on channel 1, DUAL=1 */ | ||
| 14 | #define AD7887_CH_AIN0 (0 << 3) /* convert on channel 0, DUAL=0,1 */ | ||
| 15 | #define AD7887_PM_MODE1 (0) /* CS based shutdown */ | ||
| 16 | #define AD7887_PM_MODE2 (1) /* full on */ | ||
| 17 | #define AD7887_PM_MODE3 (2) /* auto shutdown after conversion */ | ||
| 18 | #define AD7887_PM_MODE4 (3) /* standby mode */ | ||
| 19 | |||
| 20 | enum ad7887_channels { | ||
| 21 | AD7887_CH0, | ||
| 22 | AD7887_CH0_CH1, | ||
| 23 | AD7887_CH1, | ||
| 24 | }; | ||
| 25 | |||
| 26 | #define RES_MASK(bits) ((1 << (bits)) - 1) /* TODO: move this into a common header */ | ||
| 27 | |||
| 28 | /* | ||
| 29 | * TODO: struct ad7887_platform_data needs to go into include/linux/iio | ||
| 30 | */ | ||
| 31 | |||
| 32 | struct ad7887_platform_data { | ||
| 33 | /* External Vref voltage applied */ | ||
| 34 | u16 vref_mv; | ||
| 35 | /* | ||
| 36 | * AD7887: | ||
| 37 | * In single channel mode en_dual = flase, AIN1/Vref pins assumes its | ||
| 38 | * Vref function. In dual channel mode en_dual = true, AIN1 becomes the | ||
| 39 | * second input channel, and Vref is internally connected to Vdd. | ||
| 40 | */ | ||
| 41 | bool en_dual; | ||
| 42 | /* | ||
| 43 | * AD7887: | ||
| 44 | * use_onchip_ref = true, the Vref is internally connected to the 2.500V | ||
| 45 | * Voltage reference. If use_onchip_ref = false, the reference voltage | ||
| 46 | * is supplied by AIN1/Vref | ||
| 47 | */ | ||
| 48 | bool use_onchip_ref; | ||
| 49 | }; | ||
| 50 | |||
| 51 | /** | ||
| 52 | * struct ad7887_chip_info - chip specifc information | ||
| 53 | * @int_vref_mv: the internal reference voltage | ||
| 54 | * @channel: channel specification | ||
| 55 | */ | ||
| 56 | |||
| 57 | struct ad7887_chip_info { | ||
| 58 | u16 int_vref_mv; | ||
| 59 | struct iio_chan_spec channel[3]; | ||
| 60 | }; | ||
| 61 | |||
| 62 | struct ad7887_state { | ||
| 63 | struct spi_device *spi; | ||
| 64 | const struct ad7887_chip_info *chip_info; | ||
| 65 | struct regulator *reg; | ||
| 66 | size_t d_size; | ||
| 67 | u16 int_vref_mv; | ||
| 68 | struct spi_transfer xfer[4]; | ||
| 69 | struct spi_message msg[3]; | ||
| 70 | struct spi_message *ring_msg; | ||
| 71 | unsigned char tx_cmd_buf[8]; | ||
| 72 | |||
| 73 | /* | ||
| 74 | * DMA (thus cache coherency maintenance) requires the | ||
| 75 | * transfer buffers to live in their own cache lines. | ||
| 76 | */ | ||
| 77 | |||
| 78 | unsigned char data[4] ____cacheline_aligned; | ||
| 79 | }; | ||
| 80 | |||
| 81 | enum ad7887_supported_device_ids { | ||
| 82 | ID_AD7887 | ||
| 83 | }; | ||
| 84 | |||
| 85 | #ifdef CONFIG_IIO_RING_BUFFER | ||
| 86 | int ad7887_scan_from_ring(struct ad7887_state *st, long mask); | ||
| 87 | int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev); | ||
| 88 | void ad7887_ring_cleanup(struct iio_dev *indio_dev); | ||
| 89 | #else /* CONFIG_IIO_RING_BUFFER */ | ||
| 90 | static inline int ad7887_scan_from_ring(struct ad7887_state *st, long mask) | ||
| 91 | { | ||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | static inline int | ||
| 96 | ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev) | ||
| 97 | { | ||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | static inline void ad7887_ring_cleanup(struct iio_dev *indio_dev) | ||
| 102 | { | ||
| 103 | } | ||
| 104 | #endif /* CONFIG_IIO_RING_BUFFER */ | ||
| 105 | #endif /* IIO_ADC_AD7887_H_ */ | ||
diff --git a/drivers/staging/iio/adc/ad7887_core.c b/drivers/staging/iio/adc/ad7887_core.c new file mode 100644 index 00000000000..3d9121e5c37 --- /dev/null +++ b/drivers/staging/iio/adc/ad7887_core.c | |||
| @@ -0,0 +1,266 @@ | |||
| 1 | /* | ||
| 2 | * AD7887 SPI ADC driver | ||
| 3 | * | ||
| 4 | * Copyright 2010-2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/device.h> | ||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/sysfs.h> | ||
| 13 | #include <linux/spi/spi.h> | ||
| 14 | #include <linux/regulator/consumer.h> | ||
| 15 | #include <linux/err.h> | ||
| 16 | |||
| 17 | #include "../iio.h" | ||
| 18 | #include "../sysfs.h" | ||
| 19 | #include "../ring_generic.h" | ||
| 20 | #include "adc.h" | ||
| 21 | |||
| 22 | #include "ad7887.h" | ||
| 23 | |||
| 24 | static int ad7887_scan_direct(struct ad7887_state *st, unsigned ch) | ||
| 25 | { | ||
| 26 | int ret = spi_sync(st->spi, &st->msg[ch]); | ||
| 27 | if (ret) | ||
| 28 | return ret; | ||
| 29 | |||
| 30 | return (st->data[(ch * 2)] << 8) | st->data[(ch * 2) + 1]; | ||
| 31 | } | ||
| 32 | |||
| 33 | static int ad7887_read_raw(struct iio_dev *dev_info, | ||
| 34 | struct iio_chan_spec const *chan, | ||
| 35 | int *val, | ||
| 36 | int *val2, | ||
| 37 | long m) | ||
| 38 | { | ||
| 39 | int ret; | ||
| 40 | struct ad7887_state *st = iio_priv(dev_info); | ||
| 41 | unsigned int scale_uv; | ||
| 42 | |||
| 43 | switch (m) { | ||
| 44 | case 0: | ||
| 45 | mutex_lock(&dev_info->mlock); | ||
| 46 | if (iio_ring_enabled(dev_info)) | ||
| 47 | ret = ad7887_scan_from_ring(st, 1 << chan->address); | ||
| 48 | else | ||
| 49 | ret = ad7887_scan_direct(st, chan->address); | ||
| 50 | mutex_unlock(&dev_info->mlock); | ||
| 51 | |||
| 52 | if (ret < 0) | ||
| 53 | return ret; | ||
| 54 | *val = (ret >> st->chip_info->channel[0].scan_type.shift) & | ||
| 55 | RES_MASK(st->chip_info->channel[0].scan_type.realbits); | ||
| 56 | return IIO_VAL_INT; | ||
| 57 | case (1 << IIO_CHAN_INFO_SCALE_SHARED): | ||
| 58 | scale_uv = (st->int_vref_mv * 1000) | ||
| 59 | >> st->chip_info->channel[0].scan_type.realbits; | ||
| 60 | *val = scale_uv/1000; | ||
| 61 | *val2 = (scale_uv%1000)*1000; | ||
| 62 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 63 | } | ||
| 64 | return -EINVAL; | ||
| 65 | } | ||
| 66 | |||
| 67 | |||
| 68 | static const struct ad7887_chip_info ad7887_chip_info_tbl[] = { | ||
| 69 | /* | ||
| 70 | * More devices added in future | ||
| 71 | */ | ||
| 72 | [ID_AD7887] = { | ||
| 73 | .channel[0] = IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 1, 0, | ||
| 74 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 75 | 1, 1, IIO_ST('u', 12, 16, 0), 0), | ||
| 76 | |||
| 77 | .channel[1] = IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, | ||
| 78 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 79 | 0, 0, IIO_ST('u', 12, 16, 0), 0), | ||
| 80 | |||
| 81 | .channel[2] = IIO_CHAN_SOFT_TIMESTAMP(2), | ||
| 82 | .int_vref_mv = 2500, | ||
| 83 | }, | ||
| 84 | }; | ||
| 85 | |||
| 86 | static const struct iio_info ad7887_info = { | ||
| 87 | .read_raw = &ad7887_read_raw, | ||
| 88 | .driver_module = THIS_MODULE, | ||
| 89 | }; | ||
| 90 | |||
| 91 | static int __devinit ad7887_probe(struct spi_device *spi) | ||
| 92 | { | ||
| 93 | struct ad7887_platform_data *pdata = spi->dev.platform_data; | ||
| 94 | struct ad7887_state *st; | ||
| 95 | int ret, voltage_uv = 0, regdone = 0; | ||
| 96 | struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st)); | ||
| 97 | |||
| 98 | if (indio_dev == NULL) | ||
| 99 | return -ENOMEM; | ||
| 100 | |||
| 101 | st = iio_priv(indio_dev); | ||
| 102 | |||
| 103 | st->reg = regulator_get(&spi->dev, "vcc"); | ||
| 104 | if (!IS_ERR(st->reg)) { | ||
| 105 | ret = regulator_enable(st->reg); | ||
| 106 | if (ret) | ||
| 107 | goto error_put_reg; | ||
| 108 | |||
| 109 | voltage_uv = regulator_get_voltage(st->reg); | ||
| 110 | } | ||
| 111 | |||
| 112 | st->chip_info = | ||
| 113 | &ad7887_chip_info_tbl[spi_get_device_id(spi)->driver_data]; | ||
| 114 | |||
| 115 | spi_set_drvdata(spi, indio_dev); | ||
| 116 | st->spi = spi; | ||
| 117 | |||
| 118 | /* Estabilish that the iio_dev is a child of the spi device */ | ||
| 119 | indio_dev->dev.parent = &spi->dev; | ||
| 120 | indio_dev->name = spi_get_device_id(spi)->name; | ||
| 121 | indio_dev->info = &ad7887_info; | ||
| 122 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 123 | |||
| 124 | /* Setup default message */ | ||
| 125 | |||
| 126 | st->tx_cmd_buf[0] = AD7887_CH_AIN0 | AD7887_PM_MODE4 | | ||
| 127 | ((pdata && pdata->use_onchip_ref) ? | ||
| 128 | 0 : AD7887_REF_DIS); | ||
| 129 | |||
| 130 | st->xfer[0].rx_buf = &st->data[0]; | ||
| 131 | st->xfer[0].tx_buf = &st->tx_cmd_buf[0]; | ||
| 132 | st->xfer[0].len = 2; | ||
| 133 | |||
| 134 | spi_message_init(&st->msg[AD7887_CH0]); | ||
| 135 | spi_message_add_tail(&st->xfer[0], &st->msg[AD7887_CH0]); | ||
| 136 | |||
| 137 | if (pdata && pdata->en_dual) { | ||
| 138 | st->tx_cmd_buf[0] |= AD7887_DUAL | AD7887_REF_DIS; | ||
| 139 | |||
| 140 | st->tx_cmd_buf[2] = AD7887_CH_AIN1 | AD7887_DUAL | | ||
| 141 | AD7887_REF_DIS | AD7887_PM_MODE4; | ||
| 142 | st->tx_cmd_buf[4] = AD7887_CH_AIN0 | AD7887_DUAL | | ||
| 143 | AD7887_REF_DIS | AD7887_PM_MODE4; | ||
| 144 | st->tx_cmd_buf[6] = AD7887_CH_AIN1 | AD7887_DUAL | | ||
| 145 | AD7887_REF_DIS | AD7887_PM_MODE4; | ||
| 146 | |||
| 147 | st->xfer[1].rx_buf = &st->data[0]; | ||
| 148 | st->xfer[1].tx_buf = &st->tx_cmd_buf[2]; | ||
| 149 | st->xfer[1].len = 2; | ||
| 150 | |||
| 151 | st->xfer[2].rx_buf = &st->data[2]; | ||
| 152 | st->xfer[2].tx_buf = &st->tx_cmd_buf[4]; | ||
| 153 | st->xfer[2].len = 2; | ||
| 154 | |||
| 155 | spi_message_init(&st->msg[AD7887_CH0_CH1]); | ||
| 156 | spi_message_add_tail(&st->xfer[1], &st->msg[AD7887_CH0_CH1]); | ||
| 157 | spi_message_add_tail(&st->xfer[2], &st->msg[AD7887_CH0_CH1]); | ||
| 158 | |||
| 159 | st->xfer[3].rx_buf = &st->data[0]; | ||
| 160 | st->xfer[3].tx_buf = &st->tx_cmd_buf[6]; | ||
| 161 | st->xfer[3].len = 2; | ||
| 162 | |||
| 163 | spi_message_init(&st->msg[AD7887_CH1]); | ||
| 164 | spi_message_add_tail(&st->xfer[3], &st->msg[AD7887_CH1]); | ||
| 165 | |||
| 166 | if (pdata && pdata->vref_mv) | ||
| 167 | st->int_vref_mv = pdata->vref_mv; | ||
| 168 | else if (voltage_uv) | ||
| 169 | st->int_vref_mv = voltage_uv / 1000; | ||
| 170 | else | ||
| 171 | dev_warn(&spi->dev, "reference voltage unspecified\n"); | ||
| 172 | |||
| 173 | indio_dev->channels = st->chip_info->channel; | ||
| 174 | indio_dev->num_channels = 3; | ||
| 175 | } else { | ||
| 176 | if (pdata && pdata->vref_mv) | ||
| 177 | st->int_vref_mv = pdata->vref_mv; | ||
| 178 | else if (pdata && pdata->use_onchip_ref) | ||
| 179 | st->int_vref_mv = st->chip_info->int_vref_mv; | ||
| 180 | else | ||
| 181 | dev_warn(&spi->dev, "reference voltage unspecified\n"); | ||
| 182 | |||
| 183 | indio_dev->channels = &st->chip_info->channel[1]; | ||
| 184 | indio_dev->num_channels = 2; | ||
| 185 | } | ||
| 186 | |||
| 187 | ret = ad7887_register_ring_funcs_and_init(indio_dev); | ||
| 188 | if (ret) | ||
| 189 | goto error_disable_reg; | ||
| 190 | |||
| 191 | ret = iio_device_register(indio_dev); | ||
| 192 | if (ret) | ||
| 193 | goto error_disable_reg; | ||
| 194 | regdone = 1; | ||
| 195 | |||
| 196 | ret = iio_ring_buffer_register_ex(indio_dev->ring, 0, | ||
| 197 | indio_dev->channels, | ||
| 198 | indio_dev->num_channels); | ||
| 199 | if (ret) | ||
| 200 | goto error_cleanup_ring; | ||
| 201 | return 0; | ||
| 202 | |||
| 203 | error_cleanup_ring: | ||
| 204 | ad7887_ring_cleanup(indio_dev); | ||
| 205 | error_disable_reg: | ||
| 206 | if (!IS_ERR(st->reg)) | ||
| 207 | regulator_disable(st->reg); | ||
| 208 | error_put_reg: | ||
| 209 | if (!IS_ERR(st->reg)) | ||
| 210 | regulator_put(st->reg); | ||
| 211 | if (regdone) | ||
| 212 | iio_device_unregister(indio_dev); | ||
| 213 | else | ||
| 214 | iio_free_device(indio_dev); | ||
| 215 | |||
| 216 | return ret; | ||
| 217 | } | ||
| 218 | |||
| 219 | static int ad7887_remove(struct spi_device *spi) | ||
| 220 | { | ||
| 221 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 222 | struct ad7887_state *st = iio_priv(indio_dev); | ||
| 223 | |||
| 224 | iio_ring_buffer_unregister(indio_dev->ring); | ||
| 225 | ad7887_ring_cleanup(indio_dev); | ||
| 226 | if (!IS_ERR(st->reg)) { | ||
| 227 | regulator_disable(st->reg); | ||
| 228 | regulator_put(st->reg); | ||
| 229 | } | ||
| 230 | iio_device_unregister(indio_dev); | ||
| 231 | |||
| 232 | return 0; | ||
| 233 | } | ||
| 234 | |||
| 235 | static const struct spi_device_id ad7887_id[] = { | ||
| 236 | {"ad7887", ID_AD7887}, | ||
| 237 | {} | ||
| 238 | }; | ||
| 239 | |||
| 240 | static struct spi_driver ad7887_driver = { | ||
| 241 | .driver = { | ||
| 242 | .name = "ad7887", | ||
| 243 | .bus = &spi_bus_type, | ||
| 244 | .owner = THIS_MODULE, | ||
| 245 | }, | ||
| 246 | .probe = ad7887_probe, | ||
| 247 | .remove = __devexit_p(ad7887_remove), | ||
| 248 | .id_table = ad7887_id, | ||
| 249 | }; | ||
| 250 | |||
| 251 | static int __init ad7887_init(void) | ||
| 252 | { | ||
| 253 | return spi_register_driver(&ad7887_driver); | ||
| 254 | } | ||
| 255 | module_init(ad7887_init); | ||
| 256 | |||
| 257 | static void __exit ad7887_exit(void) | ||
| 258 | { | ||
| 259 | spi_unregister_driver(&ad7887_driver); | ||
| 260 | } | ||
| 261 | module_exit(ad7887_exit); | ||
| 262 | |||
| 263 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
| 264 | MODULE_DESCRIPTION("Analog Devices AD7887 ADC"); | ||
| 265 | MODULE_LICENSE("GPL v2"); | ||
| 266 | MODULE_ALIAS("spi:ad7887"); | ||
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c new file mode 100644 index 00000000000..0ac7c0b9d71 --- /dev/null +++ b/drivers/staging/iio/adc/ad7887_ring.c | |||
| @@ -0,0 +1,202 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2010-2011 Analog Devices Inc. | ||
| 3 | * Copyright (C) 2008 Jonathan Cameron | ||
| 4 | * | ||
| 5 | * Licensed under the GPL-2. | ||
| 6 | * | ||
| 7 | * ad7887_ring.c | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/interrupt.h> | ||
| 11 | #include <linux/device.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/sysfs.h> | ||
| 15 | #include <linux/spi/spi.h> | ||
| 16 | |||
| 17 | #include "../iio.h" | ||
| 18 | #include "../ring_generic.h" | ||
| 19 | #include "../ring_sw.h" | ||
| 20 | #include "../trigger.h" | ||
| 21 | #include "../sysfs.h" | ||
| 22 | |||
| 23 | #include "ad7887.h" | ||
| 24 | |||
| 25 | int ad7887_scan_from_ring(struct ad7887_state *st, long mask) | ||
| 26 | { | ||
| 27 | struct iio_ring_buffer *ring = iio_priv_to_dev(st)->ring; | ||
| 28 | int count = 0, ret; | ||
| 29 | u16 *ring_data; | ||
| 30 | |||
| 31 | if (!(ring->scan_mask & mask)) { | ||
| 32 | ret = -EBUSY; | ||
| 33 | goto error_ret; | ||
| 34 | } | ||
| 35 | |||
| 36 | ring_data = kmalloc(ring->access->get_bytes_per_datum(ring), | ||
| 37 | GFP_KERNEL); | ||
| 38 | if (ring_data == NULL) { | ||
| 39 | ret = -ENOMEM; | ||
| 40 | goto error_ret; | ||
| 41 | } | ||
| 42 | ret = ring->access->read_last(ring, (u8 *) ring_data); | ||
| 43 | if (ret) | ||
| 44 | goto error_free_ring_data; | ||
| 45 | |||
| 46 | /* for single channel scan the result is stored with zero offset */ | ||
| 47 | if ((ring->scan_mask == ((1 << 1) | (1 << 0))) && (mask == (1 << 1))) | ||
| 48 | count = 1; | ||
| 49 | |||
| 50 | ret = be16_to_cpu(ring_data[count]); | ||
| 51 | |||
| 52 | error_free_ring_data: | ||
| 53 | kfree(ring_data); | ||
| 54 | error_ret: | ||
| 55 | return ret; | ||
| 56 | } | ||
| 57 | |||
| 58 | /** | ||
| 59 | * ad7887_ring_preenable() setup the parameters of the ring before enabling | ||
| 60 | * | ||
| 61 | * The complex nature of the setting of the nuber of bytes per datum is due | ||
| 62 | * to this driver currently ensuring that the timestamp is stored at an 8 | ||
| 63 | * byte boundary. | ||
| 64 | **/ | ||
| 65 | static int ad7887_ring_preenable(struct iio_dev *indio_dev) | ||
| 66 | { | ||
| 67 | struct ad7887_state *st = iio_priv(indio_dev); | ||
| 68 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 69 | |||
| 70 | st->d_size = ring->scan_count * | ||
| 71 | st->chip_info->channel[0].scan_type.storagebits / 8; | ||
| 72 | |||
| 73 | if (ring->scan_timestamp) { | ||
| 74 | st->d_size += sizeof(s64); | ||
| 75 | |||
| 76 | if (st->d_size % sizeof(s64)) | ||
| 77 | st->d_size += sizeof(s64) - (st->d_size % sizeof(s64)); | ||
| 78 | } | ||
| 79 | |||
| 80 | if (indio_dev->ring->access->set_bytes_per_datum) | ||
| 81 | indio_dev->ring->access->set_bytes_per_datum(indio_dev->ring, | ||
| 82 | st->d_size); | ||
| 83 | |||
| 84 | switch (ring->scan_mask) { | ||
| 85 | case (1 << 0): | ||
| 86 | st->ring_msg = &st->msg[AD7887_CH0]; | ||
| 87 | break; | ||
| 88 | case (1 << 1): | ||
| 89 | st->ring_msg = &st->msg[AD7887_CH1]; | ||
| 90 | /* Dummy read: push CH1 setting down to hardware */ | ||
| 91 | spi_sync(st->spi, st->ring_msg); | ||
| 92 | break; | ||
| 93 | case ((1 << 1) | (1 << 0)): | ||
| 94 | st->ring_msg = &st->msg[AD7887_CH0_CH1]; | ||
| 95 | break; | ||
| 96 | } | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | static int ad7887_ring_postdisable(struct iio_dev *indio_dev) | ||
| 102 | { | ||
| 103 | struct ad7887_state *st = iio_priv(indio_dev); | ||
| 104 | |||
| 105 | /* dummy read: restore default CH0 settin */ | ||
| 106 | return spi_sync(st->spi, &st->msg[AD7887_CH0]); | ||
| 107 | } | ||
| 108 | |||
| 109 | /** | ||
| 110 | * ad7887_trigger_handler() bh of trigger launched polling to ring buffer | ||
| 111 | * | ||
| 112 | * Currently there is no option in this driver to disable the saving of | ||
| 113 | * timestamps within the ring. | ||
| 114 | **/ | ||
| 115 | static irqreturn_t ad7887_trigger_handler(int irq, void *p) | ||
| 116 | { | ||
| 117 | struct iio_poll_func *pf = p; | ||
| 118 | struct iio_dev *indio_dev = pf->private_data; | ||
| 119 | struct ad7887_state *st = iio_priv(indio_dev); | ||
| 120 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 121 | s64 time_ns; | ||
| 122 | __u8 *buf; | ||
| 123 | int b_sent; | ||
| 124 | |||
| 125 | unsigned int bytes = ring->scan_count * | ||
| 126 | st->chip_info->channel[0].scan_type.storagebits / 8; | ||
| 127 | |||
| 128 | buf = kzalloc(st->d_size, GFP_KERNEL); | ||
| 129 | if (buf == NULL) | ||
| 130 | return -ENOMEM; | ||
| 131 | |||
| 132 | b_sent = spi_sync(st->spi, st->ring_msg); | ||
| 133 | if (b_sent) | ||
| 134 | goto done; | ||
| 135 | |||
| 136 | time_ns = iio_get_time_ns(); | ||
| 137 | |||
| 138 | memcpy(buf, st->data, bytes); | ||
| 139 | if (ring->scan_timestamp) | ||
| 140 | memcpy(buf + st->d_size - sizeof(s64), | ||
| 141 | &time_ns, sizeof(time_ns)); | ||
| 142 | |||
| 143 | indio_dev->ring->access->store_to(indio_dev->ring, buf, time_ns); | ||
| 144 | done: | ||
| 145 | kfree(buf); | ||
| 146 | iio_trigger_notify_done(indio_dev->trig); | ||
| 147 | |||
| 148 | return IRQ_HANDLED; | ||
| 149 | } | ||
| 150 | |||
| 151 | static const struct iio_ring_setup_ops ad7887_ring_setup_ops = { | ||
| 152 | .preenable = &ad7887_ring_preenable, | ||
| 153 | .postenable = &iio_triggered_ring_postenable, | ||
| 154 | .predisable = &iio_triggered_ring_predisable, | ||
| 155 | .postdisable = &ad7887_ring_postdisable, | ||
| 156 | }; | ||
| 157 | |||
| 158 | int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev) | ||
| 159 | { | ||
| 160 | int ret; | ||
| 161 | |||
| 162 | indio_dev->ring = iio_sw_rb_allocate(indio_dev); | ||
| 163 | if (!indio_dev->ring) { | ||
| 164 | ret = -ENOMEM; | ||
| 165 | goto error_ret; | ||
| 166 | } | ||
| 167 | /* Effectively select the ring buffer implementation */ | ||
| 168 | indio_dev->ring->access = &ring_sw_access_funcs; | ||
| 169 | indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, | ||
| 170 | &ad7887_trigger_handler, | ||
| 171 | IRQF_ONESHOT, | ||
| 172 | indio_dev, | ||
| 173 | "ad7887_consumer%d", | ||
| 174 | indio_dev->id); | ||
| 175 | if (indio_dev->pollfunc == NULL) { | ||
| 176 | ret = -ENOMEM; | ||
| 177 | goto error_deallocate_sw_rb; | ||
| 178 | } | ||
| 179 | /* Ring buffer functions - here trigger setup related */ | ||
| 180 | indio_dev->ring->setup_ops = &ad7887_ring_setup_ops; | ||
| 181 | |||
| 182 | /* Flag that polled ring buffering is possible */ | ||
| 183 | indio_dev->modes |= INDIO_RING_TRIGGERED; | ||
| 184 | return 0; | ||
| 185 | |||
| 186 | error_deallocate_sw_rb: | ||
| 187 | iio_sw_rb_free(indio_dev->ring); | ||
| 188 | error_ret: | ||
| 189 | return ret; | ||
| 190 | } | ||
| 191 | |||
| 192 | void ad7887_ring_cleanup(struct iio_dev *indio_dev) | ||
| 193 | { | ||
| 194 | /* ensure that the trigger has been detached */ | ||
| 195 | if (indio_dev->trig) { | ||
| 196 | iio_put_trigger(indio_dev->trig); | ||
| 197 | iio_trigger_dettach_poll_func(indio_dev->trig, | ||
| 198 | indio_dev->pollfunc); | ||
| 199 | } | ||
| 200 | iio_dealloc_pollfunc(indio_dev->pollfunc); | ||
| 201 | iio_sw_rb_free(indio_dev->ring); | ||
| 202 | } | ||
diff --git a/drivers/staging/iio/adc/adc.h b/drivers/staging/iio/adc/adc.h new file mode 100644 index 00000000000..40c5949880b --- /dev/null +++ b/drivers/staging/iio/adc/adc.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | /* | ||
| 2 | * adc.h - sysfs attributes associated with ADCs | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms of the GNU General Public License version 2 as published by | ||
| 6 | * the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * Copyright (c) 2008 Jonathan Cameron <jic23@cam.ac.uk> | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | |||
| 12 | /* Deprecated */ | ||
| 13 | #define IIO_DEV_ATTR_ADC(_num, _show, _addr) \ | ||
| 14 | IIO_DEVICE_ATTR(adc_##_num, S_IRUGO, _show, NULL, _addr) | ||
| 15 | |||
| 16 | #define IIO_DEV_ATTR_IN_RAW(_num, _show, _addr) \ | ||
| 17 | IIO_DEVICE_ATTR(in##_num##_raw, S_IRUGO, _show, NULL, _addr) | ||
| 18 | |||
| 19 | #define IIO_DEV_ATTR_IN_NAMED_RAW(_num, _name, _show, _addr) \ | ||
| 20 | IIO_DEVICE_ATTR(in##_num##_##_name##_raw, S_IRUGO, _show, NULL, _addr) | ||
| 21 | |||
| 22 | #define IIO_DEV_ATTR_IN_DIFF_RAW(_nump, _numn, _show, _addr) \ | ||
| 23 | IIO_DEVICE_ATTR_NAMED(in##_nump##min##_numn##_raw, \ | ||
| 24 | in##_nump-in##_numn##_raw, \ | ||
| 25 | S_IRUGO, \ | ||
| 26 | _show, \ | ||
| 27 | NULL, \ | ||
| 28 | _addr) | ||
| 29 | |||
| 30 | |||
| 31 | #define IIO_CONST_ATTR_IN_NAMED_OFFSET(_num, _name, _string) \ | ||
| 32 | IIO_CONST_ATTR(in##_num##_##_name##_offset, _string) | ||
| 33 | |||
| 34 | #define IIO_CONST_ATTR_IN_NAMED_SCALE(_num, _name, _string) \ | ||
| 35 | IIO_CONST_ATTR(in##_num##_##_name##_scale, _string) | ||
| 36 | |||
| 37 | #define IIO_EVENT_CODE_IN_HIGH_THRESH(a) \ | ||
| 38 | IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_IN, a, IIO_EV_TYPE_THRESH, \ | ||
| 39 | IIO_EV_DIR_RISING) | ||
| 40 | #define IIO_EVENT_CODE_IN_LOW_THRESH(a) \ | ||
| 41 | IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_IN, a, IIO_EV_TYPE_THRESH, \ | ||
| 42 | IIO_EV_DIR_FALLING) | ||
diff --git a/drivers/staging/iio/adc/adt7310.c b/drivers/staging/iio/adc/adt7310.c new file mode 100644 index 00000000000..1a41b803440 --- /dev/null +++ b/drivers/staging/iio/adc/adt7310.c | |||
| @@ -0,0 +1,904 @@ | |||
| 1 | /* | ||
| 2 | * ADT7310 digital temperature sensor driver supporting ADT7310 | ||
| 3 | * | ||
| 4 | * Copyright 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/device.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/sysfs.h> | ||
| 14 | #include <linux/list.h> | ||
| 15 | #include <linux/spi/spi.h> | ||
| 16 | |||
| 17 | #include "../iio.h" | ||
| 18 | #include "../sysfs.h" | ||
| 19 | |||
| 20 | /* | ||
| 21 | * ADT7310 registers definition | ||
| 22 | */ | ||
| 23 | |||
| 24 | #define ADT7310_STATUS 0 | ||
| 25 | #define ADT7310_CONFIG 1 | ||
| 26 | #define ADT7310_TEMPERATURE 2 | ||
| 27 | #define ADT7310_ID 3 | ||
| 28 | #define ADT7310_T_CRIT 4 | ||
| 29 | #define ADT7310_T_HYST 5 | ||
| 30 | #define ADT7310_T_ALARM_HIGH 6 | ||
| 31 | #define ADT7310_T_ALARM_LOW 7 | ||
| 32 | |||
| 33 | /* | ||
| 34 | * ADT7310 status | ||
| 35 | */ | ||
| 36 | #define ADT7310_STAT_T_LOW 0x10 | ||
| 37 | #define ADT7310_STAT_T_HIGH 0x20 | ||
| 38 | #define ADT7310_STAT_T_CRIT 0x40 | ||
| 39 | #define ADT7310_STAT_NOT_RDY 0x80 | ||
| 40 | |||
| 41 | /* | ||
| 42 | * ADT7310 config | ||
| 43 | */ | ||
| 44 | #define ADT7310_FAULT_QUEUE_MASK 0x3 | ||
| 45 | #define ADT7310_CT_POLARITY 0x4 | ||
| 46 | #define ADT7310_INT_POLARITY 0x8 | ||
| 47 | #define ADT7310_EVENT_MODE 0x10 | ||
| 48 | #define ADT7310_MODE_MASK 0x60 | ||
| 49 | #define ADT7310_ONESHOT 0x20 | ||
| 50 | #define ADT7310_SPS 0x40 | ||
| 51 | #define ADT7310_PD 0x60 | ||
| 52 | #define ADT7310_RESOLUTION 0x80 | ||
| 53 | |||
| 54 | /* | ||
| 55 | * ADT7310 masks | ||
| 56 | */ | ||
| 57 | #define ADT7310_T16_VALUE_SIGN 0x8000 | ||
| 58 | #define ADT7310_T16_VALUE_FLOAT_OFFSET 7 | ||
| 59 | #define ADT7310_T16_VALUE_FLOAT_MASK 0x7F | ||
| 60 | #define ADT7310_T13_VALUE_SIGN 0x1000 | ||
| 61 | #define ADT7310_T13_VALUE_OFFSET 3 | ||
| 62 | #define ADT7310_T13_VALUE_FLOAT_OFFSET 4 | ||
| 63 | #define ADT7310_T13_VALUE_FLOAT_MASK 0xF | ||
| 64 | #define ADT7310_T_HYST_MASK 0xF | ||
| 65 | #define ADT7310_DEVICE_ID_MASK 0x7 | ||
| 66 | #define ADT7310_MANUFACTORY_ID_MASK 0xF8 | ||
| 67 | #define ADT7310_MANUFACTORY_ID_OFFSET 3 | ||
| 68 | |||
| 69 | |||
| 70 | #define ADT7310_CMD_REG_MASK 0x28 | ||
| 71 | #define ADT7310_CMD_REG_OFFSET 3 | ||
| 72 | #define ADT7310_CMD_READ 0x40 | ||
| 73 | #define ADT7310_CMD_CON_READ 0x4 | ||
| 74 | |||
| 75 | #define ADT7310_IRQS 2 | ||
| 76 | |||
| 77 | /* | ||
| 78 | * struct adt7310_chip_info - chip specifc information | ||
| 79 | */ | ||
| 80 | |||
| 81 | struct adt7310_chip_info { | ||
| 82 | struct spi_device *spi_dev; | ||
| 83 | u8 config; | ||
| 84 | }; | ||
| 85 | |||
| 86 | /* | ||
| 87 | * adt7310 register access by SPI | ||
| 88 | */ | ||
| 89 | |||
| 90 | static int adt7310_spi_read_word(struct adt7310_chip_info *chip, u8 reg, u16 *data) | ||
| 91 | { | ||
| 92 | struct spi_device *spi_dev = chip->spi_dev; | ||
| 93 | u8 command = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK; | ||
| 94 | int ret = 0; | ||
| 95 | |||
| 96 | command |= ADT7310_CMD_READ; | ||
| 97 | ret = spi_write(spi_dev, &command, sizeof(command)); | ||
| 98 | if (ret < 0) { | ||
| 99 | dev_err(&spi_dev->dev, "SPI write command error\n"); | ||
| 100 | return ret; | ||
| 101 | } | ||
| 102 | |||
| 103 | ret = spi_read(spi_dev, (u8 *)data, sizeof(*data)); | ||
| 104 | if (ret < 0) { | ||
| 105 | dev_err(&spi_dev->dev, "SPI read word error\n"); | ||
| 106 | return ret; | ||
| 107 | } | ||
| 108 | |||
| 109 | *data = be16_to_cpu(*data); | ||
| 110 | |||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int adt7310_spi_write_word(struct adt7310_chip_info *chip, u8 reg, u16 data) | ||
| 115 | { | ||
| 116 | struct spi_device *spi_dev = chip->spi_dev; | ||
| 117 | u8 buf[3]; | ||
| 118 | int ret = 0; | ||
| 119 | |||
| 120 | buf[0] = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK; | ||
| 121 | buf[1] = (u8)(data >> 8); | ||
| 122 | buf[2] = (u8)(data & 0xFF); | ||
| 123 | |||
| 124 | ret = spi_write(spi_dev, buf, 3); | ||
| 125 | if (ret < 0) { | ||
| 126 | dev_err(&spi_dev->dev, "SPI write word error\n"); | ||
| 127 | return ret; | ||
| 128 | } | ||
| 129 | |||
| 130 | return ret; | ||
| 131 | } | ||
| 132 | |||
| 133 | static int adt7310_spi_read_byte(struct adt7310_chip_info *chip, u8 reg, u8 *data) | ||
| 134 | { | ||
| 135 | struct spi_device *spi_dev = chip->spi_dev; | ||
| 136 | u8 command = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK; | ||
| 137 | int ret = 0; | ||
| 138 | |||
| 139 | command |= ADT7310_CMD_READ; | ||
| 140 | ret = spi_write(spi_dev, &command, sizeof(command)); | ||
| 141 | if (ret < 0) { | ||
| 142 | dev_err(&spi_dev->dev, "SPI write command error\n"); | ||
| 143 | return ret; | ||
| 144 | } | ||
| 145 | |||
| 146 | ret = spi_read(spi_dev, data, sizeof(*data)); | ||
| 147 | if (ret < 0) { | ||
| 148 | dev_err(&spi_dev->dev, "SPI read byte error\n"); | ||
| 149 | return ret; | ||
| 150 | } | ||
| 151 | |||
| 152 | return 0; | ||
| 153 | } | ||
| 154 | |||
| 155 | static int adt7310_spi_write_byte(struct adt7310_chip_info *chip, u8 reg, u8 data) | ||
| 156 | { | ||
| 157 | struct spi_device *spi_dev = chip->spi_dev; | ||
| 158 | u8 buf[2]; | ||
| 159 | int ret = 0; | ||
| 160 | |||
| 161 | buf[0] = (reg << ADT7310_CMD_REG_OFFSET) & ADT7310_CMD_REG_MASK; | ||
| 162 | buf[1] = data; | ||
| 163 | |||
| 164 | ret = spi_write(spi_dev, buf, 2); | ||
| 165 | if (ret < 0) { | ||
| 166 | dev_err(&spi_dev->dev, "SPI write byte error\n"); | ||
| 167 | return ret; | ||
| 168 | } | ||
| 169 | |||
| 170 | return ret; | ||
| 171 | } | ||
| 172 | |||
| 173 | static ssize_t adt7310_show_mode(struct device *dev, | ||
| 174 | struct device_attribute *attr, | ||
| 175 | char *buf) | ||
| 176 | { | ||
| 177 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 178 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 179 | u8 config; | ||
| 180 | |||
| 181 | config = chip->config & ADT7310_MODE_MASK; | ||
| 182 | |||
| 183 | switch (config) { | ||
| 184 | case ADT7310_PD: | ||
| 185 | return sprintf(buf, "power-down\n"); | ||
| 186 | case ADT7310_ONESHOT: | ||
| 187 | return sprintf(buf, "one-shot\n"); | ||
| 188 | case ADT7310_SPS: | ||
| 189 | return sprintf(buf, "sps\n"); | ||
| 190 | default: | ||
| 191 | return sprintf(buf, "full\n"); | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | static ssize_t adt7310_store_mode(struct device *dev, | ||
| 196 | struct device_attribute *attr, | ||
| 197 | const char *buf, | ||
| 198 | size_t len) | ||
| 199 | { | ||
| 200 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 201 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 202 | u16 config; | ||
| 203 | int ret; | ||
| 204 | |||
| 205 | ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); | ||
| 206 | if (ret) | ||
| 207 | return -EIO; | ||
| 208 | |||
| 209 | config = chip->config & (~ADT7310_MODE_MASK); | ||
| 210 | if (strcmp(buf, "power-down")) | ||
| 211 | config |= ADT7310_PD; | ||
| 212 | else if (strcmp(buf, "one-shot")) | ||
| 213 | config |= ADT7310_ONESHOT; | ||
| 214 | else if (strcmp(buf, "sps")) | ||
| 215 | config |= ADT7310_SPS; | ||
| 216 | |||
| 217 | ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config); | ||
| 218 | if (ret) | ||
| 219 | return -EIO; | ||
| 220 | |||
| 221 | chip->config = config; | ||
| 222 | |||
| 223 | return len; | ||
| 224 | } | ||
| 225 | |||
| 226 | static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, | ||
| 227 | adt7310_show_mode, | ||
| 228 | adt7310_store_mode, | ||
| 229 | 0); | ||
| 230 | |||
| 231 | static ssize_t adt7310_show_available_modes(struct device *dev, | ||
| 232 | struct device_attribute *attr, | ||
| 233 | char *buf) | ||
| 234 | { | ||
| 235 | return sprintf(buf, "full\none-shot\nsps\npower-down\n"); | ||
| 236 | } | ||
| 237 | |||
| 238 | static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt7310_show_available_modes, NULL, 0); | ||
| 239 | |||
| 240 | static ssize_t adt7310_show_resolution(struct device *dev, | ||
| 241 | struct device_attribute *attr, | ||
| 242 | char *buf) | ||
| 243 | { | ||
| 244 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 245 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 246 | int ret; | ||
| 247 | int bits; | ||
| 248 | |||
| 249 | ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); | ||
| 250 | if (ret) | ||
| 251 | return -EIO; | ||
| 252 | |||
| 253 | if (chip->config & ADT7310_RESOLUTION) | ||
| 254 | bits = 16; | ||
| 255 | else | ||
| 256 | bits = 13; | ||
| 257 | |||
| 258 | return sprintf(buf, "%d bits\n", bits); | ||
| 259 | } | ||
| 260 | |||
| 261 | static ssize_t adt7310_store_resolution(struct device *dev, | ||
| 262 | struct device_attribute *attr, | ||
| 263 | const char *buf, | ||
| 264 | size_t len) | ||
| 265 | { | ||
| 266 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 267 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 268 | unsigned long data; | ||
| 269 | u16 config; | ||
| 270 | int ret; | ||
| 271 | |||
| 272 | ret = strict_strtoul(buf, 10, &data); | ||
| 273 | if (ret) | ||
| 274 | return -EINVAL; | ||
| 275 | |||
| 276 | ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); | ||
| 277 | if (ret) | ||
| 278 | return -EIO; | ||
| 279 | |||
| 280 | config = chip->config & (~ADT7310_RESOLUTION); | ||
| 281 | if (data) | ||
| 282 | config |= ADT7310_RESOLUTION; | ||
| 283 | |||
| 284 | ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config); | ||
| 285 | if (ret) | ||
| 286 | return -EIO; | ||
| 287 | |||
| 288 | chip->config = config; | ||
| 289 | |||
| 290 | return len; | ||
| 291 | } | ||
| 292 | |||
| 293 | static IIO_DEVICE_ATTR(resolution, S_IRUGO | S_IWUSR, | ||
| 294 | adt7310_show_resolution, | ||
| 295 | adt7310_store_resolution, | ||
| 296 | 0); | ||
| 297 | |||
| 298 | static ssize_t adt7310_show_id(struct device *dev, | ||
| 299 | struct device_attribute *attr, | ||
| 300 | char *buf) | ||
| 301 | { | ||
| 302 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 303 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 304 | u8 id; | ||
| 305 | int ret; | ||
| 306 | |||
| 307 | ret = adt7310_spi_read_byte(chip, ADT7310_ID, &id); | ||
| 308 | if (ret) | ||
| 309 | return -EIO; | ||
| 310 | |||
| 311 | return sprintf(buf, "device id: 0x%x\nmanufactory id: 0x%x\n", | ||
| 312 | id & ADT7310_DEVICE_ID_MASK, | ||
| 313 | (id & ADT7310_MANUFACTORY_ID_MASK) >> ADT7310_MANUFACTORY_ID_OFFSET); | ||
| 314 | } | ||
| 315 | |||
| 316 | static IIO_DEVICE_ATTR(id, S_IRUGO | S_IWUSR, | ||
| 317 | adt7310_show_id, | ||
| 318 | NULL, | ||
| 319 | 0); | ||
| 320 | |||
| 321 | static ssize_t adt7310_convert_temperature(struct adt7310_chip_info *chip, | ||
| 322 | u16 data, char *buf) | ||
| 323 | { | ||
| 324 | char sign = ' '; | ||
| 325 | |||
| 326 | if (chip->config & ADT7310_RESOLUTION) { | ||
| 327 | if (data & ADT7310_T16_VALUE_SIGN) { | ||
| 328 | /* convert supplement to positive value */ | ||
| 329 | data = (u16)((ADT7310_T16_VALUE_SIGN << 1) - (u32)data); | ||
| 330 | sign = '-'; | ||
| 331 | } | ||
| 332 | return sprintf(buf, "%c%d.%.7d\n", sign, | ||
| 333 | (data >> ADT7310_T16_VALUE_FLOAT_OFFSET), | ||
| 334 | (data & ADT7310_T16_VALUE_FLOAT_MASK) * 78125); | ||
| 335 | } else { | ||
| 336 | if (data & ADT7310_T13_VALUE_SIGN) { | ||
| 337 | /* convert supplement to positive value */ | ||
| 338 | data >>= ADT7310_T13_VALUE_OFFSET; | ||
| 339 | data = (ADT7310_T13_VALUE_SIGN << 1) - data; | ||
| 340 | sign = '-'; | ||
| 341 | } | ||
| 342 | return sprintf(buf, "%c%d.%.4d\n", sign, | ||
| 343 | (data >> ADT7310_T13_VALUE_FLOAT_OFFSET), | ||
| 344 | (data & ADT7310_T13_VALUE_FLOAT_MASK) * 625); | ||
| 345 | } | ||
| 346 | } | ||
| 347 | |||
| 348 | static ssize_t adt7310_show_value(struct device *dev, | ||
| 349 | struct device_attribute *attr, | ||
| 350 | char *buf) | ||
| 351 | { | ||
| 352 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 353 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 354 | u8 status; | ||
| 355 | u16 data; | ||
| 356 | int ret, i = 0; | ||
| 357 | |||
| 358 | do { | ||
| 359 | ret = adt7310_spi_read_byte(chip, ADT7310_STATUS, &status); | ||
| 360 | if (ret) | ||
| 361 | return -EIO; | ||
| 362 | i++; | ||
| 363 | if (i == 10000) | ||
| 364 | return -EIO; | ||
| 365 | } while (status & ADT7310_STAT_NOT_RDY); | ||
| 366 | |||
| 367 | ret = adt7310_spi_read_word(chip, ADT7310_TEMPERATURE, &data); | ||
| 368 | if (ret) | ||
| 369 | return -EIO; | ||
| 370 | |||
| 371 | return adt7310_convert_temperature(chip, data, buf); | ||
| 372 | } | ||
| 373 | |||
| 374 | static IIO_DEVICE_ATTR(value, S_IRUGO, adt7310_show_value, NULL, 0); | ||
| 375 | |||
| 376 | static struct attribute *adt7310_attributes[] = { | ||
| 377 | &iio_dev_attr_available_modes.dev_attr.attr, | ||
| 378 | &iio_dev_attr_mode.dev_attr.attr, | ||
| 379 | &iio_dev_attr_resolution.dev_attr.attr, | ||
| 380 | &iio_dev_attr_id.dev_attr.attr, | ||
| 381 | &iio_dev_attr_value.dev_attr.attr, | ||
| 382 | NULL, | ||
| 383 | }; | ||
| 384 | |||
| 385 | static const struct attribute_group adt7310_attribute_group = { | ||
| 386 | .attrs = adt7310_attributes, | ||
| 387 | }; | ||
| 388 | |||
| 389 | static irqreturn_t adt7310_event_handler(int irq, void *private) | ||
| 390 | { | ||
| 391 | struct iio_dev *indio_dev = private; | ||
| 392 | struct adt7310_chip_info *chip = iio_priv(indio_dev); | ||
| 393 | s64 timestamp = iio_get_time_ns(); | ||
| 394 | u8 status; | ||
| 395 | int ret; | ||
| 396 | |||
| 397 | ret = adt7310_spi_read_byte(chip, ADT7310_STATUS, &status); | ||
| 398 | if (ret) | ||
| 399 | return ret; | ||
| 400 | |||
| 401 | if (status & ADT7310_STAT_T_HIGH) | ||
| 402 | iio_push_event(indio_dev, 0, | ||
| 403 | IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, | ||
| 404 | IIO_EV_TYPE_THRESH, | ||
| 405 | IIO_EV_DIR_RISING), | ||
| 406 | timestamp); | ||
| 407 | if (status & ADT7310_STAT_T_LOW) | ||
| 408 | iio_push_event(indio_dev, 0, | ||
| 409 | IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, | ||
| 410 | IIO_EV_TYPE_THRESH, | ||
| 411 | IIO_EV_DIR_FALLING), | ||
| 412 | timestamp); | ||
| 413 | if (status & ADT7310_STAT_T_CRIT) | ||
| 414 | iio_push_event(indio_dev, 0, | ||
| 415 | IIO_UNMOD_EVENT_CODE(IIO_TEMP, 0, | ||
| 416 | IIO_EV_TYPE_THRESH, | ||
| 417 | IIO_EV_DIR_RISING), | ||
| 418 | timestamp); | ||
| 419 | return IRQ_HANDLED; | ||
| 420 | } | ||
| 421 | |||
| 422 | static ssize_t adt7310_show_event_mode(struct device *dev, | ||
| 423 | struct device_attribute *attr, | ||
| 424 | char *buf) | ||
| 425 | { | ||
| 426 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 427 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 428 | int ret; | ||
| 429 | |||
| 430 | ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); | ||
| 431 | if (ret) | ||
| 432 | return -EIO; | ||
| 433 | |||
| 434 | if (chip->config & ADT7310_EVENT_MODE) | ||
| 435 | return sprintf(buf, "interrupt\n"); | ||
| 436 | else | ||
| 437 | return sprintf(buf, "comparator\n"); | ||
| 438 | } | ||
| 439 | |||
| 440 | static ssize_t adt7310_set_event_mode(struct device *dev, | ||
| 441 | struct device_attribute *attr, | ||
| 442 | const char *buf, | ||
| 443 | size_t len) | ||
| 444 | { | ||
| 445 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 446 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 447 | u16 config; | ||
| 448 | int ret; | ||
| 449 | |||
| 450 | ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); | ||
| 451 | if (ret) | ||
| 452 | return -EIO; | ||
| 453 | |||
| 454 | config = chip->config &= ~ADT7310_EVENT_MODE; | ||
| 455 | if (strcmp(buf, "comparator") != 0) | ||
| 456 | config |= ADT7310_EVENT_MODE; | ||
| 457 | |||
| 458 | ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config); | ||
| 459 | if (ret) | ||
| 460 | return -EIO; | ||
| 461 | |||
| 462 | chip->config = config; | ||
| 463 | |||
| 464 | return len; | ||
| 465 | } | ||
| 466 | |||
| 467 | static ssize_t adt7310_show_available_event_modes(struct device *dev, | ||
| 468 | struct device_attribute *attr, | ||
| 469 | char *buf) | ||
| 470 | { | ||
| 471 | return sprintf(buf, "comparator\ninterrupt\n"); | ||
| 472 | } | ||
| 473 | |||
| 474 | static ssize_t adt7310_show_fault_queue(struct device *dev, | ||
| 475 | struct device_attribute *attr, | ||
| 476 | char *buf) | ||
| 477 | { | ||
| 478 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 479 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 480 | int ret; | ||
| 481 | |||
| 482 | ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); | ||
| 483 | if (ret) | ||
| 484 | return -EIO; | ||
| 485 | |||
| 486 | return sprintf(buf, "%d\n", chip->config & ADT7310_FAULT_QUEUE_MASK); | ||
| 487 | } | ||
| 488 | |||
| 489 | static ssize_t adt7310_set_fault_queue(struct device *dev, | ||
| 490 | struct device_attribute *attr, | ||
| 491 | const char *buf, | ||
| 492 | size_t len) | ||
| 493 | { | ||
| 494 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 495 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 496 | unsigned long data; | ||
| 497 | int ret; | ||
| 498 | u8 config; | ||
| 499 | |||
| 500 | ret = strict_strtoul(buf, 10, &data); | ||
| 501 | if (ret || data > 3) | ||
| 502 | return -EINVAL; | ||
| 503 | |||
| 504 | ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); | ||
| 505 | if (ret) | ||
| 506 | return -EIO; | ||
| 507 | |||
| 508 | config = chip->config & ~ADT7310_FAULT_QUEUE_MASK; | ||
| 509 | config |= data; | ||
| 510 | ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, config); | ||
| 511 | if (ret) | ||
| 512 | return -EIO; | ||
| 513 | |||
| 514 | chip->config = config; | ||
| 515 | |||
| 516 | return len; | ||
| 517 | } | ||
| 518 | |||
| 519 | static inline ssize_t adt7310_show_t_bound(struct device *dev, | ||
| 520 | struct device_attribute *attr, | ||
| 521 | u8 bound_reg, | ||
| 522 | char *buf) | ||
| 523 | { | ||
| 524 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 525 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 526 | u16 data; | ||
| 527 | int ret; | ||
| 528 | |||
| 529 | ret = adt7310_spi_read_word(chip, bound_reg, &data); | ||
| 530 | if (ret) | ||
| 531 | return -EIO; | ||
| 532 | |||
| 533 | return adt7310_convert_temperature(chip, data, buf); | ||
| 534 | } | ||
| 535 | |||
| 536 | static inline ssize_t adt7310_set_t_bound(struct device *dev, | ||
| 537 | struct device_attribute *attr, | ||
| 538 | u8 bound_reg, | ||
| 539 | const char *buf, | ||
| 540 | size_t len) | ||
| 541 | { | ||
| 542 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 543 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 544 | long tmp1, tmp2; | ||
| 545 | u16 data; | ||
| 546 | char *pos; | ||
| 547 | int ret; | ||
| 548 | |||
| 549 | pos = strchr(buf, '.'); | ||
| 550 | |||
| 551 | ret = strict_strtol(buf, 10, &tmp1); | ||
| 552 | |||
| 553 | if (ret || tmp1 > 127 || tmp1 < -128) | ||
| 554 | return -EINVAL; | ||
| 555 | |||
| 556 | if (pos) { | ||
| 557 | len = strlen(pos); | ||
| 558 | |||
| 559 | if (chip->config & ADT7310_RESOLUTION) { | ||
| 560 | if (len > ADT7310_T16_VALUE_FLOAT_OFFSET) | ||
| 561 | len = ADT7310_T16_VALUE_FLOAT_OFFSET; | ||
| 562 | pos[len] = 0; | ||
| 563 | ret = strict_strtol(pos, 10, &tmp2); | ||
| 564 | |||
| 565 | if (!ret) | ||
| 566 | tmp2 = (tmp2 / 78125) * 78125; | ||
| 567 | } else { | ||
| 568 | if (len > ADT7310_T13_VALUE_FLOAT_OFFSET) | ||
| 569 | len = ADT7310_T13_VALUE_FLOAT_OFFSET; | ||
| 570 | pos[len] = 0; | ||
| 571 | ret = strict_strtol(pos, 10, &tmp2); | ||
| 572 | |||
| 573 | if (!ret) | ||
| 574 | tmp2 = (tmp2 / 625) * 625; | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | if (tmp1 < 0) | ||
| 579 | data = (u16)(-tmp1); | ||
| 580 | else | ||
| 581 | data = (u16)tmp1; | ||
| 582 | |||
| 583 | if (chip->config & ADT7310_RESOLUTION) { | ||
| 584 | data = (data << ADT7310_T16_VALUE_FLOAT_OFFSET) | | ||
| 585 | (tmp2 & ADT7310_T16_VALUE_FLOAT_MASK); | ||
| 586 | |||
| 587 | if (tmp1 < 0) | ||
| 588 | /* convert positive value to supplyment */ | ||
| 589 | data = (u16)((ADT7310_T16_VALUE_SIGN << 1) - (u32)data); | ||
| 590 | } else { | ||
| 591 | data = (data << ADT7310_T13_VALUE_FLOAT_OFFSET) | | ||
| 592 | (tmp2 & ADT7310_T13_VALUE_FLOAT_MASK); | ||
| 593 | |||
| 594 | if (tmp1 < 0) | ||
| 595 | /* convert positive value to supplyment */ | ||
| 596 | data = (ADT7310_T13_VALUE_SIGN << 1) - data; | ||
| 597 | data <<= ADT7310_T13_VALUE_OFFSET; | ||
| 598 | } | ||
| 599 | |||
| 600 | ret = adt7310_spi_write_word(chip, bound_reg, data); | ||
| 601 | if (ret) | ||
| 602 | return -EIO; | ||
| 603 | |||
| 604 | return len; | ||
| 605 | } | ||
| 606 | |||
| 607 | static ssize_t adt7310_show_t_alarm_high(struct device *dev, | ||
| 608 | struct device_attribute *attr, | ||
| 609 | char *buf) | ||
| 610 | { | ||
| 611 | return adt7310_show_t_bound(dev, attr, | ||
| 612 | ADT7310_T_ALARM_HIGH, buf); | ||
| 613 | } | ||
| 614 | |||
| 615 | static inline ssize_t adt7310_set_t_alarm_high(struct device *dev, | ||
| 616 | struct device_attribute *attr, | ||
| 617 | const char *buf, | ||
| 618 | size_t len) | ||
| 619 | { | ||
| 620 | return adt7310_set_t_bound(dev, attr, | ||
| 621 | ADT7310_T_ALARM_HIGH, buf, len); | ||
| 622 | } | ||
| 623 | |||
| 624 | static ssize_t adt7310_show_t_alarm_low(struct device *dev, | ||
| 625 | struct device_attribute *attr, | ||
| 626 | char *buf) | ||
| 627 | { | ||
| 628 | return adt7310_show_t_bound(dev, attr, | ||
| 629 | ADT7310_T_ALARM_LOW, buf); | ||
| 630 | } | ||
| 631 | |||
| 632 | static inline ssize_t adt7310_set_t_alarm_low(struct device *dev, | ||
| 633 | struct device_attribute *attr, | ||
| 634 | const char *buf, | ||
| 635 | size_t len) | ||
| 636 | { | ||
| 637 | return adt7310_set_t_bound(dev, attr, | ||
| 638 | ADT7310_T_ALARM_LOW, buf, len); | ||
| 639 | } | ||
| 640 | |||
| 641 | static ssize_t adt7310_show_t_crit(struct device *dev, | ||
| 642 | struct device_attribute *attr, | ||
| 643 | char *buf) | ||
| 644 | { | ||
| 645 | return adt7310_show_t_bound(dev, attr, | ||
| 646 | ADT7310_T_CRIT, buf); | ||
| 647 | } | ||
| 648 | |||
| 649 | static inline ssize_t adt7310_set_t_crit(struct device *dev, | ||
| 650 | struct device_attribute *attr, | ||
| 651 | const char *buf, | ||
| 652 | size_t len) | ||
| 653 | { | ||
| 654 | return adt7310_set_t_bound(dev, attr, | ||
| 655 | ADT7310_T_CRIT, buf, len); | ||
| 656 | } | ||
| 657 | |||
| 658 | static ssize_t adt7310_show_t_hyst(struct device *dev, | ||
| 659 | struct device_attribute *attr, | ||
| 660 | char *buf) | ||
| 661 | { | ||
| 662 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 663 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 664 | int ret; | ||
| 665 | u8 t_hyst; | ||
| 666 | |||
| 667 | ret = adt7310_spi_read_byte(chip, ADT7310_T_HYST, &t_hyst); | ||
| 668 | if (ret) | ||
| 669 | return -EIO; | ||
| 670 | |||
| 671 | return sprintf(buf, "%d\n", t_hyst & ADT7310_T_HYST_MASK); | ||
| 672 | } | ||
| 673 | |||
| 674 | static inline ssize_t adt7310_set_t_hyst(struct device *dev, | ||
| 675 | struct device_attribute *attr, | ||
| 676 | const char *buf, | ||
| 677 | size_t len) | ||
| 678 | { | ||
| 679 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 680 | struct adt7310_chip_info *chip = iio_priv(dev_info); | ||
| 681 | int ret; | ||
| 682 | unsigned long data; | ||
| 683 | u8 t_hyst; | ||
| 684 | |||
| 685 | ret = strict_strtol(buf, 10, &data); | ||
| 686 | |||
| 687 | if (ret || data > ADT7310_T_HYST_MASK) | ||
| 688 | return -EINVAL; | ||
| 689 | |||
| 690 | t_hyst = (u8)data; | ||
| 691 | |||
| 692 | ret = adt7310_spi_write_byte(chip, ADT7310_T_HYST, t_hyst); | ||
| 693 | if (ret) | ||
| 694 | return -EIO; | ||
| 695 | |||
| 696 | return len; | ||
| 697 | } | ||
| 698 | |||
| 699 | static IIO_DEVICE_ATTR(event_mode, | ||
| 700 | S_IRUGO | S_IWUSR, | ||
| 701 | adt7310_show_event_mode, adt7310_set_event_mode, 0); | ||
| 702 | static IIO_DEVICE_ATTR(available_event_modes, | ||
| 703 | S_IRUGO | S_IWUSR, | ||
| 704 | adt7310_show_available_event_modes, NULL, 0); | ||
| 705 | static IIO_DEVICE_ATTR(fault_queue, | ||
| 706 | S_IRUGO | S_IWUSR, | ||
| 707 | adt7310_show_fault_queue, adt7310_set_fault_queue, 0); | ||
| 708 | static IIO_DEVICE_ATTR(t_alarm_high, | ||
| 709 | S_IRUGO | S_IWUSR, | ||
| 710 | adt7310_show_t_alarm_high, adt7310_set_t_alarm_high, 0); | ||
| 711 | static IIO_DEVICE_ATTR(t_alarm_low, | ||
| 712 | S_IRUGO | S_IWUSR, | ||
| 713 | adt7310_show_t_alarm_low, adt7310_set_t_alarm_low, 0); | ||
| 714 | static IIO_DEVICE_ATTR(t_crit, | ||
| 715 | S_IRUGO | S_IWUSR, | ||
| 716 | adt7310_show_t_crit, adt7310_set_t_crit, 0); | ||
| 717 | static IIO_DEVICE_ATTR(t_hyst, | ||
| 718 | S_IRUGO | S_IWUSR, | ||
| 719 | adt7310_show_t_hyst, adt7310_set_t_hyst, 0); | ||
| 720 | |||
| 721 | static struct attribute *adt7310_event_int_attributes[] = { | ||
| 722 | &iio_dev_attr_event_mode.dev_attr.attr, | ||
| 723 | &iio_dev_attr_available_event_modes.dev_attr.attr, | ||
| 724 | &iio_dev_attr_fault_queue.dev_attr.attr, | ||
| 725 | &iio_dev_attr_t_alarm_high.dev_attr.attr, | ||
| 726 | &iio_dev_attr_t_alarm_low.dev_attr.attr, | ||
| 727 | &iio_dev_attr_t_hyst.dev_attr.attr, | ||
| 728 | NULL, | ||
| 729 | }; | ||
| 730 | |||
| 731 | static struct attribute *adt7310_event_ct_attributes[] = { | ||
| 732 | &iio_dev_attr_event_mode.dev_attr.attr, | ||
| 733 | &iio_dev_attr_available_event_modes.dev_attr.attr, | ||
| 734 | &iio_dev_attr_fault_queue.dev_attr.attr, | ||
| 735 | &iio_dev_attr_t_crit.dev_attr.attr, | ||
| 736 | &iio_dev_attr_t_hyst.dev_attr.attr, | ||
| 737 | NULL, | ||
| 738 | }; | ||
| 739 | |||
| 740 | static struct attribute_group adt7310_event_attribute_group[ADT7310_IRQS] = { | ||
| 741 | { | ||
| 742 | .attrs = adt7310_event_int_attributes, | ||
| 743 | }, { | ||
| 744 | .attrs = adt7310_event_ct_attributes, | ||
| 745 | } | ||
| 746 | }; | ||
| 747 | |||
| 748 | static const struct iio_info adt7310_info = { | ||
| 749 | .attrs = &adt7310_attribute_group, | ||
| 750 | .num_interrupt_lines = ADT7310_IRQS, | ||
| 751 | .event_attrs = adt7310_event_attribute_group, | ||
| 752 | .driver_module = THIS_MODULE, | ||
| 753 | }; | ||
| 754 | |||
| 755 | /* | ||
| 756 | * device probe and remove | ||
| 757 | */ | ||
| 758 | |||
| 759 | static int __devinit adt7310_probe(struct spi_device *spi_dev) | ||
| 760 | { | ||
| 761 | struct adt7310_chip_info *chip; | ||
| 762 | struct iio_dev *indio_dev; | ||
| 763 | int ret = 0; | ||
| 764 | unsigned long *adt7310_platform_data = spi_dev->dev.platform_data; | ||
| 765 | unsigned long irq_flags; | ||
| 766 | |||
| 767 | indio_dev = iio_allocate_device(sizeof(*chip)); | ||
| 768 | if (indio_dev == NULL) { | ||
| 769 | ret = -ENOMEM; | ||
| 770 | goto error_ret; | ||
| 771 | } | ||
| 772 | chip = iio_priv(indio_dev); | ||
| 773 | /* this is only used for device removal purposes */ | ||
| 774 | dev_set_drvdata(&spi_dev->dev, indio_dev); | ||
| 775 | |||
| 776 | chip->spi_dev = spi_dev; | ||
| 777 | |||
| 778 | indio_dev->dev.parent = &spi_dev->dev; | ||
| 779 | indio_dev->name = spi_get_device_id(spi_dev)->name; | ||
| 780 | indio_dev->info = &adt7310_info; | ||
| 781 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 782 | |||
| 783 | ret = iio_device_register(indio_dev); | ||
| 784 | if (ret) | ||
| 785 | goto error_free_dev; | ||
| 786 | |||
| 787 | /* CT critcal temperature event. line 0 */ | ||
| 788 | if (spi_dev->irq) { | ||
| 789 | if (adt7310_platform_data[2]) | ||
| 790 | irq_flags = adt7310_platform_data[2]; | ||
| 791 | else | ||
| 792 | irq_flags = IRQF_TRIGGER_LOW; | ||
| 793 | ret = request_threaded_irq(spi_dev->irq, | ||
| 794 | NULL, | ||
| 795 | &adt7310_event_handler, | ||
| 796 | irq_flags, | ||
| 797 | indio_dev->name, | ||
| 798 | indio_dev); | ||
| 799 | if (ret) | ||
| 800 | goto error_unreg_dev; | ||
| 801 | } | ||
| 802 | |||
| 803 | /* INT bound temperature alarm event. line 1 */ | ||
| 804 | if (adt7310_platform_data[0]) { | ||
| 805 | ret = request_threaded_irq(adt7310_platform_data[0], | ||
| 806 | NULL, | ||
| 807 | &adt7310_event_handler, | ||
| 808 | adt7310_platform_data[1], | ||
| 809 | indio_dev->name, | ||
| 810 | indio_dev); | ||
| 811 | if (ret) | ||
| 812 | goto error_unreg_ct_irq; | ||
| 813 | } | ||
| 814 | |||
| 815 | if (spi_dev->irq && adt7310_platform_data[0]) { | ||
| 816 | ret = adt7310_spi_read_byte(chip, ADT7310_CONFIG, &chip->config); | ||
| 817 | if (ret) { | ||
| 818 | ret = -EIO; | ||
| 819 | goto error_unreg_int_irq; | ||
| 820 | } | ||
| 821 | |||
| 822 | /* set irq polarity low level */ | ||
| 823 | chip->config &= ~ADT7310_CT_POLARITY; | ||
| 824 | |||
| 825 | if (adt7310_platform_data[1] & IRQF_TRIGGER_HIGH) | ||
| 826 | chip->config |= ADT7310_INT_POLARITY; | ||
| 827 | else | ||
| 828 | chip->config &= ~ADT7310_INT_POLARITY; | ||
| 829 | |||
| 830 | ret = adt7310_spi_write_byte(chip, ADT7310_CONFIG, chip->config); | ||
| 831 | if (ret) { | ||
| 832 | ret = -EIO; | ||
| 833 | goto error_unreg_int_irq; | ||
| 834 | } | ||
| 835 | } | ||
| 836 | |||
| 837 | dev_info(&spi_dev->dev, "%s temperature sensor registered.\n", | ||
| 838 | indio_dev->name); | ||
| 839 | |||
| 840 | return 0; | ||
| 841 | |||
| 842 | error_unreg_int_irq: | ||
| 843 | free_irq(adt7310_platform_data[0], indio_dev); | ||
| 844 | error_unreg_ct_irq: | ||
| 845 | free_irq(spi_dev->irq, indio_dev); | ||
| 846 | error_unreg_dev: | ||
| 847 | iio_device_unregister(indio_dev); | ||
| 848 | error_free_dev: | ||
| 849 | iio_free_device(indio_dev); | ||
| 850 | error_ret: | ||
| 851 | return ret; | ||
| 852 | } | ||
| 853 | |||
| 854 | static int __devexit adt7310_remove(struct spi_device *spi_dev) | ||
| 855 | { | ||
| 856 | struct iio_dev *indio_dev = dev_get_drvdata(&spi_dev->dev); | ||
| 857 | unsigned long *adt7310_platform_data = spi_dev->dev.platform_data; | ||
| 858 | |||
| 859 | dev_set_drvdata(&spi_dev->dev, NULL); | ||
| 860 | if (adt7310_platform_data[0]) | ||
| 861 | free_irq(adt7310_platform_data[0], indio_dev); | ||
| 862 | if (spi_dev->irq) | ||
| 863 | free_irq(spi_dev->irq, indio_dev); | ||
| 864 | iio_device_unregister(indio_dev); | ||
| 865 | iio_free_device(indio_dev); | ||
| 866 | |||
| 867 | return 0; | ||
| 868 | } | ||
| 869 | |||
| 870 | static const struct spi_device_id adt7310_id[] = { | ||
| 871 | { "adt7310", 0 }, | ||
| 872 | {} | ||
| 873 | }; | ||
| 874 | |||
| 875 | MODULE_DEVICE_TABLE(spi, adt7310_id); | ||
| 876 | |||
| 877 | static struct spi_driver adt7310_driver = { | ||
| 878 | .driver = { | ||
| 879 | .name = "adt7310", | ||
| 880 | .bus = &spi_bus_type, | ||
| 881 | .owner = THIS_MODULE, | ||
| 882 | }, | ||
| 883 | .probe = adt7310_probe, | ||
| 884 | .remove = __devexit_p(adt7310_remove), | ||
| 885 | .id_table = adt7310_id, | ||
| 886 | }; | ||
| 887 | |||
| 888 | static __init int adt7310_init(void) | ||
| 889 | { | ||
| 890 | return spi_register_driver(&adt7310_driver); | ||
| 891 | } | ||
| 892 | |||
| 893 | static __exit void adt7310_exit(void) | ||
| 894 | { | ||
| 895 | spi_unregister_driver(&adt7310_driver); | ||
| 896 | } | ||
| 897 | |||
| 898 | MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); | ||
| 899 | MODULE_DESCRIPTION("Analog Devices ADT7310 digital" | ||
| 900 | " temperature sensor driver"); | ||
| 901 | MODULE_LICENSE("GPL v2"); | ||
| 902 | |||
| 903 | module_init(adt7310_init); | ||
| 904 | module_exit(adt7310_exit); | ||
diff --git a/drivers/staging/iio/adc/adt75.c b/drivers/staging/iio/adc/adt75.c new file mode 100644 index 00000000000..38f141de6a4 --- /dev/null +++ b/drivers/staging/iio/adc/adt75.c | |||
| @@ -0,0 +1,657 @@ | |||
| 1 | /* | ||
| 2 | * ADT75 digital temperature sensor driver supporting ADT75 | ||
| 3 | * | ||
| 4 | * Copyright 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/device.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/sysfs.h> | ||
| 14 | #include <linux/i2c.h> | ||
| 15 | |||
| 16 | #include "../iio.h" | ||
| 17 | #include "../sysfs.h" | ||
| 18 | |||
| 19 | /* | ||
| 20 | * ADT75 registers definition | ||
| 21 | */ | ||
| 22 | |||
| 23 | #define ADT75_TEMPERATURE 0 | ||
| 24 | #define ADT75_CONFIG 1 | ||
| 25 | #define ADT75_T_HYST 2 | ||
| 26 | #define ADT75_T_OS 3 | ||
| 27 | #define ADT75_ONESHOT 4 | ||
| 28 | |||
| 29 | /* | ||
| 30 | * ADT75 config | ||
| 31 | */ | ||
| 32 | #define ADT75_PD 0x1 | ||
| 33 | #define ADT75_OS_INT 0x2 | ||
| 34 | #define ADT75_OS_POLARITY 0x4 | ||
| 35 | #define ADT75_FAULT_QUEUE_MASK 0x18 | ||
| 36 | #define ADT75_FAULT_QUEUE_OFFSET 3 | ||
| 37 | #define ADT75_SMBUS_ALART 0x8 | ||
| 38 | |||
| 39 | /* | ||
| 40 | * ADT75 masks | ||
| 41 | */ | ||
| 42 | #define ADT75_VALUE_SIGN 0x800 | ||
| 43 | #define ADT75_VALUE_OFFSET 4 | ||
| 44 | #define ADT75_VALUE_FLOAT_OFFSET 4 | ||
| 45 | #define ADT75_VALUE_FLOAT_MASK 0xF | ||
| 46 | |||
| 47 | |||
| 48 | /* | ||
| 49 | * struct adt75_chip_info - chip specifc information | ||
| 50 | */ | ||
| 51 | |||
| 52 | struct adt75_chip_info { | ||
| 53 | struct i2c_client *client; | ||
| 54 | u8 config; | ||
| 55 | }; | ||
| 56 | |||
| 57 | /* | ||
| 58 | * adt75 register access by I2C | ||
| 59 | */ | ||
| 60 | |||
| 61 | static int adt75_i2c_read(struct iio_dev *dev_info, u8 reg, u8 *data) | ||
| 62 | { | ||
| 63 | struct adt75_chip_info *chip = iio_priv(dev_info); | ||
| 64 | struct i2c_client *client = chip->client; | ||
| 65 | int ret = 0, len; | ||
| 66 | |||
| 67 | ret = i2c_smbus_write_byte(client, reg); | ||
| 68 | if (ret < 0) { | ||
| 69 | dev_err(&client->dev, "I2C read register address error\n"); | ||
| 70 | return ret; | ||
| 71 | } | ||
| 72 | |||
| 73 | if (reg == ADT75_CONFIG || reg == ADT75_ONESHOT) | ||
| 74 | len = 1; | ||
| 75 | else | ||
| 76 | len = 2; | ||
| 77 | |||
| 78 | ret = i2c_master_recv(client, data, len); | ||
| 79 | if (ret < 0) { | ||
| 80 | dev_err(&client->dev, "I2C read error\n"); | ||
| 81 | return ret; | ||
| 82 | } | ||
| 83 | |||
| 84 | return ret; | ||
| 85 | } | ||
| 86 | |||
| 87 | static int adt75_i2c_write(struct iio_dev *dev_info, u8 reg, u8 data) | ||
| 88 | { | ||
| 89 | struct adt75_chip_info *chip = iio_priv(dev_info); | ||
| 90 | struct i2c_client *client = chip->client; | ||
| 91 | int ret = 0; | ||
| 92 | |||
| 93 | if (reg == ADT75_CONFIG || reg == ADT75_ONESHOT) | ||
| 94 | ret = i2c_smbus_write_byte_data(client, reg, data); | ||
| 95 | else | ||
| 96 | ret = i2c_smbus_write_word_data(client, reg, data); | ||
| 97 | |||
| 98 | if (ret < 0) | ||
| 99 | dev_err(&client->dev, "I2C write error\n"); | ||
| 100 | |||
| 101 | return ret; | ||
| 102 | } | ||
| 103 | |||
| 104 | static ssize_t adt75_show_mode(struct device *dev, | ||
| 105 | struct device_attribute *attr, | ||
| 106 | char *buf) | ||
| 107 | { | ||
| 108 | struct adt75_chip_info *chip = iio_priv(dev_get_drvdata(dev)); | ||
| 109 | |||
| 110 | if (chip->config & ADT75_PD) | ||
| 111 | return sprintf(buf, "power-save\n"); | ||
| 112 | else | ||
| 113 | return sprintf(buf, "full\n"); | ||
| 114 | } | ||
| 115 | |||
| 116 | static ssize_t adt75_store_mode(struct device *dev, | ||
| 117 | struct device_attribute *attr, | ||
| 118 | const char *buf, | ||
| 119 | size_t len) | ||
| 120 | { | ||
| 121 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 122 | struct adt75_chip_info *chip = iio_priv(dev_info); | ||
| 123 | int ret; | ||
| 124 | u8 config; | ||
| 125 | |||
| 126 | ret = adt75_i2c_read(dev_info, ADT75_CONFIG, &chip->config); | ||
| 127 | if (ret) | ||
| 128 | return -EIO; | ||
| 129 | |||
| 130 | config = chip->config & ~ADT75_PD; | ||
| 131 | if (!strcmp(buf, "full")) | ||
| 132 | config |= ADT75_PD; | ||
| 133 | |||
| 134 | ret = adt75_i2c_write(dev_info, ADT75_CONFIG, config); | ||
| 135 | if (ret) | ||
| 136 | return -EIO; | ||
| 137 | |||
| 138 | chip->config = config; | ||
| 139 | |||
| 140 | return ret; | ||
| 141 | } | ||
| 142 | |||
| 143 | static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, | ||
| 144 | adt75_show_mode, | ||
| 145 | adt75_store_mode, | ||
| 146 | 0); | ||
| 147 | |||
| 148 | static ssize_t adt75_show_available_modes(struct device *dev, | ||
| 149 | struct device_attribute *attr, | ||
| 150 | char *buf) | ||
| 151 | { | ||
| 152 | return sprintf(buf, "full\npower-down\n"); | ||
| 153 | } | ||
| 154 | |||
| 155 | static IIO_DEVICE_ATTR(available_modes, S_IRUGO, adt75_show_available_modes, NULL, 0); | ||
| 156 | |||
| 157 | static ssize_t adt75_show_oneshot(struct device *dev, | ||
| 158 | struct device_attribute *attr, | ||
| 159 | char *buf) | ||
| 160 | { | ||
| 161 | struct adt75_chip_info *chip = iio_priv(dev_get_drvdata(dev)); | ||
| 162 | |||
| 163 | return sprintf(buf, "%d\n", !!(chip->config & ADT75_ONESHOT)); | ||
| 164 | } | ||
| 165 | |||
| 166 | static ssize_t adt75_store_oneshot(struct device *dev, | ||
| 167 | struct device_attribute *attr, | ||
| 168 | const char *buf, | ||
| 169 | size_t len) | ||
| 170 | { | ||
| 171 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 172 | struct adt75_chip_info *chip = iio_priv(dev_info); | ||
| 173 | unsigned long data = 0; | ||
| 174 | int ret; | ||
| 175 | u8 config; | ||
| 176 | |||
| 177 | ret = strict_strtoul(buf, 10, &data); | ||
| 178 | if (ret) | ||
| 179 | return -EINVAL; | ||
| 180 | |||
| 181 | |||
| 182 | ret = adt75_i2c_read(dev_info, ADT75_CONFIG, &chip->config); | ||
| 183 | if (ret) | ||
| 184 | return -EIO; | ||
| 185 | |||
| 186 | config = chip->config & ~ADT75_ONESHOT; | ||
| 187 | if (data) | ||
| 188 | config |= ADT75_ONESHOT; | ||
| 189 | |||
| 190 | ret = adt75_i2c_write(dev_info, ADT75_CONFIG, config); | ||
| 191 | if (ret) | ||
| 192 | return -EIO; | ||
| 193 | |||
| 194 | chip->config = config; | ||
| 195 | |||
| 196 | return ret; | ||
| 197 | } | ||
| 198 | |||
| 199 | static IIO_DEVICE_ATTR(oneshot, S_IRUGO | S_IWUSR, | ||
| 200 | adt75_show_oneshot, | ||
| 201 | adt75_store_oneshot, | ||
| 202 | 0); | ||
| 203 | |||
| 204 | static ssize_t adt75_show_value(struct device *dev, | ||
| 205 | struct device_attribute *attr, | ||
| 206 | char *buf) | ||
| 207 | { | ||
| 208 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 209 | struct adt75_chip_info *chip = iio_priv(dev_info); | ||
| 210 | u16 data; | ||
| 211 | char sign = ' '; | ||
| 212 | int ret; | ||
| 213 | |||
| 214 | if (chip->config & ADT75_PD) { | ||
| 215 | dev_err(dev, "Can't read value in power-down mode.\n"); | ||
| 216 | return -EIO; | ||
| 217 | } | ||
| 218 | |||
| 219 | if (chip->config & ADT75_ONESHOT) { | ||
| 220 | /* write to active converter */ | ||
| 221 | ret = i2c_smbus_write_byte(chip->client, ADT75_ONESHOT); | ||
| 222 | if (ret) | ||
| 223 | return -EIO; | ||
| 224 | } | ||
| 225 | |||
| 226 | ret = adt75_i2c_read(dev_info, ADT75_TEMPERATURE, (u8 *)&data); | ||
| 227 | if (ret) | ||
| 228 | return -EIO; | ||
| 229 | |||
| 230 | data = swab16(data) >> ADT75_VALUE_OFFSET; | ||
| 231 | if (data & ADT75_VALUE_SIGN) { | ||
| 232 | /* convert supplement to positive value */ | ||
| 233 | data = (ADT75_VALUE_SIGN << 1) - data; | ||
| 234 | sign = '-'; | ||
| 235 | } | ||
| 236 | |||
| 237 | return sprintf(buf, "%c%d.%.4d\n", sign, | ||
| 238 | (data >> ADT75_VALUE_FLOAT_OFFSET), | ||
| 239 | (data & ADT75_VALUE_FLOAT_MASK) * 625); | ||
| 240 | } | ||
| 241 | |||
| 242 | static IIO_DEVICE_ATTR(value, S_IRUGO, adt75_show_value, NULL, 0); | ||
| 243 | |||
| 244 | static struct attribute *adt75_attributes[] = { | ||
| 245 | &iio_dev_attr_available_modes.dev_attr.attr, | ||
| 246 | &iio_dev_attr_mode.dev_attr.attr, | ||
| 247 | &iio_dev_attr_oneshot.dev_attr.attr, | ||
| 248 | &iio_dev_attr_value.dev_attr.attr, | ||
| 249 | NULL, | ||
| 250 | }; | ||
| 251 | |||
| 252 | static const struct attribute_group adt75_attribute_group = { | ||
| 253 | .attrs = adt75_attributes, | ||
| 254 | }; | ||
| 255 | |||
| 256 | /* | ||
| 257 | * temperature bound events | ||
| 258 | */ | ||
| 259 | |||
| 260 | #define IIO_EVENT_CODE_ADT75_OTI IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_TEMP, \ | ||
| 261 | 0, \ | ||
| 262 | IIO_EV_TYPE_THRESH, \ | ||
| 263 | IIO_EV_DIR_FALLING) | ||
| 264 | |||
| 265 | static irqreturn_t adt75_event_handler(int irq, void *private) | ||
| 266 | { | ||
| 267 | iio_push_event(private, 0, | ||
| 268 | IIO_EVENT_CODE_ADT75_OTI, | ||
| 269 | iio_get_time_ns()); | ||
| 270 | |||
| 271 | return IRQ_HANDLED; | ||
| 272 | } | ||
| 273 | |||
| 274 | static ssize_t adt75_show_oti_mode(struct device *dev, | ||
| 275 | struct device_attribute *attr, | ||
| 276 | char *buf) | ||
| 277 | { | ||
| 278 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 279 | struct adt75_chip_info *chip = iio_priv(dev_info); | ||
| 280 | int ret; | ||
| 281 | |||
| 282 | /* retrive ALART status */ | ||
| 283 | ret = adt75_i2c_read(dev_info, ADT75_CONFIG, &chip->config); | ||
| 284 | if (ret) | ||
| 285 | return -EIO; | ||
| 286 | |||
| 287 | if (chip->config & ADT75_OS_INT) | ||
| 288 | return sprintf(buf, "interrupt\n"); | ||
| 289 | else | ||
| 290 | return sprintf(buf, "comparator\n"); | ||
| 291 | } | ||
| 292 | |||
| 293 | static ssize_t adt75_set_oti_mode(struct device *dev, | ||
| 294 | struct device_attribute *attr, | ||
| 295 | const char *buf, | ||
| 296 | size_t len) | ||
| 297 | { | ||
| 298 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 299 | struct adt75_chip_info *chip = iio_priv(dev_info); | ||
| 300 | int ret; | ||
| 301 | u8 config; | ||
| 302 | |||
| 303 | /* retrive ALART status */ | ||
| 304 | ret = adt75_i2c_read(dev_info, ADT75_CONFIG, &chip->config); | ||
| 305 | if (ret) | ||
| 306 | return -EIO; | ||
| 307 | |||
| 308 | config = chip->config & ~ADT75_OS_INT; | ||
| 309 | if (strcmp(buf, "comparator") != 0) | ||
| 310 | config |= ADT75_OS_INT; | ||
| 311 | |||
| 312 | ret = adt75_i2c_write(dev_info, ADT75_CONFIG, config); | ||
| 313 | if (ret) | ||
| 314 | return -EIO; | ||
| 315 | |||
| 316 | chip->config = config; | ||
| 317 | |||
| 318 | return ret; | ||
| 319 | } | ||
| 320 | |||
| 321 | static ssize_t adt75_show_available_oti_modes(struct device *dev, | ||
| 322 | struct device_attribute *attr, | ||
| 323 | char *buf) | ||
| 324 | { | ||
| 325 | return sprintf(buf, "comparator\ninterrupt\n"); | ||
| 326 | } | ||
| 327 | |||
| 328 | static ssize_t adt75_show_smbus_alart(struct device *dev, | ||
| 329 | struct device_attribute *attr, | ||
| 330 | char *buf) | ||
| 331 | { | ||
| 332 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 333 | struct adt75_chip_info *chip = iio_priv(dev_info); | ||
| 334 | int ret; | ||
| 335 | |||
| 336 | /* retrive ALART status */ | ||
| 337 | ret = adt75_i2c_read(dev_info, ADT75_CONFIG, &chip->config); | ||
| 338 | if (ret) | ||
| 339 | return -EIO; | ||
| 340 | |||
| 341 | return sprintf(buf, "%d\n", !!(chip->config & ADT75_SMBUS_ALART)); | ||
| 342 | } | ||
| 343 | |||
| 344 | static ssize_t adt75_set_smbus_alart(struct device *dev, | ||
| 345 | struct device_attribute *attr, | ||
| 346 | const char *buf, | ||
| 347 | size_t len) | ||
| 348 | { | ||
| 349 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 350 | struct adt75_chip_info *chip = iio_priv(dev_info); | ||
| 351 | unsigned long data = 0; | ||
| 352 | int ret; | ||
| 353 | u8 config; | ||
| 354 | |||
| 355 | ret = strict_strtoul(buf, 10, &data); | ||
| 356 | if (ret) | ||
| 357 | return -EINVAL; | ||
| 358 | |||
| 359 | /* retrive ALART status */ | ||
| 360 | ret = adt75_i2c_read(dev_info, ADT75_CONFIG, &chip->config); | ||
| 361 | if (ret) | ||
| 362 | return -EIO; | ||
| 363 | |||
| 364 | config = chip->config & ~ADT75_SMBUS_ALART; | ||
| 365 | if (data) | ||
| 366 | config |= ADT75_SMBUS_ALART; | ||
| 367 | |||
| 368 | ret = adt75_i2c_write(dev_info, ADT75_CONFIG, config); | ||
| 369 | if (ret) | ||
| 370 | return -EIO; | ||
| 371 | |||
| 372 | chip->config = config; | ||
| 373 | |||
| 374 | return ret; | ||
| 375 | } | ||
| 376 | |||
| 377 | static ssize_t adt75_show_fault_queue(struct device *dev, | ||
| 378 | struct device_attribute *attr, | ||
| 379 | char *buf) | ||
| 380 | { | ||
| 381 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 382 | struct adt75_chip_info *chip = iio_priv(dev_info); | ||
| 383 | int ret; | ||
| 384 | |||
| 385 | /* retrive ALART status */ | ||
| 386 | ret = adt75_i2c_read(dev_info, ADT75_CONFIG, &chip->config); | ||
| 387 | if (ret) | ||
| 388 | return -EIO; | ||
| 389 | |||
| 390 | return sprintf(buf, "%d\n", (chip->config & ADT75_FAULT_QUEUE_MASK) >> | ||
| 391 | ADT75_FAULT_QUEUE_OFFSET); | ||
| 392 | } | ||
| 393 | |||
| 394 | static ssize_t adt75_set_fault_queue(struct device *dev, | ||
| 395 | struct device_attribute *attr, | ||
| 396 | const char *buf, | ||
| 397 | size_t len) | ||
| 398 | { | ||
| 399 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 400 | struct adt75_chip_info *chip = iio_priv(dev_info); | ||
| 401 | unsigned long data; | ||
| 402 | int ret; | ||
| 403 | u8 config; | ||
| 404 | |||
| 405 | ret = strict_strtoul(buf, 10, &data); | ||
| 406 | if (ret || data > 3) | ||
| 407 | return -EINVAL; | ||
| 408 | |||
| 409 | /* retrive ALART status */ | ||
| 410 | ret = adt75_i2c_read(dev_info, ADT75_CONFIG, &chip->config); | ||
| 411 | if (ret) | ||
| 412 | return -EIO; | ||
| 413 | |||
| 414 | config = chip->config & ~ADT75_FAULT_QUEUE_MASK; | ||
| 415 | config |= (data << ADT75_FAULT_QUEUE_OFFSET); | ||
| 416 | ret = adt75_i2c_write(dev_info, ADT75_CONFIG, config); | ||
| 417 | if (ret) | ||
| 418 | return -EIO; | ||
| 419 | |||
| 420 | chip->config = config; | ||
| 421 | |||
| 422 | return ret; | ||
| 423 | } | ||
| 424 | static inline ssize_t adt75_show_t_bound(struct device *dev, | ||
| 425 | struct device_attribute *attr, | ||
| 426 | char *buf) | ||
| 427 | { | ||
| 428 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 429 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 430 | u16 data; | ||
| 431 | char sign = ' '; | ||
| 432 | int ret; | ||
| 433 | |||
| 434 | ret = adt75_i2c_read(dev_info, this_attr->address, (u8 *)&data); | ||
| 435 | if (ret) | ||
| 436 | return -EIO; | ||
| 437 | |||
| 438 | data = swab16(data) >> ADT75_VALUE_OFFSET; | ||
| 439 | if (data & ADT75_VALUE_SIGN) { | ||
| 440 | /* convert supplement to positive value */ | ||
| 441 | data = (ADT75_VALUE_SIGN << 1) - data; | ||
| 442 | sign = '-'; | ||
| 443 | } | ||
| 444 | |||
| 445 | return sprintf(buf, "%c%d.%.4d\n", sign, | ||
| 446 | (data >> ADT75_VALUE_FLOAT_OFFSET), | ||
| 447 | (data & ADT75_VALUE_FLOAT_MASK) * 625); | ||
| 448 | } | ||
| 449 | |||
| 450 | static inline ssize_t adt75_set_t_bound(struct device *dev, | ||
| 451 | struct device_attribute *attr, | ||
| 452 | const char *buf, | ||
| 453 | size_t len) | ||
| 454 | { | ||
| 455 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 456 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 457 | long tmp1, tmp2; | ||
| 458 | u16 data; | ||
| 459 | char *pos; | ||
| 460 | int ret; | ||
| 461 | |||
| 462 | pos = strchr(buf, '.'); | ||
| 463 | |||
| 464 | ret = strict_strtol(buf, 10, &tmp1); | ||
| 465 | |||
| 466 | if (ret || tmp1 > 127 || tmp1 < -128) | ||
| 467 | return -EINVAL; | ||
| 468 | |||
| 469 | if (pos) { | ||
| 470 | len = strlen(pos); | ||
| 471 | if (len > ADT75_VALUE_FLOAT_OFFSET) | ||
| 472 | len = ADT75_VALUE_FLOAT_OFFSET; | ||
| 473 | pos[len] = 0; | ||
| 474 | ret = strict_strtol(pos, 10, &tmp2); | ||
| 475 | |||
| 476 | if (!ret) | ||
| 477 | tmp2 = (tmp2 / 625) * 625; | ||
| 478 | } | ||
| 479 | |||
| 480 | if (tmp1 < 0) | ||
| 481 | data = (u16)(-tmp1); | ||
| 482 | else | ||
| 483 | data = (u16)tmp1; | ||
| 484 | data = (data << ADT75_VALUE_FLOAT_OFFSET) | (tmp2 & ADT75_VALUE_FLOAT_MASK); | ||
| 485 | if (tmp1 < 0) | ||
| 486 | /* convert positive value to supplyment */ | ||
| 487 | data = (ADT75_VALUE_SIGN << 1) - data; | ||
| 488 | data <<= ADT75_VALUE_OFFSET; | ||
| 489 | data = swab16(data); | ||
| 490 | |||
| 491 | ret = adt75_i2c_write(dev_info, this_attr->address, (u8)data); | ||
| 492 | if (ret) | ||
| 493 | return -EIO; | ||
| 494 | |||
| 495 | return ret; | ||
| 496 | } | ||
| 497 | |||
| 498 | |||
| 499 | static IIO_DEVICE_ATTR(oti_mode, | ||
| 500 | S_IRUGO | S_IWUSR, | ||
| 501 | adt75_show_oti_mode, adt75_set_oti_mode, 0); | ||
| 502 | static IIO_DEVICE_ATTR(available_oti_modes, | ||
| 503 | S_IRUGO, | ||
| 504 | adt75_show_available_oti_modes, NULL, 0); | ||
| 505 | static IIO_DEVICE_ATTR(smbus_alart, | ||
| 506 | S_IRUGO | S_IWUSR, | ||
| 507 | adt75_show_smbus_alart, adt75_set_smbus_alart, 0); | ||
| 508 | static IIO_DEVICE_ATTR(fault_queue, | ||
| 509 | S_IRUGO | S_IWUSR, | ||
| 510 | adt75_show_fault_queue, adt75_set_fault_queue, 0); | ||
| 511 | static IIO_DEVICE_ATTR(t_os_value, | ||
| 512 | S_IRUGO | S_IWUSR, | ||
| 513 | adt75_show_t_bound, adt75_set_t_bound, | ||
| 514 | ADT75_T_OS); | ||
| 515 | static IIO_DEVICE_ATTR(t_hyst_value, | ||
| 516 | S_IRUGO | S_IWUSR, | ||
| 517 | adt75_show_t_bound, adt75_set_t_bound, | ||
| 518 | ADT75_T_HYST); | ||
| 519 | |||
| 520 | static struct attribute *adt75_event_attributes[] = { | ||
| 521 | &iio_dev_attr_oti_mode.dev_attr.attr, | ||
| 522 | &iio_dev_attr_available_oti_modes.dev_attr.attr, | ||
| 523 | &iio_dev_attr_smbus_alart.dev_attr.attr, | ||
| 524 | &iio_dev_attr_fault_queue.dev_attr.attr, | ||
| 525 | &iio_dev_attr_t_os_value.dev_attr.attr, | ||
| 526 | &iio_dev_attr_t_hyst_value.dev_attr.attr, | ||
| 527 | NULL, | ||
| 528 | }; | ||
| 529 | |||
| 530 | static struct attribute_group adt75_event_attribute_group = { | ||
| 531 | .attrs = adt75_event_attributes, | ||
| 532 | }; | ||
| 533 | |||
| 534 | static const struct iio_info adt75_info = { | ||
| 535 | .attrs = &adt75_attribute_group, | ||
| 536 | .num_interrupt_lines = 1, | ||
| 537 | .event_attrs = &adt75_event_attribute_group, | ||
| 538 | .driver_module = THIS_MODULE, | ||
| 539 | }; | ||
| 540 | |||
| 541 | /* | ||
| 542 | * device probe and remove | ||
| 543 | */ | ||
| 544 | |||
| 545 | static int __devinit adt75_probe(struct i2c_client *client, | ||
| 546 | const struct i2c_device_id *id) | ||
| 547 | { | ||
| 548 | struct adt75_chip_info *chip; | ||
| 549 | struct iio_dev *indio_dev; | ||
| 550 | int ret = 0; | ||
| 551 | |||
| 552 | indio_dev = iio_allocate_device(sizeof(*chip)); | ||
| 553 | if (indio_dev == NULL) { | ||
| 554 | ret = -ENOMEM; | ||
| 555 | goto error_ret; | ||
| 556 | } | ||
| 557 | chip = iio_priv(indio_dev); | ||
| 558 | |||
| 559 | /* this is only used for device removal purposes */ | ||
| 560 | i2c_set_clientdata(client, indio_dev); | ||
| 561 | |||
| 562 | chip->client = client; | ||
| 563 | |||
| 564 | indio_dev->name = id->name; | ||
| 565 | indio_dev->dev.parent = &client->dev; | ||
| 566 | indio_dev->info = &adt75_info; | ||
| 567 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 568 | |||
| 569 | ret = iio_device_register(indio_dev); | ||
| 570 | if (ret) | ||
| 571 | goto error_free_dev; | ||
| 572 | |||
| 573 | if (client->irq > 0) { | ||
| 574 | ret = request_threaded_irq(client->irq, | ||
| 575 | NULL, | ||
| 576 | &adt75_event_handler, | ||
| 577 | IRQF_TRIGGER_LOW, | ||
| 578 | indio_dev->name, | ||
| 579 | indio_dev); | ||
| 580 | if (ret) | ||
| 581 | goto error_unreg_dev; | ||
| 582 | |||
| 583 | ret = adt75_i2c_read(indio_dev, ADT75_CONFIG, &chip->config); | ||
| 584 | if (ret) { | ||
| 585 | ret = -EIO; | ||
| 586 | goto error_unreg_irq; | ||
| 587 | } | ||
| 588 | |||
| 589 | /* set irq polarity low level */ | ||
| 590 | chip->config &= ~ADT75_OS_POLARITY; | ||
| 591 | |||
| 592 | ret = adt75_i2c_write(indio_dev, ADT75_CONFIG, chip->config); | ||
| 593 | if (ret) { | ||
| 594 | ret = -EIO; | ||
| 595 | goto error_unreg_irq; | ||
| 596 | } | ||
| 597 | } | ||
| 598 | |||
| 599 | dev_info(&client->dev, "%s temperature sensor registered.\n", | ||
| 600 | indio_dev->name); | ||
| 601 | |||
| 602 | return 0; | ||
| 603 | error_unreg_irq: | ||
| 604 | free_irq(client->irq, indio_dev); | ||
| 605 | error_unreg_dev: | ||
| 606 | iio_device_unregister(indio_dev); | ||
| 607 | error_free_dev: | ||
| 608 | iio_free_device(indio_dev); | ||
| 609 | error_ret: | ||
| 610 | return ret; | ||
| 611 | } | ||
| 612 | |||
| 613 | static int __devexit adt75_remove(struct i2c_client *client) | ||
| 614 | { | ||
| 615 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | ||
| 616 | |||
| 617 | if (client->irq) | ||
| 618 | free_irq(client->irq, indio_dev); | ||
| 619 | iio_device_unregister(indio_dev); | ||
| 620 | iio_free_device(indio_dev); | ||
| 621 | |||
| 622 | return 0; | ||
| 623 | } | ||
| 624 | |||
| 625 | static const struct i2c_device_id adt75_id[] = { | ||
| 626 | { "adt75", 0 }, | ||
| 627 | {} | ||
| 628 | }; | ||
| 629 | |||
| 630 | MODULE_DEVICE_TABLE(i2c, adt75_id); | ||
| 631 | |||
| 632 | static struct i2c_driver adt75_driver = { | ||
| 633 | .driver = { | ||
| 634 | .name = "adt75", | ||
| 635 | }, | ||
| 636 | .probe = adt75_probe, | ||
| 637 | .remove = __devexit_p(adt75_remove), | ||
| 638 | .id_table = adt75_id, | ||
| 639 | }; | ||
| 640 | |||
| 641 | static __init int adt75_init(void) | ||
| 642 | { | ||
| 643 | return i2c_add_driver(&adt75_driver); | ||
| 644 | } | ||
| 645 | |||
| 646 | static __exit void adt75_exit(void) | ||
| 647 | { | ||
| 648 | i2c_del_driver(&adt75_driver); | ||
| 649 | } | ||
| 650 | |||
| 651 | MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); | ||
| 652 | MODULE_DESCRIPTION("Analog Devices ADT75 digital" | ||
| 653 | " temperature sensor driver"); | ||
| 654 | MODULE_LICENSE("GPL v2"); | ||
| 655 | |||
| 656 | module_init(adt75_init); | ||
| 657 | module_exit(adt75_exit); | ||
diff --git a/drivers/staging/iio/adc/max1363.h b/drivers/staging/iio/adc/max1363.h new file mode 100644 index 00000000000..360bfc5398f --- /dev/null +++ b/drivers/staging/iio/adc/max1363.h | |||
| @@ -0,0 +1,175 @@ | |||
| 1 | #ifndef _MAX1363_H_ | ||
| 2 | #define _MAX1363_H_ | ||
| 3 | |||
| 4 | #define MAX1363_SETUP_BYTE(a) ((a) | 0x80) | ||
| 5 | |||
| 6 | /* There is a fair bit more defined here than currently | ||
| 7 | * used, but the intention is to support everything these | ||
| 8 | * chips do in the long run */ | ||
| 9 | |||
| 10 | /* see data sheets */ | ||
| 11 | /* max1363 and max1236, max1237, max1238, max1239 */ | ||
| 12 | #define MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_VDD 0x00 | ||
| 13 | #define MAX1363_SETUP_AIN3_IS_REF_EXT_TO_REF 0x20 | ||
| 14 | #define MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_INT 0x40 | ||
| 15 | #define MAX1363_SETUP_AIN3_IS_REF_REF_IS_INT 0x60 | ||
| 16 | #define MAX1363_SETUP_POWER_UP_INT_REF 0x10 | ||
| 17 | #define MAX1363_SETUP_POWER_DOWN_INT_REF 0x00 | ||
| 18 | |||
| 19 | /* think about includeing max11600 etc - more settings */ | ||
| 20 | #define MAX1363_SETUP_EXT_CLOCK 0x08 | ||
| 21 | #define MAX1363_SETUP_INT_CLOCK 0x00 | ||
| 22 | #define MAX1363_SETUP_UNIPOLAR 0x00 | ||
| 23 | #define MAX1363_SETUP_BIPOLAR 0x04 | ||
| 24 | #define MAX1363_SETUP_RESET 0x00 | ||
| 25 | #define MAX1363_SETUP_NORESET 0x02 | ||
| 26 | /* max1363 only - though don't care on others. | ||
| 27 | * For now monitor modes are not implemented as the relevant | ||
| 28 | * line is not connected on my test board. | ||
| 29 | * The definitions are here as I intend to add this soon. | ||
| 30 | */ | ||
| 31 | #define MAX1363_SETUP_MONITOR_SETUP 0x01 | ||
| 32 | |||
| 33 | /* Specific to the max1363 */ | ||
| 34 | #define MAX1363_MON_RESET_CHAN(a) (1 << ((a) + 4)) | ||
| 35 | #define MAX1363_MON_INT_ENABLE 0x01 | ||
| 36 | |||
| 37 | /* defined for readability reasons */ | ||
| 38 | /* All chips */ | ||
| 39 | #define MAX1363_CONFIG_BYTE(a) ((a)) | ||
| 40 | |||
| 41 | #define MAX1363_CONFIG_SE 0x01 | ||
| 42 | #define MAX1363_CONFIG_DE 0x00 | ||
| 43 | #define MAX1363_CONFIG_SCAN_TO_CS 0x00 | ||
| 44 | #define MAX1363_CONFIG_SCAN_SINGLE_8 0x20 | ||
| 45 | #define MAX1363_CONFIG_SCAN_MONITOR_MODE 0x40 | ||
| 46 | #define MAX1363_CONFIG_SCAN_SINGLE_1 0x60 | ||
| 47 | /* max123{6-9} only */ | ||
| 48 | #define MAX1236_SCAN_MID_TO_CHANNEL 0x40 | ||
| 49 | |||
| 50 | /* max1363 only - merely part of channel selects or don't care for others*/ | ||
| 51 | #define MAX1363_CONFIG_EN_MON_MODE_READ 0x18 | ||
| 52 | |||
| 53 | #define MAX1363_CHANNEL_SEL(a) ((a) << 1) | ||
| 54 | |||
| 55 | /* max1363 strictly 0x06 - but doesn't matter */ | ||
| 56 | #define MAX1363_CHANNEL_SEL_MASK 0x1E | ||
| 57 | #define MAX1363_SCAN_MASK 0x60 | ||
| 58 | #define MAX1363_SE_DE_MASK 0x01 | ||
| 59 | |||
| 60 | /** | ||
| 61 | * struct max1363_mode - scan mode information | ||
| 62 | * @conf: The corresponding value of the configuration register | ||
| 63 | * @modemask: Bit mask corresponding to channels enabled in this mode | ||
| 64 | */ | ||
| 65 | struct max1363_mode { | ||
| 66 | int8_t conf; | ||
| 67 | long modemask; | ||
| 68 | }; | ||
| 69 | |||
| 70 | /* This must be maintained along side the max1363_mode_table in max1363_core */ | ||
| 71 | enum max1363_modes { | ||
| 72 | /* Single read of a single channel */ | ||
| 73 | _s0, _s1, _s2, _s3, _s4, _s5, _s6, _s7, _s8, _s9, _s10, _s11, | ||
| 74 | /* Differential single read */ | ||
| 75 | d0m1, d2m3, d4m5, d6m7, d8m9, d10m11, | ||
| 76 | d1m0, d3m2, d5m4, d7m6, d9m8, d11m10, | ||
| 77 | /* Scan to channel and mid to channel where overlapping */ | ||
| 78 | s0to1, s0to2, s2to3, s0to3, s0to4, s0to5, s0to6, | ||
| 79 | s6to7, s0to7, s6to8, s0to8, s6to9, | ||
| 80 | s0to9, s6to10, s0to10, s6to11, s0to11, | ||
| 81 | /* Differential scan to channel and mid to channel where overlapping */ | ||
| 82 | d0m1to2m3, d0m1to4m5, d0m1to6m7, d6m7to8m9, | ||
| 83 | d0m1to8m9, d6m7to10m11, d0m1to10m11, d1m0to3m2, | ||
| 84 | d1m0to5m4, d1m0to7m6, d7m6to9m8, d1m0to9m8, | ||
| 85 | d7m6to11m10, d1m0to11m10, | ||
| 86 | }; | ||
| 87 | |||
| 88 | /** | ||
| 89 | * struct max1363_chip_info - chip specifc information | ||
| 90 | * @name: indentification string for chip | ||
| 91 | * @bits: accuracy of the adc in bits | ||
| 92 | * @int_vref_mv: the internal reference voltage | ||
| 93 | * @info: iio core function callbacks structure | ||
| 94 | * @mode_list: array of available scan modes | ||
| 95 | * @num_modes: the number of scan modes available | ||
| 96 | * @default_mode: the scan mode in which the chip starts up | ||
| 97 | * @channel: channel specification | ||
| 98 | * @num_channels: number of channels | ||
| 99 | */ | ||
| 100 | struct max1363_chip_info { | ||
| 101 | const struct iio_info *info; | ||
| 102 | struct iio_chan_spec *channels; | ||
| 103 | int num_channels; | ||
| 104 | const enum max1363_modes *mode_list; | ||
| 105 | enum max1363_modes default_mode; | ||
| 106 | u16 int_vref_mv; | ||
| 107 | u8 num_modes; | ||
| 108 | u8 bits; | ||
| 109 | }; | ||
| 110 | |||
| 111 | /** | ||
| 112 | * struct max1363_state - driver instance specific data | ||
| 113 | * @client: i2c_client | ||
| 114 | * @setupbyte: cache of current device setup byte | ||
| 115 | * @configbyte: cache of current device config byte | ||
| 116 | * @chip_info: chip model specific constants, available modes etc | ||
| 117 | * @current_mode: the scan mode of this chip | ||
| 118 | * @requestedmask: a valid requested set of channels | ||
| 119 | * @reg: supply regulator | ||
| 120 | * @monitor_on: whether monitor mode is enabled | ||
| 121 | * @monitor_speed: parameter corresponding to device monitor speed setting | ||
| 122 | * @mask_high: bitmask for enabled high thresholds | ||
| 123 | * @mask_low: bitmask for enabled low thresholds | ||
| 124 | * @thresh_high: high threshold values | ||
| 125 | * @thresh_low: low threshold values | ||
| 126 | */ | ||
| 127 | struct max1363_state { | ||
| 128 | struct i2c_client *client; | ||
| 129 | u8 setupbyte; | ||
| 130 | u8 configbyte; | ||
| 131 | const struct max1363_chip_info *chip_info; | ||
| 132 | const struct max1363_mode *current_mode; | ||
| 133 | u32 requestedmask; | ||
| 134 | struct regulator *reg; | ||
| 135 | |||
| 136 | /* Using monitor modes and buffer at the same time is | ||
| 137 | currently not supported */ | ||
| 138 | bool monitor_on; | ||
| 139 | unsigned int monitor_speed:3; | ||
| 140 | u8 mask_high; | ||
| 141 | u8 mask_low; | ||
| 142 | /* 4x unipolar first then the fours bipolar ones */ | ||
| 143 | s16 thresh_high[8]; | ||
| 144 | s16 thresh_low[8]; | ||
| 145 | }; | ||
| 146 | |||
| 147 | const struct max1363_mode | ||
| 148 | *max1363_match_mode(u32 mask, const struct max1363_chip_info *ci); | ||
| 149 | |||
| 150 | int max1363_set_scan_mode(struct max1363_state *st); | ||
| 151 | |||
| 152 | #ifdef CONFIG_MAX1363_RING_BUFFER | ||
| 153 | |||
| 154 | int max1363_single_channel_from_ring(long mask, struct max1363_state *st); | ||
| 155 | int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev); | ||
| 156 | void max1363_ring_cleanup(struct iio_dev *indio_dev); | ||
| 157 | |||
| 158 | #else /* CONFIG_MAX1363_RING_BUFFER */ | ||
| 159 | |||
| 160 | int max1363_single_channel_from_ring(long mask, struct max1363_state *st) | ||
| 161 | { | ||
| 162 | return -EINVAL; | ||
| 163 | } | ||
| 164 | |||
| 165 | static inline int | ||
| 166 | max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev) | ||
| 167 | { | ||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | |||
| 171 | static inline void max1363_ring_cleanup(struct iio_dev *indio_dev) | ||
| 172 | { | ||
| 173 | } | ||
| 174 | #endif /* CONFIG_MAX1363_RING_BUFFER */ | ||
| 175 | #endif /* _MAX1363_H_ */ | ||
diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c new file mode 100644 index 00000000000..72b0917412e --- /dev/null +++ b/drivers/staging/iio/adc/max1363_core.c | |||
| @@ -0,0 +1,1433 @@ | |||
| 1 | /* | ||
| 2 | * iio/adc/max1363.c | ||
| 3 | * Copyright (C) 2008-2010 Jonathan Cameron | ||
| 4 | * | ||
| 5 | * based on linux/drivers/i2c/chips/max123x | ||
| 6 | * Copyright (C) 2002-2004 Stefan Eletzhofer | ||
| 7 | * | ||
| 8 | * based on linux/drivers/acron/char/pcf8583.c | ||
| 9 | * Copyright (C) 2000 Russell King | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or modify | ||
| 12 | * it under the terms of the GNU General Public License version 2 as | ||
| 13 | * published by the Free Software Foundation. | ||
| 14 | * | ||
| 15 | * max1363.c | ||
| 16 | * | ||
| 17 | * Partial support for max1363 and similar chips. | ||
| 18 | * | ||
| 19 | * Not currently implemented. | ||
| 20 | * | ||
| 21 | * - Control of internal reference. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/interrupt.h> | ||
| 25 | #include <linux/device.h> | ||
| 26 | #include <linux/kernel.h> | ||
| 27 | #include <linux/sysfs.h> | ||
| 28 | #include <linux/list.h> | ||
| 29 | #include <linux/i2c.h> | ||
| 30 | #include <linux/regulator/consumer.h> | ||
| 31 | #include <linux/slab.h> | ||
| 32 | #include <linux/err.h> | ||
| 33 | |||
| 34 | #include "../iio.h" | ||
| 35 | #include "../sysfs.h" | ||
| 36 | |||
| 37 | #include "../ring_generic.h" | ||
| 38 | #include "adc.h" | ||
| 39 | #include "max1363.h" | ||
| 40 | |||
| 41 | #define MAX1363_MODE_SINGLE(_num, _mask) { \ | ||
| 42 | .conf = MAX1363_CHANNEL_SEL(_num) \ | ||
| 43 | | MAX1363_CONFIG_SCAN_SINGLE_1 \ | ||
| 44 | | MAX1363_CONFIG_SE, \ | ||
| 45 | .modemask = _mask, \ | ||
| 46 | } | ||
| 47 | |||
| 48 | #define MAX1363_MODE_SCAN_TO_CHANNEL(_num, _mask) { \ | ||
| 49 | .conf = MAX1363_CHANNEL_SEL(_num) \ | ||
| 50 | | MAX1363_CONFIG_SCAN_TO_CS \ | ||
| 51 | | MAX1363_CONFIG_SE, \ | ||
| 52 | .modemask = _mask, \ | ||
| 53 | } | ||
| 54 | |||
| 55 | /* note not available for max1363 hence naming */ | ||
| 56 | #define MAX1236_MODE_SCAN_MID_TO_CHANNEL(_mid, _num, _mask) { \ | ||
| 57 | .conf = MAX1363_CHANNEL_SEL(_num) \ | ||
| 58 | | MAX1236_SCAN_MID_TO_CHANNEL \ | ||
| 59 | | MAX1363_CONFIG_SE, \ | ||
| 60 | .modemask = _mask \ | ||
| 61 | } | ||
| 62 | |||
| 63 | #define MAX1363_MODE_DIFF_SINGLE(_nump, _numm, _mask) { \ | ||
| 64 | .conf = MAX1363_CHANNEL_SEL(_nump) \ | ||
| 65 | | MAX1363_CONFIG_SCAN_SINGLE_1 \ | ||
| 66 | | MAX1363_CONFIG_DE, \ | ||
| 67 | .modemask = _mask \ | ||
| 68 | } | ||
| 69 | |||
| 70 | /* Can't think how to automate naming so specify for now */ | ||
| 71 | #define MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(_num, _numvals, _mask) { \ | ||
| 72 | .conf = MAX1363_CHANNEL_SEL(_num) \ | ||
| 73 | | MAX1363_CONFIG_SCAN_TO_CS \ | ||
| 74 | | MAX1363_CONFIG_DE, \ | ||
| 75 | .modemask = _mask \ | ||
| 76 | } | ||
| 77 | |||
| 78 | /* note only available for max1363 hence naming */ | ||
| 79 | #define MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(_num, _numvals, _mask) { \ | ||
| 80 | .conf = MAX1363_CHANNEL_SEL(_num) \ | ||
| 81 | | MAX1236_SCAN_MID_TO_CHANNEL \ | ||
| 82 | | MAX1363_CONFIG_SE, \ | ||
| 83 | .modemask = _mask \ | ||
| 84 | } | ||
| 85 | |||
| 86 | static const struct max1363_mode max1363_mode_table[] = { | ||
| 87 | /* All of the single channel options first */ | ||
| 88 | MAX1363_MODE_SINGLE(0, 1 << 0), | ||
| 89 | MAX1363_MODE_SINGLE(1, 1 << 1), | ||
| 90 | MAX1363_MODE_SINGLE(2, 1 << 2), | ||
| 91 | MAX1363_MODE_SINGLE(3, 1 << 3), | ||
| 92 | MAX1363_MODE_SINGLE(4, 1 << 4), | ||
| 93 | MAX1363_MODE_SINGLE(5, 1 << 5), | ||
| 94 | MAX1363_MODE_SINGLE(6, 1 << 6), | ||
| 95 | MAX1363_MODE_SINGLE(7, 1 << 7), | ||
| 96 | MAX1363_MODE_SINGLE(8, 1 << 8), | ||
| 97 | MAX1363_MODE_SINGLE(9, 1 << 9), | ||
| 98 | MAX1363_MODE_SINGLE(10, 1 << 10), | ||
| 99 | MAX1363_MODE_SINGLE(11, 1 << 11), | ||
| 100 | |||
| 101 | MAX1363_MODE_DIFF_SINGLE(0, 1, 1 << 12), | ||
| 102 | MAX1363_MODE_DIFF_SINGLE(2, 3, 1 << 13), | ||
| 103 | MAX1363_MODE_DIFF_SINGLE(4, 5, 1 << 14), | ||
| 104 | MAX1363_MODE_DIFF_SINGLE(6, 7, 1 << 15), | ||
| 105 | MAX1363_MODE_DIFF_SINGLE(8, 9, 1 << 16), | ||
| 106 | MAX1363_MODE_DIFF_SINGLE(10, 11, 1 << 17), | ||
| 107 | MAX1363_MODE_DIFF_SINGLE(1, 0, 1 << 18), | ||
| 108 | MAX1363_MODE_DIFF_SINGLE(3, 2, 1 << 19), | ||
| 109 | MAX1363_MODE_DIFF_SINGLE(5, 4, 1 << 20), | ||
| 110 | MAX1363_MODE_DIFF_SINGLE(7, 6, 1 << 21), | ||
| 111 | MAX1363_MODE_DIFF_SINGLE(9, 8, 1 << 22), | ||
| 112 | MAX1363_MODE_DIFF_SINGLE(11, 10, 1 << 23), | ||
| 113 | |||
| 114 | /* The multichannel scans next */ | ||
| 115 | MAX1363_MODE_SCAN_TO_CHANNEL(1, 0x003), | ||
| 116 | MAX1363_MODE_SCAN_TO_CHANNEL(2, 0x007), | ||
| 117 | MAX1236_MODE_SCAN_MID_TO_CHANNEL(2, 3, 0x00C), | ||
| 118 | MAX1363_MODE_SCAN_TO_CHANNEL(3, 0x00F), | ||
| 119 | MAX1363_MODE_SCAN_TO_CHANNEL(4, 0x01F), | ||
| 120 | MAX1363_MODE_SCAN_TO_CHANNEL(5, 0x03F), | ||
| 121 | MAX1363_MODE_SCAN_TO_CHANNEL(6, 0x07F), | ||
| 122 | MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 7, 0x0C0), | ||
| 123 | MAX1363_MODE_SCAN_TO_CHANNEL(7, 0x0FF), | ||
| 124 | MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 8, 0x1C0), | ||
| 125 | MAX1363_MODE_SCAN_TO_CHANNEL(8, 0x1FF), | ||
| 126 | MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 9, 0x3C0), | ||
| 127 | MAX1363_MODE_SCAN_TO_CHANNEL(9, 0x3FF), | ||
| 128 | MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 10, 0x7C0), | ||
| 129 | MAX1363_MODE_SCAN_TO_CHANNEL(10, 0x7FF), | ||
| 130 | MAX1236_MODE_SCAN_MID_TO_CHANNEL(6, 11, 0xFC0), | ||
| 131 | MAX1363_MODE_SCAN_TO_CHANNEL(11, 0xFFF), | ||
| 132 | |||
| 133 | MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(2, 2, 0x003000), | ||
| 134 | MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(4, 3, 0x007000), | ||
| 135 | MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(6, 4, 0x00F000), | ||
| 136 | MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(8, 2, 0x018000), | ||
| 137 | MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(8, 5, 0x01F000), | ||
| 138 | MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(10, 3, 0x038000), | ||
| 139 | MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(10, 6, 0x3F000), | ||
| 140 | MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(3, 2, 0x0C0000), | ||
| 141 | MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(5, 3, 0x1C0000), | ||
| 142 | MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(7, 4, 0x3C0000), | ||
| 143 | MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(9, 2, 0x600000), | ||
| 144 | MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(9, 5, 0x7C0000), | ||
| 145 | MAX1236_MODE_DIFF_SCAN_MID_TO_CHANNEL(11, 3, 0xE00000), | ||
| 146 | MAX1363_MODE_DIFF_SCAN_TO_CHANNEL(11, 6, 0xFC0000), | ||
| 147 | }; | ||
| 148 | |||
| 149 | const struct max1363_mode | ||
| 150 | *max1363_match_mode(u32 mask, const struct max1363_chip_info *ci) | ||
| 151 | { | ||
| 152 | int i; | ||
| 153 | if (mask) | ||
| 154 | for (i = 0; i < ci->num_modes; i++) | ||
| 155 | if (!((~max1363_mode_table[ci->mode_list[i]].modemask) & | ||
| 156 | mask)) | ||
| 157 | return &max1363_mode_table[ci->mode_list[i]]; | ||
| 158 | return NULL; | ||
| 159 | } | ||
| 160 | |||
| 161 | static int max1363_write_basic_config(struct i2c_client *client, | ||
| 162 | unsigned char d1, | ||
| 163 | unsigned char d2) | ||
| 164 | { | ||
| 165 | u8 tx_buf[2] = {d1, d2}; | ||
| 166 | |||
| 167 | return i2c_master_send(client, tx_buf, 2); | ||
| 168 | } | ||
| 169 | |||
| 170 | int max1363_set_scan_mode(struct max1363_state *st) | ||
| 171 | { | ||
| 172 | st->configbyte &= ~(MAX1363_CHANNEL_SEL_MASK | ||
| 173 | | MAX1363_SCAN_MASK | ||
| 174 | | MAX1363_SE_DE_MASK); | ||
| 175 | st->configbyte |= st->current_mode->conf; | ||
| 176 | |||
| 177 | return max1363_write_basic_config(st->client, | ||
| 178 | st->setupbyte, | ||
| 179 | st->configbyte); | ||
| 180 | } | ||
| 181 | |||
| 182 | static int max1363_read_single_chan(struct iio_dev *indio_dev, | ||
| 183 | struct iio_chan_spec const *chan, | ||
| 184 | int *val, | ||
| 185 | long m) | ||
| 186 | { | ||
| 187 | int ret = 0; | ||
| 188 | s32 data; | ||
| 189 | char rxbuf[2]; | ||
| 190 | long mask; | ||
| 191 | struct max1363_state *st = iio_priv(indio_dev); | ||
| 192 | struct i2c_client *client = st->client; | ||
| 193 | |||
| 194 | mutex_lock(&indio_dev->mlock); | ||
| 195 | /* | ||
| 196 | * If monitor mode is enabled, the method for reading a single | ||
| 197 | * channel will have to be rather different and has not yet | ||
| 198 | * been implemented. | ||
| 199 | */ | ||
| 200 | if (st->monitor_on) { | ||
| 201 | ret = -EBUSY; | ||
| 202 | goto error_ret; | ||
| 203 | } | ||
| 204 | |||
| 205 | /* If ring buffer capture is occurring, query the buffer */ | ||
| 206 | if (iio_ring_enabled(indio_dev)) { | ||
| 207 | mask = max1363_mode_table[chan->address].modemask; | ||
| 208 | data = max1363_single_channel_from_ring(mask, st); | ||
| 209 | if (data < 0) { | ||
| 210 | ret = data; | ||
| 211 | goto error_ret; | ||
| 212 | } | ||
| 213 | } else { | ||
| 214 | /* Check to see if current scan mode is correct */ | ||
| 215 | if (st->current_mode != &max1363_mode_table[chan->address]) { | ||
| 216 | /* Update scan mode if needed */ | ||
| 217 | st->current_mode = &max1363_mode_table[chan->address]; | ||
| 218 | ret = max1363_set_scan_mode(st); | ||
| 219 | if (ret < 0) | ||
| 220 | goto error_ret; | ||
| 221 | } | ||
| 222 | if (st->chip_info->bits != 8) { | ||
| 223 | /* Get reading */ | ||
| 224 | data = i2c_master_recv(client, rxbuf, 2); | ||
| 225 | if (data < 0) { | ||
| 226 | ret = data; | ||
| 227 | goto error_ret; | ||
| 228 | } | ||
| 229 | data = (s32)(rxbuf[1]) | ((s32)(rxbuf[0] & 0x0F)) << 8; | ||
| 230 | } else { | ||
| 231 | /* Get reading */ | ||
| 232 | data = i2c_master_recv(client, rxbuf, 1); | ||
| 233 | if (data < 0) { | ||
| 234 | ret = data; | ||
| 235 | goto error_ret; | ||
| 236 | } | ||
| 237 | data = rxbuf[0]; | ||
| 238 | } | ||
| 239 | } | ||
| 240 | *val = data; | ||
| 241 | error_ret: | ||
| 242 | mutex_unlock(&indio_dev->mlock); | ||
| 243 | return ret; | ||
| 244 | |||
| 245 | } | ||
| 246 | |||
| 247 | static int max1363_read_raw(struct iio_dev *indio_dev, | ||
| 248 | struct iio_chan_spec const *chan, | ||
| 249 | int *val, | ||
| 250 | int *val2, | ||
| 251 | long m) | ||
| 252 | { | ||
| 253 | struct max1363_state *st = iio_priv(indio_dev); | ||
| 254 | int ret; | ||
| 255 | switch (m) { | ||
| 256 | case 0: | ||
| 257 | ret = max1363_read_single_chan(indio_dev, chan, val, m); | ||
| 258 | if (ret) | ||
| 259 | return ret; | ||
| 260 | return IIO_VAL_INT; | ||
| 261 | case (1 << IIO_CHAN_INFO_SCALE_SHARED): | ||
| 262 | if ((1 << (st->chip_info->bits + 1)) > | ||
| 263 | st->chip_info->int_vref_mv) { | ||
| 264 | *val = 0; | ||
| 265 | *val2 = 500000; | ||
| 266 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 267 | } else { | ||
| 268 | *val = (st->chip_info->int_vref_mv) | ||
| 269 | >> st->chip_info->bits; | ||
| 270 | return IIO_VAL_INT; | ||
| 271 | } | ||
| 272 | default: | ||
| 273 | return -EINVAL; | ||
| 274 | } | ||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | |||
| 278 | /* Applies to max1363 */ | ||
| 279 | static const enum max1363_modes max1363_mode_list[] = { | ||
| 280 | _s0, _s1, _s2, _s3, | ||
| 281 | s0to1, s0to2, s0to3, | ||
| 282 | d0m1, d2m3, d1m0, d3m2, | ||
| 283 | d0m1to2m3, d1m0to3m2, | ||
| 284 | }; | ||
| 285 | |||
| 286 | #define MAX1363_EV_M \ | ||
| 287 | (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \ | ||
| 288 | | IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)) | ||
| 289 | #define MAX1363_INFO_MASK (1 << IIO_CHAN_INFO_SCALE_SHARED) | ||
| 290 | |||
| 291 | static struct iio_chan_spec max1363_channels[] = { | ||
| 292 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, MAX1363_INFO_MASK, | ||
| 293 | _s0, 0, IIO_ST('u', 12, 16, 0), MAX1363_EV_M), | ||
| 294 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 1, 0, MAX1363_INFO_MASK, | ||
| 295 | _s1, 1, IIO_ST('u', 12, 16, 0), MAX1363_EV_M), | ||
| 296 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 2, 0, MAX1363_INFO_MASK, | ||
| 297 | _s2, 2, IIO_ST('u', 12, 16, 0), MAX1363_EV_M), | ||
| 298 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 3, 0, MAX1363_INFO_MASK, | ||
| 299 | _s3, 3, IIO_ST('u', 12, 16, 0), MAX1363_EV_M), | ||
| 300 | IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 0, 1, MAX1363_INFO_MASK, | ||
| 301 | d0m1, 4, IIO_ST('s', 12, 16, 0), MAX1363_EV_M), | ||
| 302 | IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 2, 3, MAX1363_INFO_MASK, | ||
| 303 | d2m3, 5, IIO_ST('s', 12, 16, 0), MAX1363_EV_M), | ||
| 304 | IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 1, 0, MAX1363_INFO_MASK, | ||
| 305 | d1m0, 6, IIO_ST('s', 12, 16, 0), MAX1363_EV_M), | ||
| 306 | IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 3, 2, MAX1363_INFO_MASK, | ||
| 307 | d3m2, 7, IIO_ST('s', 12, 16, 0), MAX1363_EV_M), | ||
| 308 | IIO_CHAN_SOFT_TIMESTAMP(8) | ||
| 309 | }; | ||
| 310 | |||
| 311 | static struct iio_chan_spec max1361_channels[] = { | ||
| 312 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 0, 0, MAX1363_INFO_MASK, | ||
| 313 | _s0, 0, IIO_ST('u', 10, 16, 0), MAX1363_EV_M), | ||
| 314 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 1, 0, MAX1363_INFO_MASK, | ||
| 315 | _s1, 1, IIO_ST('u', 10, 16, 0), MAX1363_EV_M), | ||
| 316 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 2, 0, MAX1363_INFO_MASK, | ||
| 317 | _s2, 2, IIO_ST('u', 10, 16, 0), MAX1363_EV_M), | ||
| 318 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, 3, 0, MAX1363_INFO_MASK, | ||
| 319 | _s3, 3, IIO_ST('u', 10, 16, 0), MAX1363_EV_M), | ||
| 320 | IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 0, 1, MAX1363_INFO_MASK, | ||
| 321 | d0m1, 4, IIO_ST('s', 10, 16, 0), MAX1363_EV_M), | ||
| 322 | IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 2, 3, MAX1363_INFO_MASK, | ||
| 323 | d2m3, 5, IIO_ST('s', 10, 16, 0), MAX1363_EV_M), | ||
| 324 | IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 1, 0, MAX1363_INFO_MASK, | ||
| 325 | d1m0, 6, IIO_ST('s', 10, 16, 0), MAX1363_EV_M), | ||
| 326 | IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, 3, 2, MAX1363_INFO_MASK, | ||
| 327 | d3m2, 7, IIO_ST('s', 10, 16, 0), MAX1363_EV_M), | ||
| 328 | IIO_CHAN_SOFT_TIMESTAMP(8) | ||
| 329 | }; | ||
| 330 | |||
| 331 | #define MAX1363_CHAN_U(num, address, scan_index, bits) \ | ||
| 332 | IIO_CHAN(IIO_IN, 0, 1, 0, NULL, num, 0, MAX1363_INFO_MASK, \ | ||
| 333 | address, scan_index, IIO_ST('u', bits, \ | ||
| 334 | (bits == 8) ? 8 : 16, 0), 0) | ||
| 335 | /* bipolar channel */ | ||
| 336 | #define MAX1363_CHAN_B(num, num2, address, scan_index, bits) \ | ||
| 337 | IIO_CHAN(IIO_IN_DIFF, 0, 1, 0, NULL, num, num2, MAX1363_INFO_MASK,\ | ||
| 338 | address, scan_index, IIO_ST('s', bits, \ | ||
| 339 | (bits == 8) ? 8 : 16, 0), 0) | ||
| 340 | |||
| 341 | #define MAX1363_4X_CHANS(bits) { \ | ||
| 342 | MAX1363_CHAN_U(0, _s0, 0, bits), \ | ||
| 343 | MAX1363_CHAN_U(1, _s1, 1, bits), \ | ||
| 344 | MAX1363_CHAN_U(2, _s2, 2, bits), \ | ||
| 345 | MAX1363_CHAN_U(3, _s3, 3, bits), \ | ||
| 346 | MAX1363_CHAN_B(0, 1, d0m1, 4, bits), \ | ||
| 347 | MAX1363_CHAN_B(2, 3, d2m3, 5, bits), \ | ||
| 348 | MAX1363_CHAN_B(1, 0, d1m0, 6, bits), \ | ||
| 349 | MAX1363_CHAN_B(3, 2, d3m2, 7, bits), \ | ||
| 350 | IIO_CHAN_SOFT_TIMESTAMP(8) \ | ||
| 351 | } | ||
| 352 | |||
| 353 | static struct iio_chan_spec max1036_channels[] = MAX1363_4X_CHANS(8); | ||
| 354 | static struct iio_chan_spec max1136_channels[] = MAX1363_4X_CHANS(10); | ||
| 355 | static struct iio_chan_spec max1236_channels[] = MAX1363_4X_CHANS(12); | ||
| 356 | |||
| 357 | /* Appies to max1236, max1237 */ | ||
| 358 | static const enum max1363_modes max1236_mode_list[] = { | ||
| 359 | _s0, _s1, _s2, _s3, | ||
| 360 | s0to1, s0to2, s0to3, | ||
| 361 | d0m1, d2m3, d1m0, d3m2, | ||
| 362 | d0m1to2m3, d1m0to3m2, | ||
| 363 | s2to3, | ||
| 364 | }; | ||
| 365 | |||
| 366 | /* Applies to max1238, max1239 */ | ||
| 367 | static const enum max1363_modes max1238_mode_list[] = { | ||
| 368 | _s0, _s1, _s2, _s3, _s4, _s5, _s6, _s7, _s8, _s9, _s10, _s11, | ||
| 369 | s0to1, s0to2, s0to3, s0to4, s0to5, s0to6, | ||
| 370 | s0to7, s0to8, s0to9, s0to10, s0to11, | ||
| 371 | d0m1, d2m3, d4m5, d6m7, d8m9, d10m11, | ||
| 372 | d1m0, d3m2, d5m4, d7m6, d9m8, d11m10, | ||
| 373 | d0m1to2m3, d0m1to4m5, d0m1to6m7, d0m1to8m9, d0m1to10m11, | ||
| 374 | d1m0to3m2, d1m0to5m4, d1m0to7m6, d1m0to9m8, d1m0to11m10, | ||
| 375 | s6to7, s6to8, s6to9, s6to10, s6to11, | ||
| 376 | d6m7to8m9, d6m7to10m11, d7m6to9m8, d7m6to11m10, | ||
| 377 | }; | ||
| 378 | |||
| 379 | #define MAX1363_12X_CHANS(bits) { \ | ||
| 380 | MAX1363_CHAN_U(0, _s0, 0, bits), \ | ||
| 381 | MAX1363_CHAN_U(1, _s1, 1, bits), \ | ||
| 382 | MAX1363_CHAN_U(2, _s2, 2, bits), \ | ||
| 383 | MAX1363_CHAN_U(3, _s3, 3, bits), \ | ||
| 384 | MAX1363_CHAN_U(4, _s4, 4, bits), \ | ||
| 385 | MAX1363_CHAN_U(5, _s5, 5, bits), \ | ||
| 386 | MAX1363_CHAN_U(6, _s6, 6, bits), \ | ||
| 387 | MAX1363_CHAN_U(7, _s7, 7, bits), \ | ||
| 388 | MAX1363_CHAN_U(8, _s8, 8, bits), \ | ||
| 389 | MAX1363_CHAN_U(9, _s9, 9, bits), \ | ||
| 390 | MAX1363_CHAN_U(10, _s10, 10, bits), \ | ||
| 391 | MAX1363_CHAN_U(11, _s11, 11, bits), \ | ||
| 392 | MAX1363_CHAN_B(0, 1, d0m1, 12, bits), \ | ||
| 393 | MAX1363_CHAN_B(2, 3, d2m3, 13, bits), \ | ||
| 394 | MAX1363_CHAN_B(4, 5, d4m5, 14, bits), \ | ||
| 395 | MAX1363_CHAN_B(6, 7, d6m7, 15, bits), \ | ||
| 396 | MAX1363_CHAN_B(8, 9, d8m9, 16, bits), \ | ||
| 397 | MAX1363_CHAN_B(10, 11, d10m11, 17, bits), \ | ||
| 398 | MAX1363_CHAN_B(1, 0, d1m0, 18, bits), \ | ||
| 399 | MAX1363_CHAN_B(3, 2, d3m2, 19, bits), \ | ||
| 400 | MAX1363_CHAN_B(5, 4, d5m4, 20, bits), \ | ||
| 401 | MAX1363_CHAN_B(7, 6, d7m6, 21, bits), \ | ||
| 402 | MAX1363_CHAN_B(9, 8, d9m8, 22, bits), \ | ||
| 403 | MAX1363_CHAN_B(11, 10, d11m10, 23, bits), \ | ||
| 404 | IIO_CHAN_SOFT_TIMESTAMP(24) \ | ||
| 405 | } | ||
| 406 | static struct iio_chan_spec max1038_channels[] = MAX1363_12X_CHANS(8); | ||
| 407 | static struct iio_chan_spec max1138_channels[] = MAX1363_12X_CHANS(10); | ||
| 408 | static struct iio_chan_spec max1238_channels[] = MAX1363_12X_CHANS(12); | ||
| 409 | |||
| 410 | static const enum max1363_modes max11607_mode_list[] = { | ||
| 411 | _s0, _s1, _s2, _s3, | ||
| 412 | s0to1, s0to2, s0to3, | ||
| 413 | s2to3, | ||
| 414 | d0m1, d2m3, d1m0, d3m2, | ||
| 415 | d0m1to2m3, d1m0to3m2, | ||
| 416 | }; | ||
| 417 | |||
| 418 | static const enum max1363_modes max11608_mode_list[] = { | ||
| 419 | _s0, _s1, _s2, _s3, _s4, _s5, _s6, _s7, | ||
| 420 | s0to1, s0to2, s0to3, s0to4, s0to5, s0to6, s0to7, | ||
| 421 | s6to7, | ||
| 422 | d0m1, d2m3, d4m5, d6m7, | ||
| 423 | d1m0, d3m2, d5m4, d7m6, | ||
| 424 | d0m1to2m3, d0m1to4m5, d0m1to6m7, | ||
| 425 | d1m0to3m2, d1m0to5m4, d1m0to7m6, | ||
| 426 | }; | ||
| 427 | |||
| 428 | #define MAX1363_8X_CHANS(bits) { \ | ||
| 429 | MAX1363_CHAN_U(0, _s0, 0, bits), \ | ||
| 430 | MAX1363_CHAN_U(1, _s1, 1, bits), \ | ||
| 431 | MAX1363_CHAN_U(2, _s2, 2, bits), \ | ||
| 432 | MAX1363_CHAN_U(3, _s3, 3, bits), \ | ||
| 433 | MAX1363_CHAN_U(4, _s4, 4, bits), \ | ||
| 434 | MAX1363_CHAN_U(5, _s5, 5, bits), \ | ||
| 435 | MAX1363_CHAN_U(6, _s6, 6, bits), \ | ||
| 436 | MAX1363_CHAN_U(7, _s7, 7, bits), \ | ||
| 437 | MAX1363_CHAN_B(0, 1, d0m1, 8, bits), \ | ||
| 438 | MAX1363_CHAN_B(2, 3, d2m3, 9, bits), \ | ||
| 439 | MAX1363_CHAN_B(4, 5, d4m5, 10, bits), \ | ||
| 440 | MAX1363_CHAN_B(6, 7, d6m7, 11, bits), \ | ||
| 441 | MAX1363_CHAN_B(1, 0, d1m0, 12, bits), \ | ||
| 442 | MAX1363_CHAN_B(3, 2, d3m2, 13, bits), \ | ||
| 443 | MAX1363_CHAN_B(5, 4, d5m4, 14, bits), \ | ||
| 444 | MAX1363_CHAN_B(7, 6, d7m6, 15, bits), \ | ||
| 445 | IIO_CHAN_SOFT_TIMESTAMP(16) \ | ||
| 446 | } | ||
| 447 | static struct iio_chan_spec max11602_channels[] = MAX1363_8X_CHANS(8); | ||
| 448 | static struct iio_chan_spec max11608_channels[] = MAX1363_8X_CHANS(10); | ||
| 449 | static struct iio_chan_spec max11614_channels[] = MAX1363_8X_CHANS(12); | ||
| 450 | |||
| 451 | static const enum max1363_modes max11644_mode_list[] = { | ||
| 452 | _s0, _s1, s0to1, d0m1, d1m0, | ||
| 453 | }; | ||
| 454 | |||
| 455 | #define MAX1363_2X_CHANS(bits) { \ | ||
| 456 | MAX1363_CHAN_U(0, _s0, 0, bits), \ | ||
| 457 | MAX1363_CHAN_U(1, _s1, 1, bits), \ | ||
| 458 | MAX1363_CHAN_B(0, 1, d0m1, 2, bits), \ | ||
| 459 | MAX1363_CHAN_B(1, 0, d1m0, 3, bits), \ | ||
| 460 | IIO_CHAN_SOFT_TIMESTAMP(4) \ | ||
| 461 | } | ||
| 462 | |||
| 463 | static struct iio_chan_spec max11646_channels[] = MAX1363_2X_CHANS(10); | ||
| 464 | static struct iio_chan_spec max11644_channels[] = MAX1363_2X_CHANS(12); | ||
| 465 | |||
| 466 | enum { max1361, | ||
| 467 | max1362, | ||
| 468 | max1363, | ||
| 469 | max1364, | ||
| 470 | max1036, | ||
| 471 | max1037, | ||
| 472 | max1038, | ||
| 473 | max1039, | ||
| 474 | max1136, | ||
| 475 | max1137, | ||
| 476 | max1138, | ||
| 477 | max1139, | ||
| 478 | max1236, | ||
| 479 | max1237, | ||
| 480 | max1238, | ||
| 481 | max1239, | ||
| 482 | max11600, | ||
| 483 | max11601, | ||
| 484 | max11602, | ||
| 485 | max11603, | ||
| 486 | max11604, | ||
| 487 | max11605, | ||
| 488 | max11606, | ||
| 489 | max11607, | ||
| 490 | max11608, | ||
| 491 | max11609, | ||
| 492 | max11610, | ||
| 493 | max11611, | ||
| 494 | max11612, | ||
| 495 | max11613, | ||
| 496 | max11614, | ||
| 497 | max11615, | ||
| 498 | max11616, | ||
| 499 | max11617, | ||
| 500 | max11644, | ||
| 501 | max11645, | ||
| 502 | max11646, | ||
| 503 | max11647 | ||
| 504 | }; | ||
| 505 | |||
| 506 | static const int max1363_monitor_speeds[] = { 133000, 665000, 33300, 16600, | ||
| 507 | 8300, 4200, 2000, 1000 }; | ||
| 508 | |||
| 509 | static ssize_t max1363_monitor_show_freq(struct device *dev, | ||
| 510 | struct device_attribute *attr, | ||
| 511 | char *buf) | ||
| 512 | { | ||
| 513 | struct max1363_state *st = iio_priv(dev_get_drvdata(dev)); | ||
| 514 | return sprintf(buf, "%d\n", max1363_monitor_speeds[st->monitor_speed]); | ||
| 515 | } | ||
| 516 | |||
| 517 | static ssize_t max1363_monitor_store_freq(struct device *dev, | ||
| 518 | struct device_attribute *attr, | ||
| 519 | const char *buf, | ||
| 520 | size_t len) | ||
| 521 | { | ||
| 522 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 523 | struct max1363_state *st = iio_priv(indio_dev); | ||
| 524 | int i, ret; | ||
| 525 | unsigned long val; | ||
| 526 | bool found = false; | ||
| 527 | |||
| 528 | ret = strict_strtoul(buf, 10, &val); | ||
| 529 | if (ret) | ||
| 530 | return -EINVAL; | ||
| 531 | for (i = 0; i < ARRAY_SIZE(max1363_monitor_speeds); i++) | ||
| 532 | if (val == max1363_monitor_speeds[i]) { | ||
| 533 | found = true; | ||
| 534 | break; | ||
| 535 | } | ||
| 536 | if (!found) | ||
| 537 | return -EINVAL; | ||
| 538 | |||
| 539 | mutex_lock(&indio_dev->mlock); | ||
| 540 | st->monitor_speed = i; | ||
| 541 | mutex_unlock(&indio_dev->mlock); | ||
| 542 | |||
| 543 | return 0; | ||
| 544 | } | ||
| 545 | |||
| 546 | static IIO_DEV_ATTR_SAMP_FREQ(S_IRUGO | S_IWUSR, | ||
| 547 | max1363_monitor_show_freq, | ||
| 548 | max1363_monitor_store_freq); | ||
| 549 | |||
| 550 | static IIO_CONST_ATTR(sampling_frequency_available, | ||
| 551 | "133000 665000 33300 16600 8300 4200 2000 1000"); | ||
| 552 | |||
| 553 | static int max1363_read_thresh(struct iio_dev *indio_dev, | ||
| 554 | int event_code, | ||
| 555 | int *val) | ||
| 556 | { | ||
| 557 | struct max1363_state *st = iio_priv(indio_dev); | ||
| 558 | if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) | ||
| 559 | *val = st->thresh_low[IIO_EVENT_CODE_EXTRACT_NUM(event_code)]; | ||
| 560 | else | ||
| 561 | *val = st->thresh_high[IIO_EVENT_CODE_EXTRACT_NUM(event_code)]; | ||
| 562 | return 0; | ||
| 563 | } | ||
| 564 | |||
| 565 | static int max1363_write_thresh(struct iio_dev *indio_dev, | ||
| 566 | int event_code, | ||
| 567 | int val) | ||
| 568 | { | ||
| 569 | struct max1363_state *st = iio_priv(indio_dev); | ||
| 570 | /* make it handle signed correctly as well */ | ||
| 571 | switch (st->chip_info->bits) { | ||
| 572 | case 10: | ||
| 573 | if (val > 0x3FF) | ||
| 574 | return -EINVAL; | ||
| 575 | break; | ||
| 576 | case 12: | ||
| 577 | if (val > 0xFFF) | ||
| 578 | return -EINVAL; | ||
| 579 | break; | ||
| 580 | } | ||
| 581 | |||
| 582 | switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) { | ||
| 583 | case IIO_EV_DIR_FALLING: | ||
| 584 | st->thresh_low[IIO_EVENT_CODE_EXTRACT_NUM(event_code)] = val; | ||
| 585 | break; | ||
| 586 | case IIO_EV_DIR_RISING: | ||
| 587 | st->thresh_high[IIO_EVENT_CODE_EXTRACT_NUM(event_code)] = val; | ||
| 588 | break; | ||
| 589 | } | ||
| 590 | |||
| 591 | return 0; | ||
| 592 | } | ||
| 593 | |||
| 594 | static const int max1363_event_codes[] = { | ||
| 595 | IIO_EVENT_CODE_IN_LOW_THRESH(3), IIO_EVENT_CODE_IN_HIGH_THRESH(3), | ||
| 596 | IIO_EVENT_CODE_IN_LOW_THRESH(2), IIO_EVENT_CODE_IN_HIGH_THRESH(2), | ||
| 597 | IIO_EVENT_CODE_IN_LOW_THRESH(1), IIO_EVENT_CODE_IN_HIGH_THRESH(1), | ||
| 598 | IIO_EVENT_CODE_IN_LOW_THRESH(0), IIO_EVENT_CODE_IN_HIGH_THRESH(0) | ||
| 599 | }; | ||
| 600 | |||
| 601 | static irqreturn_t max1363_event_handler(int irq, void *private) | ||
| 602 | { | ||
| 603 | struct iio_dev *indio_dev = private; | ||
| 604 | struct max1363_state *st = iio_priv(indio_dev); | ||
| 605 | s64 timestamp = iio_get_time_ns(); | ||
| 606 | unsigned long mask, loc; | ||
| 607 | u8 rx; | ||
| 608 | u8 tx[2] = { st->setupbyte, | ||
| 609 | MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0 }; | ||
| 610 | |||
| 611 | i2c_master_recv(st->client, &rx, 1); | ||
| 612 | mask = rx; | ||
| 613 | for_each_set_bit(loc, &mask, 8) | ||
| 614 | iio_push_event(indio_dev, 0, max1363_event_codes[loc], | ||
| 615 | timestamp); | ||
| 616 | i2c_master_send(st->client, tx, 2); | ||
| 617 | |||
| 618 | return IRQ_HANDLED; | ||
| 619 | } | ||
| 620 | |||
| 621 | static int max1363_read_event_config(struct iio_dev *indio_dev, | ||
| 622 | int event_code) | ||
| 623 | { | ||
| 624 | struct max1363_state *st = iio_priv(indio_dev); | ||
| 625 | |||
| 626 | int val; | ||
| 627 | int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code); | ||
| 628 | mutex_lock(&indio_dev->mlock); | ||
| 629 | if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) | ||
| 630 | val = (1 << number) & st->mask_low; | ||
| 631 | else | ||
| 632 | val = (1 << number) & st->mask_high; | ||
| 633 | mutex_unlock(&indio_dev->mlock); | ||
| 634 | |||
| 635 | return val; | ||
| 636 | } | ||
| 637 | |||
| 638 | static int max1363_monitor_mode_update(struct max1363_state *st, int enabled) | ||
| 639 | { | ||
| 640 | u8 *tx_buf; | ||
| 641 | int ret, i = 3, j; | ||
| 642 | unsigned long numelements; | ||
| 643 | int len; | ||
| 644 | long modemask; | ||
| 645 | |||
| 646 | if (!enabled) { | ||
| 647 | /* transition to ring capture is not currently supported */ | ||
| 648 | st->setupbyte &= ~MAX1363_SETUP_MONITOR_SETUP; | ||
| 649 | st->configbyte &= ~MAX1363_SCAN_MASK; | ||
| 650 | st->monitor_on = false; | ||
| 651 | return max1363_write_basic_config(st->client, | ||
| 652 | st->setupbyte, | ||
| 653 | st->configbyte); | ||
| 654 | } | ||
| 655 | |||
| 656 | /* Ensure we are in the relevant mode */ | ||
| 657 | st->setupbyte |= MAX1363_SETUP_MONITOR_SETUP; | ||
| 658 | st->configbyte &= ~(MAX1363_CHANNEL_SEL_MASK | ||
| 659 | | MAX1363_SCAN_MASK | ||
| 660 | | MAX1363_SE_DE_MASK); | ||
| 661 | st->configbyte |= MAX1363_CONFIG_SCAN_MONITOR_MODE; | ||
| 662 | if ((st->mask_low | st->mask_high) & 0x0F) { | ||
| 663 | st->configbyte |= max1363_mode_table[s0to3].conf; | ||
| 664 | modemask = max1363_mode_table[s0to3].modemask; | ||
| 665 | } else if ((st->mask_low | st->mask_high) & 0x30) { | ||
| 666 | st->configbyte |= max1363_mode_table[d0m1to2m3].conf; | ||
| 667 | modemask = max1363_mode_table[d0m1to2m3].modemask; | ||
| 668 | } else { | ||
| 669 | st->configbyte |= max1363_mode_table[d1m0to3m2].conf; | ||
| 670 | modemask = max1363_mode_table[d1m0to3m2].modemask; | ||
| 671 | } | ||
| 672 | numelements = hweight_long(modemask); | ||
| 673 | len = 3 * numelements + 3; | ||
| 674 | tx_buf = kmalloc(len, GFP_KERNEL); | ||
| 675 | if (!tx_buf) { | ||
| 676 | ret = -ENOMEM; | ||
| 677 | goto error_ret; | ||
| 678 | } | ||
| 679 | tx_buf[0] = st->configbyte; | ||
| 680 | tx_buf[1] = st->setupbyte; | ||
| 681 | tx_buf[2] = (st->monitor_speed << 1); | ||
| 682 | |||
| 683 | /* | ||
| 684 | * So we need to do yet another bit of nefarious scan mode | ||
| 685 | * setup to match what we need. | ||
| 686 | */ | ||
| 687 | for (j = 0; j < 8; j++) | ||
| 688 | if (modemask & (1 << j)) { | ||
| 689 | /* Establish the mode is in the scan */ | ||
| 690 | if (st->mask_low & (1 << j)) { | ||
| 691 | tx_buf[i] = (st->thresh_low[j] >> 4) & 0xFF; | ||
| 692 | tx_buf[i + 1] = (st->thresh_low[j] << 4) & 0xF0; | ||
| 693 | } else if (j < 4) { | ||
| 694 | tx_buf[i] = 0; | ||
| 695 | tx_buf[i + 1] = 0; | ||
| 696 | } else { | ||
| 697 | tx_buf[i] = 0x80; | ||
| 698 | tx_buf[i + 1] = 0; | ||
| 699 | } | ||
| 700 | if (st->mask_high & (1 << j)) { | ||
| 701 | tx_buf[i + 1] |= | ||
| 702 | (st->thresh_high[j] >> 8) & 0x0F; | ||
| 703 | tx_buf[i + 2] = st->thresh_high[j] & 0xFF; | ||
| 704 | } else if (j < 4) { | ||
| 705 | tx_buf[i + 1] |= 0x0F; | ||
| 706 | tx_buf[i + 2] = 0xFF; | ||
| 707 | } else { | ||
| 708 | tx_buf[i + 1] |= 0x07; | ||
| 709 | tx_buf[i + 2] = 0xFF; | ||
| 710 | } | ||
| 711 | i += 3; | ||
| 712 | } | ||
| 713 | |||
| 714 | |||
| 715 | ret = i2c_master_send(st->client, tx_buf, len); | ||
| 716 | if (ret < 0) | ||
| 717 | goto error_ret; | ||
| 718 | if (ret != len) { | ||
| 719 | ret = -EIO; | ||
| 720 | goto error_ret; | ||
| 721 | } | ||
| 722 | |||
| 723 | /* | ||
| 724 | * Now that we hopefully have sensible thresholds in place it is | ||
| 725 | * time to turn the interrupts on. | ||
| 726 | * It is unclear from the data sheet if this should be necessary | ||
| 727 | * (i.e. whether monitor mode setup is atomic) but it appears to | ||
| 728 | * be in practice. | ||
| 729 | */ | ||
| 730 | tx_buf[0] = st->setupbyte; | ||
| 731 | tx_buf[1] = MAX1363_MON_INT_ENABLE | (st->monitor_speed << 1) | 0xF0; | ||
| 732 | ret = i2c_master_send(st->client, tx_buf, 2); | ||
| 733 | if (ret < 0) | ||
| 734 | goto error_ret; | ||
| 735 | if (ret != 2) { | ||
| 736 | ret = -EIO; | ||
| 737 | goto error_ret; | ||
| 738 | } | ||
| 739 | ret = 0; | ||
| 740 | st->monitor_on = true; | ||
| 741 | error_ret: | ||
| 742 | |||
| 743 | kfree(tx_buf); | ||
| 744 | |||
| 745 | return ret; | ||
| 746 | } | ||
| 747 | |||
| 748 | /* | ||
| 749 | * To keep this manageable we always use one of 3 scan modes. | ||
| 750 | * Scan 0...3, 0-1,2-3 and 1-0,3-2 | ||
| 751 | */ | ||
| 752 | |||
| 753 | static inline int __max1363_check_event_mask(int thismask, int checkmask) | ||
| 754 | { | ||
| 755 | int ret = 0; | ||
| 756 | /* Is it unipolar */ | ||
| 757 | if (thismask < 4) { | ||
| 758 | if (checkmask & ~0x0F) { | ||
| 759 | ret = -EBUSY; | ||
| 760 | goto error_ret; | ||
| 761 | } | ||
| 762 | } else if (thismask < 6) { | ||
| 763 | if (checkmask & ~0x30) { | ||
| 764 | ret = -EBUSY; | ||
| 765 | goto error_ret; | ||
| 766 | } | ||
| 767 | } else if (checkmask & ~0xC0) | ||
| 768 | ret = -EBUSY; | ||
| 769 | error_ret: | ||
| 770 | return ret; | ||
| 771 | } | ||
| 772 | |||
| 773 | static int max1363_write_event_config(struct iio_dev *indio_dev, | ||
| 774 | int event_code, | ||
| 775 | int state) | ||
| 776 | { | ||
| 777 | int ret = 0; | ||
| 778 | struct max1363_state *st = iio_priv(indio_dev); | ||
| 779 | u16 unifiedmask; | ||
| 780 | int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code); | ||
| 781 | |||
| 782 | mutex_lock(&indio_dev->mlock); | ||
| 783 | unifiedmask = st->mask_low | st->mask_high; | ||
| 784 | if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING) { | ||
| 785 | |||
| 786 | if (state == 0) | ||
| 787 | st->mask_low &= ~(1 << number); | ||
| 788 | else { | ||
| 789 | ret = __max1363_check_event_mask((1 << number), | ||
| 790 | unifiedmask); | ||
| 791 | if (ret) | ||
| 792 | goto error_ret; | ||
| 793 | st->mask_low |= (1 << number); | ||
| 794 | } | ||
| 795 | } else { | ||
| 796 | if (state == 0) | ||
| 797 | st->mask_high &= ~(1 << number); | ||
| 798 | else { | ||
| 799 | ret = __max1363_check_event_mask((1 << number), | ||
| 800 | unifiedmask); | ||
| 801 | if (ret) | ||
| 802 | goto error_ret; | ||
| 803 | st->mask_high |= (1 << number); | ||
| 804 | } | ||
| 805 | } | ||
| 806 | |||
| 807 | max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low)); | ||
| 808 | error_ret: | ||
| 809 | mutex_unlock(&indio_dev->mlock); | ||
| 810 | |||
| 811 | return ret; | ||
| 812 | } | ||
| 813 | |||
| 814 | /* | ||
| 815 | * As with scan_elements, only certain sets of these can | ||
| 816 | * be combined. | ||
| 817 | */ | ||
| 818 | static struct attribute *max1363_event_attributes[] = { | ||
| 819 | &iio_dev_attr_sampling_frequency.dev_attr.attr, | ||
| 820 | &iio_const_attr_sampling_frequency_available.dev_attr.attr, | ||
| 821 | NULL, | ||
| 822 | }; | ||
| 823 | |||
| 824 | static struct attribute_group max1363_event_attribute_group = { | ||
| 825 | .attrs = max1363_event_attributes, | ||
| 826 | }; | ||
| 827 | |||
| 828 | #define MAX1363_EVENT_FUNCS \ | ||
| 829 | |||
| 830 | |||
| 831 | static const struct iio_info max1238_info = { | ||
| 832 | .read_raw = &max1363_read_raw, | ||
| 833 | .driver_module = THIS_MODULE, | ||
| 834 | }; | ||
| 835 | |||
| 836 | static const struct iio_info max1363_info = { | ||
| 837 | .read_event_value = &max1363_read_thresh, | ||
| 838 | .write_event_value = &max1363_write_thresh, | ||
| 839 | .read_event_config = &max1363_read_event_config, | ||
| 840 | .write_event_config = &max1363_write_event_config, | ||
| 841 | .read_raw = &max1363_read_raw, | ||
| 842 | .driver_module = THIS_MODULE, | ||
| 843 | .num_interrupt_lines = 1, | ||
| 844 | .event_attrs = &max1363_event_attribute_group, | ||
| 845 | }; | ||
| 846 | |||
| 847 | /* max1363 and max1368 tested - rest from data sheet */ | ||
| 848 | static const struct max1363_chip_info max1363_chip_info_tbl[] = { | ||
| 849 | [max1361] = { | ||
| 850 | .bits = 10, | ||
| 851 | .int_vref_mv = 2048, | ||
| 852 | .mode_list = max1363_mode_list, | ||
| 853 | .num_modes = ARRAY_SIZE(max1363_mode_list), | ||
| 854 | .default_mode = s0to3, | ||
| 855 | .channels = max1361_channels, | ||
| 856 | .num_channels = ARRAY_SIZE(max1361_channels), | ||
| 857 | .info = &max1363_info, | ||
| 858 | }, | ||
| 859 | [max1362] = { | ||
| 860 | .bits = 10, | ||
| 861 | .int_vref_mv = 4096, | ||
| 862 | .mode_list = max1363_mode_list, | ||
| 863 | .num_modes = ARRAY_SIZE(max1363_mode_list), | ||
| 864 | .default_mode = s0to3, | ||
| 865 | .channels = max1361_channels, | ||
| 866 | .num_channels = ARRAY_SIZE(max1361_channels), | ||
| 867 | .info = &max1363_info, | ||
| 868 | }, | ||
| 869 | [max1363] = { | ||
| 870 | .bits = 12, | ||
| 871 | .int_vref_mv = 2048, | ||
| 872 | .mode_list = max1363_mode_list, | ||
| 873 | .num_modes = ARRAY_SIZE(max1363_mode_list), | ||
| 874 | .default_mode = s0to3, | ||
| 875 | .channels = max1363_channels, | ||
| 876 | .num_channels = ARRAY_SIZE(max1363_channels), | ||
| 877 | .info = &max1363_info, | ||
| 878 | }, | ||
| 879 | [max1364] = { | ||
| 880 | .bits = 12, | ||
| 881 | .int_vref_mv = 4096, | ||
| 882 | .mode_list = max1363_mode_list, | ||
| 883 | .num_modes = ARRAY_SIZE(max1363_mode_list), | ||
| 884 | .default_mode = s0to3, | ||
| 885 | .channels = max1363_channels, | ||
| 886 | .num_channels = ARRAY_SIZE(max1363_channels), | ||
| 887 | .info = &max1363_info, | ||
| 888 | }, | ||
| 889 | [max1036] = { | ||
| 890 | .bits = 8, | ||
| 891 | .int_vref_mv = 4096, | ||
| 892 | .mode_list = max1236_mode_list, | ||
| 893 | .num_modes = ARRAY_SIZE(max1236_mode_list), | ||
| 894 | .default_mode = s0to3, | ||
| 895 | .info = &max1238_info, | ||
| 896 | .channels = max1036_channels, | ||
| 897 | .num_channels = ARRAY_SIZE(max1036_channels), | ||
| 898 | }, | ||
| 899 | [max1037] = { | ||
| 900 | .bits = 8, | ||
| 901 | .int_vref_mv = 2048, | ||
| 902 | .mode_list = max1236_mode_list, | ||
| 903 | .num_modes = ARRAY_SIZE(max1236_mode_list), | ||
| 904 | .default_mode = s0to3, | ||
| 905 | .info = &max1238_info, | ||
| 906 | .channels = max1036_channels, | ||
| 907 | .num_channels = ARRAY_SIZE(max1036_channels), | ||
| 908 | }, | ||
| 909 | [max1038] = { | ||
| 910 | .bits = 8, | ||
| 911 | .int_vref_mv = 4096, | ||
| 912 | .mode_list = max1238_mode_list, | ||
| 913 | .num_modes = ARRAY_SIZE(max1238_mode_list), | ||
| 914 | .default_mode = s0to11, | ||
| 915 | .info = &max1238_info, | ||
| 916 | .channels = max1038_channels, | ||
| 917 | .num_channels = ARRAY_SIZE(max1038_channels), | ||
| 918 | }, | ||
| 919 | [max1039] = { | ||
| 920 | .bits = 8, | ||
| 921 | .int_vref_mv = 2048, | ||
| 922 | .mode_list = max1238_mode_list, | ||
| 923 | .num_modes = ARRAY_SIZE(max1238_mode_list), | ||
| 924 | .default_mode = s0to11, | ||
| 925 | .info = &max1238_info, | ||
| 926 | .channels = max1038_channels, | ||
| 927 | .num_channels = ARRAY_SIZE(max1038_channels), | ||
| 928 | }, | ||
| 929 | [max1136] = { | ||
| 930 | .bits = 10, | ||
| 931 | .int_vref_mv = 4096, | ||
| 932 | .mode_list = max1236_mode_list, | ||
| 933 | .num_modes = ARRAY_SIZE(max1236_mode_list), | ||
| 934 | .default_mode = s0to3, | ||
| 935 | .info = &max1238_info, | ||
| 936 | .channels = max1136_channels, | ||
| 937 | .num_channels = ARRAY_SIZE(max1136_channels), | ||
| 938 | }, | ||
| 939 | [max1137] = { | ||
| 940 | .bits = 10, | ||
| 941 | .int_vref_mv = 2048, | ||
| 942 | .mode_list = max1236_mode_list, | ||
| 943 | .num_modes = ARRAY_SIZE(max1236_mode_list), | ||
| 944 | .default_mode = s0to3, | ||
| 945 | .info = &max1238_info, | ||
| 946 | .channels = max1136_channels, | ||
| 947 | .num_channels = ARRAY_SIZE(max1136_channels), | ||
| 948 | }, | ||
| 949 | [max1138] = { | ||
| 950 | .bits = 10, | ||
| 951 | .int_vref_mv = 4096, | ||
| 952 | .mode_list = max1238_mode_list, | ||
| 953 | .num_modes = ARRAY_SIZE(max1238_mode_list), | ||
| 954 | .default_mode = s0to11, | ||
| 955 | .info = &max1238_info, | ||
| 956 | .channels = max1138_channels, | ||
| 957 | .num_channels = ARRAY_SIZE(max1138_channels), | ||
| 958 | }, | ||
| 959 | [max1139] = { | ||
| 960 | .bits = 10, | ||
| 961 | .int_vref_mv = 2048, | ||
| 962 | .mode_list = max1238_mode_list, | ||
| 963 | .num_modes = ARRAY_SIZE(max1238_mode_list), | ||
| 964 | .default_mode = s0to11, | ||
| 965 | .info = &max1238_info, | ||
| 966 | .channels = max1138_channels, | ||
| 967 | .num_channels = ARRAY_SIZE(max1138_channels), | ||
| 968 | }, | ||
| 969 | [max1236] = { | ||
| 970 | .bits = 12, | ||
| 971 | .int_vref_mv = 4096, | ||
| 972 | .mode_list = max1236_mode_list, | ||
| 973 | .num_modes = ARRAY_SIZE(max1236_mode_list), | ||
| 974 | .default_mode = s0to3, | ||
| 975 | .info = &max1238_info, | ||
| 976 | .channels = max1236_channels, | ||
| 977 | .num_channels = ARRAY_SIZE(max1236_channels), | ||
| 978 | }, | ||
| 979 | [max1237] = { | ||
| 980 | .bits = 12, | ||
| 981 | .int_vref_mv = 2048, | ||
| 982 | .mode_list = max1236_mode_list, | ||
| 983 | .num_modes = ARRAY_SIZE(max1236_mode_list), | ||
| 984 | .default_mode = s0to3, | ||
| 985 | .info = &max1238_info, | ||
| 986 | .channels = max1236_channels, | ||
| 987 | .num_channels = ARRAY_SIZE(max1236_channels), | ||
| 988 | }, | ||
| 989 | [max1238] = { | ||
| 990 | .bits = 12, | ||
| 991 | .int_vref_mv = 4096, | ||
| 992 | .mode_list = max1238_mode_list, | ||
| 993 | .num_modes = ARRAY_SIZE(max1238_mode_list), | ||
| 994 | .default_mode = s0to11, | ||
| 995 | .info = &max1238_info, | ||
| 996 | .channels = max1238_channels, | ||
| 997 | .num_channels = ARRAY_SIZE(max1238_channels), | ||
| 998 | }, | ||
| 999 | [max1239] = { | ||
| 1000 | .bits = 12, | ||
| 1001 | .int_vref_mv = 2048, | ||
| 1002 | .mode_list = max1238_mode_list, | ||
| 1003 | .num_modes = ARRAY_SIZE(max1238_mode_list), | ||
| 1004 | .default_mode = s0to11, | ||
| 1005 | .info = &max1238_info, | ||
| 1006 | .channels = max1238_channels, | ||
| 1007 | .num_channels = ARRAY_SIZE(max1238_channels), | ||
| 1008 | }, | ||
| 1009 | [max11600] = { | ||
| 1010 | .bits = 8, | ||
| 1011 | .int_vref_mv = 4096, | ||
| 1012 | .mode_list = max11607_mode_list, | ||
| 1013 | .num_modes = ARRAY_SIZE(max11607_mode_list), | ||
| 1014 | .default_mode = s0to3, | ||
| 1015 | .info = &max1238_info, | ||
| 1016 | .channels = max1036_channels, | ||
| 1017 | .num_channels = ARRAY_SIZE(max1036_channels), | ||
| 1018 | }, | ||
| 1019 | [max11601] = { | ||
| 1020 | .bits = 8, | ||
| 1021 | .int_vref_mv = 2048, | ||
| 1022 | .mode_list = max11607_mode_list, | ||
| 1023 | .num_modes = ARRAY_SIZE(max11607_mode_list), | ||
| 1024 | .default_mode = s0to3, | ||
| 1025 | .info = &max1238_info, | ||
| 1026 | .channels = max1036_channels, | ||
| 1027 | .num_channels = ARRAY_SIZE(max1036_channels), | ||
| 1028 | }, | ||
| 1029 | [max11602] = { | ||
| 1030 | .bits = 8, | ||
| 1031 | .int_vref_mv = 4096, | ||
| 1032 | .mode_list = max11608_mode_list, | ||
| 1033 | .num_modes = ARRAY_SIZE(max11608_mode_list), | ||
| 1034 | .default_mode = s0to7, | ||
| 1035 | .info = &max1238_info, | ||
| 1036 | .channels = max11602_channels, | ||
| 1037 | .num_channels = ARRAY_SIZE(max11602_channels), | ||
| 1038 | }, | ||
| 1039 | [max11603] = { | ||
| 1040 | .bits = 8, | ||
| 1041 | .int_vref_mv = 2048, | ||
| 1042 | .mode_list = max11608_mode_list, | ||
| 1043 | .num_modes = ARRAY_SIZE(max11608_mode_list), | ||
| 1044 | .default_mode = s0to7, | ||
| 1045 | .info = &max1238_info, | ||
| 1046 | .channels = max11602_channels, | ||
| 1047 | .num_channels = ARRAY_SIZE(max11602_channels), | ||
| 1048 | }, | ||
| 1049 | [max11604] = { | ||
| 1050 | .bits = 8, | ||
| 1051 | .int_vref_mv = 4098, | ||
| 1052 | .mode_list = max1238_mode_list, | ||
| 1053 | .num_modes = ARRAY_SIZE(max1238_mode_list), | ||
| 1054 | .default_mode = s0to11, | ||
| 1055 | .info = &max1238_info, | ||
| 1056 | .channels = max1238_channels, | ||
| 1057 | .num_channels = ARRAY_SIZE(max1238_channels), | ||
| 1058 | }, | ||
| 1059 | [max11605] = { | ||
| 1060 | .bits = 8, | ||
| 1061 | .int_vref_mv = 2048, | ||
| 1062 | .mode_list = max1238_mode_list, | ||
| 1063 | .num_modes = ARRAY_SIZE(max1238_mode_list), | ||
| 1064 | .default_mode = s0to11, | ||
| 1065 | .info = &max1238_info, | ||
| 1066 | .channels = max1238_channels, | ||
| 1067 | .num_channels = ARRAY_SIZE(max1238_channels), | ||
| 1068 | }, | ||
| 1069 | [max11606] = { | ||
| 1070 | .bits = 10, | ||
| 1071 | .int_vref_mv = 4096, | ||
| 1072 | .mode_list = max11607_mode_list, | ||
| 1073 | .num_modes = ARRAY_SIZE(max11607_mode_list), | ||
| 1074 | .default_mode = s0to3, | ||
| 1075 | .info = &max1238_info, | ||
| 1076 | .channels = max1136_channels, | ||
| 1077 | .num_channels = ARRAY_SIZE(max1136_channels), | ||
| 1078 | }, | ||
| 1079 | [max11607] = { | ||
| 1080 | .bits = 10, | ||
| 1081 | .int_vref_mv = 2048, | ||
| 1082 | .mode_list = max11607_mode_list, | ||
| 1083 | .num_modes = ARRAY_SIZE(max11607_mode_list), | ||
| 1084 | .default_mode = s0to3, | ||
| 1085 | .info = &max1238_info, | ||
| 1086 | .channels = max1136_channels, | ||
| 1087 | .num_channels = ARRAY_SIZE(max1136_channels), | ||
| 1088 | }, | ||
| 1089 | [max11608] = { | ||
| 1090 | .bits = 10, | ||
| 1091 | .int_vref_mv = 4096, | ||
| 1092 | .mode_list = max11608_mode_list, | ||
| 1093 | .num_modes = ARRAY_SIZE(max11608_mode_list), | ||
| 1094 | .default_mode = s0to7, | ||
| 1095 | .info = &max1238_info, | ||
| 1096 | .channels = max11608_channels, | ||
| 1097 | .num_channels = ARRAY_SIZE(max11608_channels), | ||
| 1098 | }, | ||
| 1099 | [max11609] = { | ||
| 1100 | .bits = 10, | ||
| 1101 | .int_vref_mv = 2048, | ||
| 1102 | .mode_list = max11608_mode_list, | ||
| 1103 | .num_modes = ARRAY_SIZE(max11608_mode_list), | ||
| 1104 | .default_mode = s0to7, | ||
| 1105 | .info = &max1238_info, | ||
| 1106 | .channels = max11608_channels, | ||
| 1107 | .num_channels = ARRAY_SIZE(max11608_channels), | ||
| 1108 | }, | ||
| 1109 | [max11610] = { | ||
| 1110 | .bits = 10, | ||
| 1111 | .int_vref_mv = 4098, | ||
| 1112 | .mode_list = max1238_mode_list, | ||
| 1113 | .num_modes = ARRAY_SIZE(max1238_mode_list), | ||
| 1114 | .default_mode = s0to11, | ||
| 1115 | .info = &max1238_info, | ||
| 1116 | .channels = max1238_channels, | ||
| 1117 | .num_channels = ARRAY_SIZE(max1238_channels), | ||
| 1118 | }, | ||
| 1119 | [max11611] = { | ||
| 1120 | .bits = 10, | ||
| 1121 | .int_vref_mv = 2048, | ||
| 1122 | .mode_list = max1238_mode_list, | ||
| 1123 | .num_modes = ARRAY_SIZE(max1238_mode_list), | ||
| 1124 | .default_mode = s0to11, | ||
| 1125 | .info = &max1238_info, | ||
| 1126 | .channels = max1238_channels, | ||
| 1127 | .num_channels = ARRAY_SIZE(max1238_channels), | ||
| 1128 | }, | ||
| 1129 | [max11612] = { | ||
| 1130 | .bits = 12, | ||
| 1131 | .int_vref_mv = 4096, | ||
| 1132 | .mode_list = max11607_mode_list, | ||
| 1133 | .num_modes = ARRAY_SIZE(max11607_mode_list), | ||
| 1134 | .default_mode = s0to3, | ||
| 1135 | .info = &max1238_info, | ||
| 1136 | .channels = max1363_channels, | ||
| 1137 | .num_channels = ARRAY_SIZE(max1363_channels), | ||
| 1138 | }, | ||
| 1139 | [max11613] = { | ||
| 1140 | .bits = 12, | ||
| 1141 | .int_vref_mv = 2048, | ||
| 1142 | .mode_list = max11607_mode_list, | ||
| 1143 | .num_modes = ARRAY_SIZE(max11607_mode_list), | ||
| 1144 | .default_mode = s0to3, | ||
| 1145 | .info = &max1238_info, | ||
| 1146 | .channels = max1363_channels, | ||
| 1147 | .num_channels = ARRAY_SIZE(max1363_channels), | ||
| 1148 | }, | ||
| 1149 | [max11614] = { | ||
| 1150 | .bits = 12, | ||
| 1151 | .int_vref_mv = 4096, | ||
| 1152 | .mode_list = max11608_mode_list, | ||
| 1153 | .num_modes = ARRAY_SIZE(max11608_mode_list), | ||
| 1154 | .default_mode = s0to7, | ||
| 1155 | .info = &max1238_info, | ||
| 1156 | .channels = max11614_channels, | ||
| 1157 | .num_channels = ARRAY_SIZE(max11614_channels), | ||
| 1158 | }, | ||
| 1159 | [max11615] = { | ||
| 1160 | .bits = 12, | ||
| 1161 | .int_vref_mv = 2048, | ||
| 1162 | .mode_list = max11608_mode_list, | ||
| 1163 | .num_modes = ARRAY_SIZE(max11608_mode_list), | ||
| 1164 | .default_mode = s0to7, | ||
| 1165 | .info = &max1238_info, | ||
| 1166 | .channels = max11614_channels, | ||
| 1167 | .num_channels = ARRAY_SIZE(max11614_channels), | ||
| 1168 | }, | ||
| 1169 | [max11616] = { | ||
| 1170 | .bits = 12, | ||
| 1171 | .int_vref_mv = 4098, | ||
| 1172 | .mode_list = max1238_mode_list, | ||
| 1173 | .num_modes = ARRAY_SIZE(max1238_mode_list), | ||
| 1174 | .default_mode = s0to11, | ||
| 1175 | .info = &max1238_info, | ||
| 1176 | .channels = max1238_channels, | ||
| 1177 | .num_channels = ARRAY_SIZE(max1238_channels), | ||
| 1178 | }, | ||
| 1179 | [max11617] = { | ||
| 1180 | .bits = 12, | ||
| 1181 | .int_vref_mv = 2048, | ||
| 1182 | .mode_list = max1238_mode_list, | ||
| 1183 | .num_modes = ARRAY_SIZE(max1238_mode_list), | ||
| 1184 | .default_mode = s0to11, | ||
| 1185 | .info = &max1238_info, | ||
| 1186 | .channels = max1238_channels, | ||
| 1187 | .num_channels = ARRAY_SIZE(max1238_channels), | ||
| 1188 | }, | ||
| 1189 | [max11644] = { | ||
| 1190 | .bits = 12, | ||
| 1191 | .int_vref_mv = 2048, | ||
| 1192 | .mode_list = max11644_mode_list, | ||
| 1193 | .num_modes = ARRAY_SIZE(max11644_mode_list), | ||
| 1194 | .default_mode = s0to1, | ||
| 1195 | .info = &max1238_info, | ||
| 1196 | .channels = max11644_channels, | ||
| 1197 | .num_channels = ARRAY_SIZE(max11644_channels), | ||
| 1198 | }, | ||
| 1199 | [max11645] = { | ||
| 1200 | .bits = 12, | ||
| 1201 | .int_vref_mv = 4096, | ||
| 1202 | .mode_list = max11644_mode_list, | ||
| 1203 | .num_modes = ARRAY_SIZE(max11644_mode_list), | ||
| 1204 | .default_mode = s0to1, | ||
| 1205 | .info = &max1238_info, | ||
| 1206 | .channels = max11644_channels, | ||
| 1207 | .num_channels = ARRAY_SIZE(max11644_channels), | ||
| 1208 | }, | ||
| 1209 | [max11646] = { | ||
| 1210 | .bits = 10, | ||
| 1211 | .int_vref_mv = 2048, | ||
| 1212 | .mode_list = max11644_mode_list, | ||
| 1213 | .num_modes = ARRAY_SIZE(max11644_mode_list), | ||
| 1214 | .default_mode = s0to1, | ||
| 1215 | .info = &max1238_info, | ||
| 1216 | .channels = max11646_channels, | ||
| 1217 | .num_channels = ARRAY_SIZE(max11646_channels), | ||
| 1218 | }, | ||
| 1219 | [max11647] = { | ||
| 1220 | .bits = 10, | ||
| 1221 | .int_vref_mv = 4096, | ||
| 1222 | .mode_list = max11644_mode_list, | ||
| 1223 | .num_modes = ARRAY_SIZE(max11644_mode_list), | ||
| 1224 | .default_mode = s0to1, | ||
| 1225 | .info = &max1238_info, | ||
| 1226 | .channels = max11646_channels, | ||
| 1227 | .num_channels = ARRAY_SIZE(max11646_channels), | ||
| 1228 | }, | ||
| 1229 | }; | ||
| 1230 | |||
| 1231 | |||
| 1232 | |||
| 1233 | static int max1363_initial_setup(struct max1363_state *st) | ||
| 1234 | { | ||
| 1235 | st->setupbyte = MAX1363_SETUP_AIN3_IS_AIN3_REF_IS_VDD | ||
| 1236 | | MAX1363_SETUP_POWER_UP_INT_REF | ||
| 1237 | | MAX1363_SETUP_INT_CLOCK | ||
| 1238 | | MAX1363_SETUP_UNIPOLAR | ||
| 1239 | | MAX1363_SETUP_NORESET; | ||
| 1240 | |||
| 1241 | /* Set scan mode writes the config anyway so wait until then*/ | ||
| 1242 | st->setupbyte = MAX1363_SETUP_BYTE(st->setupbyte); | ||
| 1243 | st->current_mode = &max1363_mode_table[st->chip_info->default_mode]; | ||
| 1244 | st->configbyte = MAX1363_CONFIG_BYTE(st->configbyte); | ||
| 1245 | |||
| 1246 | return max1363_set_scan_mode(st); | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | static int __devinit max1363_probe(struct i2c_client *client, | ||
| 1250 | const struct i2c_device_id *id) | ||
| 1251 | { | ||
| 1252 | int ret, i, regdone = 0; | ||
| 1253 | struct max1363_state *st; | ||
| 1254 | struct iio_dev *indio_dev; | ||
| 1255 | struct regulator *reg; | ||
| 1256 | |||
| 1257 | reg = regulator_get(&client->dev, "vcc"); | ||
| 1258 | if (IS_ERR(reg)) { | ||
| 1259 | ret = PTR_ERR(reg); | ||
| 1260 | goto error_out; | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | ret = regulator_enable(reg); | ||
| 1264 | if (ret) | ||
| 1265 | goto error_put_reg; | ||
| 1266 | |||
| 1267 | indio_dev = iio_allocate_device(sizeof(struct max1363_state)); | ||
| 1268 | if (indio_dev == NULL) { | ||
| 1269 | ret = -ENOMEM; | ||
| 1270 | goto error_disable_reg; | ||
| 1271 | } | ||
| 1272 | st = iio_priv(indio_dev); | ||
| 1273 | st->reg = reg; | ||
| 1274 | /* this is only used for device removal purposes */ | ||
| 1275 | i2c_set_clientdata(client, indio_dev); | ||
| 1276 | |||
| 1277 | st->chip_info = &max1363_chip_info_tbl[id->driver_data]; | ||
| 1278 | st->client = client; | ||
| 1279 | |||
| 1280 | indio_dev->available_scan_masks | ||
| 1281 | = kzalloc(sizeof(*indio_dev->available_scan_masks)* | ||
| 1282 | (st->chip_info->num_modes + 1), GFP_KERNEL); | ||
| 1283 | if (!indio_dev->available_scan_masks) { | ||
| 1284 | ret = -ENOMEM; | ||
| 1285 | goto error_free_device; | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | for (i = 0; i < st->chip_info->num_modes; i++) | ||
| 1289 | indio_dev->available_scan_masks[i] = | ||
| 1290 | max1363_mode_table[st->chip_info->mode_list[i]] | ||
| 1291 | .modemask; | ||
| 1292 | /* Estabilish that the iio_dev is a child of the i2c device */ | ||
| 1293 | indio_dev->dev.parent = &client->dev; | ||
| 1294 | indio_dev->name = id->name; | ||
| 1295 | |||
| 1296 | indio_dev->info = st->chip_info->info; | ||
| 1297 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 1298 | ret = max1363_initial_setup(st); | ||
| 1299 | if (ret < 0) | ||
| 1300 | goto error_free_available_scan_masks; | ||
| 1301 | |||
| 1302 | ret = max1363_register_ring_funcs_and_init(indio_dev); | ||
| 1303 | if (ret) | ||
| 1304 | goto error_free_available_scan_masks; | ||
| 1305 | |||
| 1306 | ret = iio_device_register(indio_dev); | ||
| 1307 | if (ret) | ||
| 1308 | goto error_cleanup_ring; | ||
| 1309 | regdone = 1; | ||
| 1310 | ret = iio_ring_buffer_register_ex(indio_dev->ring, 0, | ||
| 1311 | st->chip_info->channels, | ||
| 1312 | st->chip_info->num_channels); | ||
| 1313 | if (ret) | ||
| 1314 | goto error_cleanup_ring; | ||
| 1315 | |||
| 1316 | if (client->irq) { | ||
| 1317 | ret = request_threaded_irq(st->client->irq, | ||
| 1318 | NULL, | ||
| 1319 | &max1363_event_handler, | ||
| 1320 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | ||
| 1321 | "max1363_event", | ||
| 1322 | indio_dev); | ||
| 1323 | |||
| 1324 | if (ret) | ||
| 1325 | goto error_uninit_ring; | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | return 0; | ||
| 1329 | |||
| 1330 | error_uninit_ring: | ||
| 1331 | iio_ring_buffer_unregister(indio_dev->ring); | ||
| 1332 | error_cleanup_ring: | ||
| 1333 | max1363_ring_cleanup(indio_dev); | ||
| 1334 | error_free_available_scan_masks: | ||
| 1335 | kfree(indio_dev->available_scan_masks); | ||
| 1336 | error_free_device: | ||
| 1337 | if (!regdone) | ||
| 1338 | iio_free_device(indio_dev); | ||
| 1339 | else | ||
| 1340 | iio_device_unregister(indio_dev); | ||
| 1341 | error_disable_reg: | ||
| 1342 | regulator_disable(reg); | ||
| 1343 | error_put_reg: | ||
| 1344 | regulator_put(reg); | ||
| 1345 | error_out: | ||
| 1346 | return ret; | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | static int max1363_remove(struct i2c_client *client) | ||
| 1350 | { | ||
| 1351 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | ||
| 1352 | struct max1363_state *st = iio_priv(indio_dev); | ||
| 1353 | struct regulator *reg = st->reg; | ||
| 1354 | |||
| 1355 | if (client->irq) | ||
| 1356 | free_irq(st->client->irq, indio_dev); | ||
| 1357 | iio_ring_buffer_unregister(indio_dev->ring); | ||
| 1358 | max1363_ring_cleanup(indio_dev); | ||
| 1359 | kfree(indio_dev->available_scan_masks); | ||
| 1360 | if (!IS_ERR(reg)) { | ||
| 1361 | regulator_disable(reg); | ||
| 1362 | regulator_put(reg); | ||
| 1363 | } | ||
| 1364 | iio_device_unregister(indio_dev); | ||
| 1365 | |||
| 1366 | return 0; | ||
| 1367 | } | ||
| 1368 | |||
| 1369 | static const struct i2c_device_id max1363_id[] = { | ||
| 1370 | { "max1361", max1361 }, | ||
| 1371 | { "max1362", max1362 }, | ||
| 1372 | { "max1363", max1363 }, | ||
| 1373 | { "max1364", max1364 }, | ||
| 1374 | { "max1036", max1036 }, | ||
| 1375 | { "max1037", max1037 }, | ||
| 1376 | { "max1038", max1038 }, | ||
| 1377 | { "max1039", max1039 }, | ||
| 1378 | { "max1136", max1136 }, | ||
| 1379 | { "max1137", max1137 }, | ||
| 1380 | { "max1138", max1138 }, | ||
| 1381 | { "max1139", max1139 }, | ||
| 1382 | { "max1236", max1236 }, | ||
| 1383 | { "max1237", max1237 }, | ||
| 1384 | { "max1238", max1238 }, | ||
| 1385 | { "max1239", max1239 }, | ||
| 1386 | { "max11600", max11600 }, | ||
| 1387 | { "max11601", max11601 }, | ||
| 1388 | { "max11602", max11602 }, | ||
| 1389 | { "max11603", max11603 }, | ||
| 1390 | { "max11604", max11604 }, | ||
| 1391 | { "max11605", max11605 }, | ||
| 1392 | { "max11606", max11606 }, | ||
| 1393 | { "max11607", max11607 }, | ||
| 1394 | { "max11608", max11608 }, | ||
| 1395 | { "max11609", max11609 }, | ||
| 1396 | { "max11610", max11610 }, | ||
| 1397 | { "max11611", max11611 }, | ||
| 1398 | { "max11612", max11612 }, | ||
| 1399 | { "max11613", max11613 }, | ||
| 1400 | { "max11614", max11614 }, | ||
| 1401 | { "max11615", max11615 }, | ||
| 1402 | { "max11616", max11616 }, | ||
| 1403 | { "max11617", max11617 }, | ||
| 1404 | {} | ||
| 1405 | }; | ||
| 1406 | |||
| 1407 | MODULE_DEVICE_TABLE(i2c, max1363_id); | ||
| 1408 | |||
| 1409 | static struct i2c_driver max1363_driver = { | ||
| 1410 | .driver = { | ||
| 1411 | .name = "max1363", | ||
| 1412 | }, | ||
| 1413 | .probe = max1363_probe, | ||
| 1414 | .remove = max1363_remove, | ||
| 1415 | .id_table = max1363_id, | ||
| 1416 | }; | ||
| 1417 | |||
| 1418 | static __init int max1363_init(void) | ||
| 1419 | { | ||
| 1420 | return i2c_add_driver(&max1363_driver); | ||
| 1421 | } | ||
| 1422 | |||
| 1423 | static __exit void max1363_exit(void) | ||
| 1424 | { | ||
| 1425 | i2c_del_driver(&max1363_driver); | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); | ||
| 1429 | MODULE_DESCRIPTION("Maxim 1363 ADC"); | ||
| 1430 | MODULE_LICENSE("GPL v2"); | ||
| 1431 | |||
| 1432 | module_init(max1363_init); | ||
| 1433 | module_exit(max1363_exit); | ||
diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c new file mode 100644 index 00000000000..f43befd1f77 --- /dev/null +++ b/drivers/staging/iio/adc/max1363_ring.c | |||
| @@ -0,0 +1,209 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008 Jonathan Cameron | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * max1363_ring.c | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/interrupt.h> | ||
| 12 | #include <linux/device.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/sysfs.h> | ||
| 16 | #include <linux/list.h> | ||
| 17 | #include <linux/i2c.h> | ||
| 18 | #include <linux/bitops.h> | ||
| 19 | |||
| 20 | #include "../iio.h" | ||
| 21 | #include "../ring_generic.h" | ||
| 22 | #include "../ring_sw.h" | ||
| 23 | #include "../trigger.h" | ||
| 24 | #include "../sysfs.h" | ||
| 25 | |||
| 26 | #include "max1363.h" | ||
| 27 | |||
| 28 | int max1363_single_channel_from_ring(long mask, struct max1363_state *st) | ||
| 29 | { | ||
| 30 | struct iio_ring_buffer *ring = iio_priv_to_dev(st)->ring; | ||
| 31 | int count = 0, ret; | ||
| 32 | u8 *ring_data; | ||
| 33 | if (!(st->current_mode->modemask & mask)) { | ||
| 34 | ret = -EBUSY; | ||
| 35 | goto error_ret; | ||
| 36 | } | ||
| 37 | |||
| 38 | ring_data = kmalloc(ring->access->get_bytes_per_datum(ring), | ||
| 39 | GFP_KERNEL); | ||
| 40 | if (ring_data == NULL) { | ||
| 41 | ret = -ENOMEM; | ||
| 42 | goto error_ret; | ||
| 43 | } | ||
| 44 | ret = ring->access->read_last(ring, ring_data); | ||
| 45 | if (ret) | ||
| 46 | goto error_free_ring_data; | ||
| 47 | /* Need a count of channels prior to this one */ | ||
| 48 | mask >>= 1; | ||
| 49 | while (mask) { | ||
| 50 | if (mask & st->current_mode->modemask) | ||
| 51 | count++; | ||
| 52 | mask >>= 1; | ||
| 53 | } | ||
| 54 | if (st->chip_info->bits != 8) | ||
| 55 | ret = ((int)(ring_data[count*2 + 0] & 0x0F) << 8) | ||
| 56 | + (int)(ring_data[count*2 + 1]); | ||
| 57 | else | ||
| 58 | ret = ring_data[count]; | ||
| 59 | |||
| 60 | error_free_ring_data: | ||
| 61 | kfree(ring_data); | ||
| 62 | error_ret: | ||
| 63 | return ret; | ||
| 64 | } | ||
| 65 | |||
| 66 | |||
| 67 | /** | ||
| 68 | * max1363_ring_preenable() - setup the parameters of the ring before enabling | ||
| 69 | * | ||
| 70 | * The complex nature of the setting of the nuber of bytes per datum is due | ||
| 71 | * to this driver currently ensuring that the timestamp is stored at an 8 | ||
| 72 | * byte boundary. | ||
| 73 | **/ | ||
| 74 | static int max1363_ring_preenable(struct iio_dev *indio_dev) | ||
| 75 | { | ||
| 76 | struct max1363_state *st = iio_priv(indio_dev); | ||
| 77 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 78 | size_t d_size = 0; | ||
| 79 | unsigned long numvals; | ||
| 80 | |||
| 81 | /* | ||
| 82 | * Need to figure out the current mode based upon the requested | ||
| 83 | * scan mask in iio_dev | ||
| 84 | */ | ||
| 85 | st->current_mode = max1363_match_mode(ring->scan_mask, | ||
| 86 | st->chip_info); | ||
| 87 | if (!st->current_mode) | ||
| 88 | return -EINVAL; | ||
| 89 | |||
| 90 | max1363_set_scan_mode(st); | ||
| 91 | |||
| 92 | numvals = hweight_long(st->current_mode->modemask); | ||
| 93 | if (ring->access->set_bytes_per_datum) { | ||
| 94 | if (ring->scan_timestamp) | ||
| 95 | d_size += sizeof(s64); | ||
| 96 | if (st->chip_info->bits != 8) | ||
| 97 | d_size += numvals*2; | ||
| 98 | else | ||
| 99 | d_size += numvals; | ||
| 100 | if (ring->scan_timestamp && (d_size % 8)) | ||
| 101 | d_size += 8 - (d_size % 8); | ||
| 102 | ring->access->set_bytes_per_datum(ring, d_size); | ||
| 103 | } | ||
| 104 | |||
| 105 | return 0; | ||
| 106 | } | ||
| 107 | |||
| 108 | static irqreturn_t max1363_trigger_handler(int irq, void *p) | ||
| 109 | { | ||
| 110 | struct iio_poll_func *pf = p; | ||
| 111 | struct iio_dev *indio_dev = pf->private_data; | ||
| 112 | struct max1363_state *st = iio_priv(indio_dev); | ||
| 113 | s64 time_ns; | ||
| 114 | __u8 *rxbuf; | ||
| 115 | int b_sent; | ||
| 116 | size_t d_size; | ||
| 117 | unsigned long numvals = hweight_long(st->current_mode->modemask); | ||
| 118 | |||
| 119 | /* Ensure the timestamp is 8 byte aligned */ | ||
| 120 | if (st->chip_info->bits != 8) | ||
| 121 | d_size = numvals*2 + sizeof(s64); | ||
| 122 | else | ||
| 123 | d_size = numvals + sizeof(s64); | ||
| 124 | if (d_size % sizeof(s64)) | ||
| 125 | d_size += sizeof(s64) - (d_size % sizeof(s64)); | ||
| 126 | |||
| 127 | /* Monitor mode prevents reading. Whilst not currently implemented | ||
| 128 | * might as well have this test in here in the meantime as it does | ||
| 129 | * no harm. | ||
| 130 | */ | ||
| 131 | if (numvals == 0) | ||
| 132 | return IRQ_HANDLED; | ||
| 133 | |||
| 134 | rxbuf = kmalloc(d_size, GFP_KERNEL); | ||
| 135 | if (rxbuf == NULL) | ||
| 136 | return -ENOMEM; | ||
| 137 | if (st->chip_info->bits != 8) | ||
| 138 | b_sent = i2c_master_recv(st->client, rxbuf, numvals*2); | ||
| 139 | else | ||
| 140 | b_sent = i2c_master_recv(st->client, rxbuf, numvals); | ||
| 141 | if (b_sent < 0) | ||
| 142 | goto done; | ||
| 143 | |||
| 144 | time_ns = iio_get_time_ns(); | ||
| 145 | |||
| 146 | memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); | ||
| 147 | |||
| 148 | indio_dev->ring->access->store_to(indio_dev->ring, rxbuf, time_ns); | ||
| 149 | done: | ||
| 150 | iio_trigger_notify_done(indio_dev->trig); | ||
| 151 | kfree(rxbuf); | ||
| 152 | |||
| 153 | return IRQ_HANDLED; | ||
| 154 | } | ||
| 155 | |||
| 156 | static const struct iio_ring_setup_ops max1363_ring_setup_ops = { | ||
| 157 | .postenable = &iio_triggered_ring_postenable, | ||
| 158 | .preenable = &max1363_ring_preenable, | ||
| 159 | .predisable = &iio_triggered_ring_predisable, | ||
| 160 | }; | ||
| 161 | |||
| 162 | int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev) | ||
| 163 | { | ||
| 164 | struct max1363_state *st = iio_priv(indio_dev); | ||
| 165 | int ret = 0; | ||
| 166 | |||
| 167 | indio_dev->ring = iio_sw_rb_allocate(indio_dev); | ||
| 168 | if (!indio_dev->ring) { | ||
| 169 | ret = -ENOMEM; | ||
| 170 | goto error_ret; | ||
| 171 | } | ||
| 172 | indio_dev->pollfunc = iio_alloc_pollfunc(NULL, | ||
| 173 | &max1363_trigger_handler, | ||
| 174 | IRQF_ONESHOT, | ||
| 175 | indio_dev, | ||
| 176 | "%s_consumer%d", | ||
| 177 | st->client->name, | ||
| 178 | indio_dev->id); | ||
| 179 | if (indio_dev->pollfunc == NULL) { | ||
| 180 | ret = -ENOMEM; | ||
| 181 | goto error_deallocate_sw_rb; | ||
| 182 | } | ||
| 183 | /* Effectively select the ring buffer implementation */ | ||
| 184 | indio_dev->ring->access = &ring_sw_access_funcs; | ||
| 185 | /* Ring buffer functions - here trigger setup related */ | ||
| 186 | indio_dev->ring->setup_ops = &max1363_ring_setup_ops; | ||
| 187 | |||
| 188 | /* Flag that polled ring buffering is possible */ | ||
| 189 | indio_dev->modes |= INDIO_RING_TRIGGERED; | ||
| 190 | |||
| 191 | return 0; | ||
| 192 | |||
| 193 | error_deallocate_sw_rb: | ||
| 194 | iio_sw_rb_free(indio_dev->ring); | ||
| 195 | error_ret: | ||
| 196 | return ret; | ||
| 197 | } | ||
| 198 | |||
| 199 | void max1363_ring_cleanup(struct iio_dev *indio_dev) | ||
| 200 | { | ||
| 201 | /* ensure that the trigger has been detached */ | ||
| 202 | if (indio_dev->trig) { | ||
| 203 | iio_put_trigger(indio_dev->trig); | ||
| 204 | iio_trigger_dettach_poll_func(indio_dev->trig, | ||
| 205 | indio_dev->pollfunc); | ||
| 206 | } | ||
| 207 | iio_dealloc_pollfunc(indio_dev->pollfunc); | ||
| 208 | iio_sw_rb_free(indio_dev->ring); | ||
| 209 | } | ||
diff --git a/drivers/staging/iio/chrdev.h b/drivers/staging/iio/chrdev.h new file mode 100644 index 00000000000..3e31ee6220e --- /dev/null +++ b/drivers/staging/iio/chrdev.h | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | /* The industrial I/O core - character device related | ||
| 2 | * | ||
| 3 | * Copyright (c) 2008 Jonathan Cameron | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 as published by | ||
| 7 | * the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef _IIO_CHRDEV_H_ | ||
| 11 | #define _IIO_CHRDEV_H_ | ||
| 12 | struct iio_dev; | ||
| 13 | |||
| 14 | /** | ||
| 15 | * struct iio_handler - Structure used to specify file operations | ||
| 16 | * for a particular chrdev | ||
| 17 | * @chrdev: character device structure | ||
| 18 | * @id: the location in the handler table - used for deallocation. | ||
| 19 | * @flags: file operations related flags including busy flag. | ||
| 20 | * @private: handler specific data used by the fileops registered with | ||
| 21 | * the chrdev. | ||
| 22 | */ | ||
| 23 | struct iio_handler { | ||
| 24 | struct cdev chrdev; | ||
| 25 | int id; | ||
| 26 | unsigned long flags; | ||
| 27 | void *private; | ||
| 28 | }; | ||
| 29 | |||
| 30 | #define iio_cdev_to_handler(cd) \ | ||
| 31 | container_of(cd, struct iio_handler, chrdev) | ||
| 32 | |||
| 33 | /** | ||
| 34 | * struct iio_event_data - The actual event being pushed to userspace | ||
| 35 | * @id: event identifier | ||
| 36 | * @timestamp: best estimate of time of event occurrence (often from | ||
| 37 | * the interrupt handler) | ||
| 38 | */ | ||
| 39 | struct iio_event_data { | ||
| 40 | int id; | ||
| 41 | s64 timestamp; | ||
| 42 | }; | ||
| 43 | |||
| 44 | /** | ||
| 45 | * struct iio_detected_event_list - list element for events that have occurred | ||
| 46 | * @list: linked list header | ||
| 47 | * @ev: the event itself | ||
| 48 | */ | ||
| 49 | struct iio_detected_event_list { | ||
| 50 | struct list_head list; | ||
| 51 | struct iio_event_data ev; | ||
| 52 | }; | ||
| 53 | |||
| 54 | /** | ||
| 55 | * struct iio_event_interface - chrdev interface for an event line | ||
| 56 | * @dev: device assocated with event interface | ||
| 57 | * @handler: fileoperations and related control for the chrdev | ||
| 58 | * @wait: wait queue to allow blocking reads of events | ||
| 59 | * @event_list_lock: mutex to protect the list of detected events | ||
| 60 | * @det_events: list of detected events | ||
| 61 | * @max_events: maximum number of events before new ones are dropped | ||
| 62 | * @current_events: number of events in detected list | ||
| 63 | */ | ||
| 64 | struct iio_event_interface { | ||
| 65 | struct device dev; | ||
| 66 | struct iio_handler handler; | ||
| 67 | wait_queue_head_t wait; | ||
| 68 | struct mutex event_list_lock; | ||
| 69 | struct list_head det_events; | ||
| 70 | int max_events; | ||
| 71 | int current_events; | ||
| 72 | struct list_head dev_attr_list; | ||
| 73 | }; | ||
| 74 | |||
| 75 | #endif | ||
diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig new file mode 100644 index 00000000000..7ddae357f20 --- /dev/null +++ b/drivers/staging/iio/dac/Kconfig | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | # | ||
| 2 | # DAC drivers | ||
| 3 | # | ||
| 4 | comment "Digital to analog convertors" | ||
| 5 | |||
| 6 | config AD5624R_SPI | ||
| 7 | tristate "Analog Devices AD5624/44/64R DAC spi driver" | ||
| 8 | depends on SPI | ||
| 9 | help | ||
| 10 | Say yes here to build support for Analog Devices AD5624R, AD5644R and | ||
| 11 | AD5664R convertors (DAC). This driver uses the common SPI interface. | ||
| 12 | |||
| 13 | config AD5446 | ||
| 14 | tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5542A/12A DAC SPI driver" | ||
| 15 | depends on SPI | ||
| 16 | help | ||
| 17 | Say yes here to build support for Analog Devices AD5444, AD5446, | ||
| 18 | AD5512A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620, AD5621, | ||
| 19 | AD5640, AD5660 DACs. | ||
| 20 | |||
| 21 | To compile this driver as a module, choose M here: the | ||
| 22 | module will be called ad5446. | ||
| 23 | |||
| 24 | config AD5504 | ||
| 25 | tristate "Analog Devices AD5504/AD5501 DAC SPI driver" | ||
| 26 | depends on SPI | ||
| 27 | help | ||
| 28 | Say yes here to build support for Analog Devices AD5504, AD5501, | ||
| 29 | High Voltage Digital to Analog Converter. | ||
| 30 | |||
| 31 | To compile this driver as a module, choose M here: the | ||
| 32 | module will be called ad5504. | ||
| 33 | |||
| 34 | config AD5791 | ||
| 35 | tristate "Analog Devices AD5760/AD5780/AD5781/AD5791 DAC SPI driver" | ||
| 36 | depends on SPI | ||
| 37 | help | ||
| 38 | Say yes here to build support for Analog Devices AD5760, AD5780, | ||
| 39 | AD5781, AD5791 High Resolution Voltage Output Digital to | ||
| 40 | Analog Converter. | ||
| 41 | |||
| 42 | To compile this driver as a module, choose M here: the | ||
| 43 | module will be called ad5791. | ||
| 44 | |||
| 45 | config AD5686 | ||
| 46 | tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver" | ||
| 47 | depends on SPI | ||
| 48 | help | ||
| 49 | Say yes here to build support for Analog Devices AD5686R, AD5685R, | ||
| 50 | AD5684R, AD5791 Voltage Output Digital to | ||
| 51 | Analog Converter. | ||
| 52 | |||
| 53 | To compile this driver as a module, choose M here: the | ||
| 54 | module will be called ad5686. | ||
| 55 | |||
| 56 | config MAX517 | ||
| 57 | tristate "Maxim MAX517/518/519 DAC driver" | ||
| 58 | depends on I2C && EXPERIMENTAL | ||
| 59 | help | ||
| 60 | If you say yes here you get support for the Maxim chips MAX517, | ||
| 61 | MAX518 and MAX519 (I2C 8-Bit DACs with rail-to-rail outputs). | ||
| 62 | |||
| 63 | This driver can also be built as a module. If so, the module | ||
| 64 | will be called max517. | ||
diff --git a/drivers/staging/iio/dac/Makefile b/drivers/staging/iio/dac/Makefile new file mode 100644 index 00000000000..7f4f2ed031e --- /dev/null +++ b/drivers/staging/iio/dac/Makefile | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | # | ||
| 2 | # Makefile for industrial I/O DAC drivers | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o | ||
| 6 | obj-$(CONFIG_AD5504) += ad5504.o | ||
| 7 | obj-$(CONFIG_AD5446) += ad5446.o | ||
| 8 | obj-$(CONFIG_AD5791) += ad5791.o | ||
| 9 | obj-$(CONFIG_AD5686) += ad5686.o | ||
| 10 | obj-$(CONFIG_MAX517) += max517.o | ||
diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c new file mode 100644 index 00000000000..e8a9d0bf1ed --- /dev/null +++ b/drivers/staging/iio/dac/ad5446.c | |||
| @@ -0,0 +1,480 @@ | |||
| 1 | /* | ||
| 2 | * AD5446 SPI DAC driver | ||
| 3 | * | ||
| 4 | * Copyright 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/workqueue.h> | ||
| 11 | #include <linux/device.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/sysfs.h> | ||
| 15 | #include <linux/list.h> | ||
| 16 | #include <linux/spi/spi.h> | ||
| 17 | #include <linux/regulator/consumer.h> | ||
| 18 | #include <linux/err.h> | ||
| 19 | |||
| 20 | #include "../iio.h" | ||
| 21 | #include "../sysfs.h" | ||
| 22 | #include "dac.h" | ||
| 23 | |||
| 24 | #include "ad5446.h" | ||
| 25 | |||
| 26 | static void ad5446_store_sample(struct ad5446_state *st, unsigned val) | ||
| 27 | { | ||
| 28 | st->data.d16 = cpu_to_be16(AD5446_LOAD | | ||
| 29 | (val << st->chip_info->left_shift)); | ||
| 30 | } | ||
| 31 | |||
| 32 | static void ad5542_store_sample(struct ad5446_state *st, unsigned val) | ||
| 33 | { | ||
| 34 | st->data.d16 = cpu_to_be16(val << st->chip_info->left_shift); | ||
| 35 | } | ||
| 36 | |||
| 37 | static void ad5620_store_sample(struct ad5446_state *st, unsigned val) | ||
| 38 | { | ||
| 39 | st->data.d16 = cpu_to_be16(AD5620_LOAD | | ||
| 40 | (val << st->chip_info->left_shift)); | ||
| 41 | } | ||
| 42 | |||
| 43 | static void ad5660_store_sample(struct ad5446_state *st, unsigned val) | ||
| 44 | { | ||
| 45 | val |= AD5660_LOAD; | ||
| 46 | st->data.d24[0] = (val >> 16) & 0xFF; | ||
| 47 | st->data.d24[1] = (val >> 8) & 0xFF; | ||
| 48 | st->data.d24[2] = val & 0xFF; | ||
| 49 | } | ||
| 50 | |||
| 51 | static void ad5620_store_pwr_down(struct ad5446_state *st, unsigned mode) | ||
| 52 | { | ||
| 53 | st->data.d16 = cpu_to_be16(mode << 14); | ||
| 54 | } | ||
| 55 | |||
| 56 | static void ad5660_store_pwr_down(struct ad5446_state *st, unsigned mode) | ||
| 57 | { | ||
| 58 | unsigned val = mode << 16; | ||
| 59 | |||
| 60 | st->data.d24[0] = (val >> 16) & 0xFF; | ||
| 61 | st->data.d24[1] = (val >> 8) & 0xFF; | ||
| 62 | st->data.d24[2] = val & 0xFF; | ||
| 63 | } | ||
| 64 | |||
| 65 | static ssize_t ad5446_write(struct device *dev, | ||
| 66 | struct device_attribute *attr, | ||
| 67 | const char *buf, | ||
| 68 | size_t len) | ||
| 69 | { | ||
| 70 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 71 | struct ad5446_state *st = iio_priv(dev_info); | ||
| 72 | int ret; | ||
| 73 | long val; | ||
| 74 | |||
| 75 | ret = strict_strtol(buf, 10, &val); | ||
| 76 | if (ret) | ||
| 77 | goto error_ret; | ||
| 78 | |||
| 79 | if (val > RES_MASK(st->chip_info->bits)) { | ||
| 80 | ret = -EINVAL; | ||
| 81 | goto error_ret; | ||
| 82 | } | ||
| 83 | |||
| 84 | mutex_lock(&dev_info->mlock); | ||
| 85 | st->cached_val = val; | ||
| 86 | st->chip_info->store_sample(st, val); | ||
| 87 | ret = spi_sync(st->spi, &st->msg); | ||
| 88 | mutex_unlock(&dev_info->mlock); | ||
| 89 | |||
| 90 | error_ret: | ||
| 91 | return ret ? ret : len; | ||
| 92 | } | ||
| 93 | |||
| 94 | static IIO_DEV_ATTR_OUT_RAW(0, ad5446_write, 0); | ||
| 95 | |||
| 96 | static ssize_t ad5446_show_scale(struct device *dev, | ||
| 97 | struct device_attribute *attr, | ||
| 98 | char *buf) | ||
| 99 | { | ||
| 100 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 101 | struct ad5446_state *st = iio_priv(dev_info); | ||
| 102 | /* Corresponds to Vref / 2^(bits) */ | ||
| 103 | unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits; | ||
| 104 | |||
| 105 | return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); | ||
| 106 | } | ||
| 107 | static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5446_show_scale, NULL, 0); | ||
| 108 | |||
| 109 | static ssize_t ad5446_write_powerdown_mode(struct device *dev, | ||
| 110 | struct device_attribute *attr, | ||
| 111 | const char *buf, size_t len) | ||
| 112 | { | ||
| 113 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 114 | struct ad5446_state *st = iio_priv(dev_info); | ||
| 115 | |||
| 116 | if (sysfs_streq(buf, "1kohm_to_gnd")) | ||
| 117 | st->pwr_down_mode = MODE_PWRDWN_1k; | ||
| 118 | else if (sysfs_streq(buf, "100kohm_to_gnd")) | ||
| 119 | st->pwr_down_mode = MODE_PWRDWN_100k; | ||
| 120 | else if (sysfs_streq(buf, "three_state")) | ||
| 121 | st->pwr_down_mode = MODE_PWRDWN_TRISTATE; | ||
| 122 | else | ||
| 123 | return -EINVAL; | ||
| 124 | |||
| 125 | return len; | ||
| 126 | } | ||
| 127 | |||
| 128 | static ssize_t ad5446_read_powerdown_mode(struct device *dev, | ||
| 129 | struct device_attribute *attr, char *buf) | ||
| 130 | { | ||
| 131 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 132 | struct ad5446_state *st = iio_priv(dev_info); | ||
| 133 | |||
| 134 | char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"}; | ||
| 135 | |||
| 136 | return sprintf(buf, "%s\n", mode[st->pwr_down_mode]); | ||
| 137 | } | ||
| 138 | |||
| 139 | static ssize_t ad5446_read_dac_powerdown(struct device *dev, | ||
| 140 | struct device_attribute *attr, | ||
| 141 | char *buf) | ||
| 142 | { | ||
| 143 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 144 | struct ad5446_state *st = iio_priv(dev_info); | ||
| 145 | |||
| 146 | return sprintf(buf, "%d\n", st->pwr_down); | ||
| 147 | } | ||
| 148 | |||
| 149 | static ssize_t ad5446_write_dac_powerdown(struct device *dev, | ||
| 150 | struct device_attribute *attr, | ||
| 151 | const char *buf, size_t len) | ||
| 152 | { | ||
| 153 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 154 | struct ad5446_state *st = iio_priv(dev_info); | ||
| 155 | unsigned long readin; | ||
| 156 | int ret; | ||
| 157 | |||
| 158 | ret = strict_strtol(buf, 10, &readin); | ||
| 159 | if (ret) | ||
| 160 | return ret; | ||
| 161 | |||
| 162 | if (readin > 1) | ||
| 163 | ret = -EINVAL; | ||
| 164 | |||
| 165 | mutex_lock(&dev_info->mlock); | ||
| 166 | st->pwr_down = readin; | ||
| 167 | |||
| 168 | if (st->pwr_down) | ||
| 169 | st->chip_info->store_pwr_down(st, st->pwr_down_mode); | ||
| 170 | else | ||
| 171 | st->chip_info->store_sample(st, st->cached_val); | ||
| 172 | |||
| 173 | ret = spi_sync(st->spi, &st->msg); | ||
| 174 | mutex_unlock(&dev_info->mlock); | ||
| 175 | |||
| 176 | return ret ? ret : len; | ||
| 177 | } | ||
| 178 | |||
| 179 | static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | S_IWUSR, | ||
| 180 | ad5446_read_powerdown_mode, | ||
| 181 | ad5446_write_powerdown_mode, 0); | ||
| 182 | |||
| 183 | static IIO_CONST_ATTR(out_powerdown_mode_available, | ||
| 184 | "1kohm_to_gnd 100kohm_to_gnd three_state"); | ||
| 185 | |||
| 186 | static IIO_DEVICE_ATTR(out0_powerdown, S_IRUGO | S_IWUSR, | ||
| 187 | ad5446_read_dac_powerdown, | ||
| 188 | ad5446_write_dac_powerdown, 0); | ||
| 189 | |||
| 190 | static struct attribute *ad5446_attributes[] = { | ||
| 191 | &iio_dev_attr_out0_raw.dev_attr.attr, | ||
| 192 | &iio_dev_attr_out_scale.dev_attr.attr, | ||
| 193 | &iio_dev_attr_out0_powerdown.dev_attr.attr, | ||
| 194 | &iio_dev_attr_out_powerdown_mode.dev_attr.attr, | ||
| 195 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, | ||
| 196 | NULL, | ||
| 197 | }; | ||
| 198 | |||
| 199 | static mode_t ad5446_attr_is_visible(struct kobject *kobj, | ||
| 200 | struct attribute *attr, int n) | ||
| 201 | { | ||
| 202 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 203 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 204 | struct ad5446_state *st = iio_priv(dev_info); | ||
| 205 | |||
| 206 | mode_t mode = attr->mode; | ||
| 207 | |||
| 208 | if (!st->chip_info->store_pwr_down && | ||
| 209 | (attr == &iio_dev_attr_out0_powerdown.dev_attr.attr || | ||
| 210 | attr == &iio_dev_attr_out_powerdown_mode.dev_attr.attr || | ||
| 211 | attr == | ||
| 212 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr)) | ||
| 213 | mode = 0; | ||
| 214 | |||
| 215 | return mode; | ||
| 216 | } | ||
| 217 | |||
| 218 | static const struct attribute_group ad5446_attribute_group = { | ||
| 219 | .attrs = ad5446_attributes, | ||
| 220 | .is_visible = ad5446_attr_is_visible, | ||
| 221 | }; | ||
| 222 | |||
| 223 | static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { | ||
| 224 | [ID_AD5444] = { | ||
| 225 | .bits = 12, | ||
| 226 | .storagebits = 16, | ||
| 227 | .left_shift = 2, | ||
| 228 | .store_sample = ad5446_store_sample, | ||
| 229 | }, | ||
| 230 | [ID_AD5446] = { | ||
| 231 | .bits = 14, | ||
| 232 | .storagebits = 16, | ||
| 233 | .left_shift = 0, | ||
| 234 | .store_sample = ad5446_store_sample, | ||
| 235 | }, | ||
| 236 | [ID_AD5541A] = { | ||
| 237 | .bits = 16, | ||
| 238 | .storagebits = 16, | ||
| 239 | .left_shift = 0, | ||
| 240 | .store_sample = ad5542_store_sample, | ||
| 241 | }, | ||
| 242 | [ID_AD5542A] = { | ||
| 243 | .bits = 16, | ||
| 244 | .storagebits = 16, | ||
| 245 | .left_shift = 0, | ||
| 246 | .store_sample = ad5542_store_sample, | ||
| 247 | }, | ||
| 248 | [ID_AD5543] = { | ||
| 249 | .bits = 16, | ||
| 250 | .storagebits = 16, | ||
| 251 | .left_shift = 0, | ||
| 252 | .store_sample = ad5542_store_sample, | ||
| 253 | }, | ||
| 254 | [ID_AD5512A] = { | ||
| 255 | .bits = 12, | ||
| 256 | .storagebits = 16, | ||
| 257 | .left_shift = 4, | ||
| 258 | .store_sample = ad5542_store_sample, | ||
| 259 | }, | ||
| 260 | [ID_AD5553] = { | ||
| 261 | .bits = 14, | ||
| 262 | .storagebits = 16, | ||
| 263 | .left_shift = 0, | ||
| 264 | .store_sample = ad5542_store_sample, | ||
| 265 | }, | ||
| 266 | [ID_AD5601] = { | ||
| 267 | .bits = 8, | ||
| 268 | .storagebits = 16, | ||
| 269 | .left_shift = 6, | ||
| 270 | .store_sample = ad5542_store_sample, | ||
| 271 | .store_pwr_down = ad5620_store_pwr_down, | ||
| 272 | }, | ||
| 273 | [ID_AD5611] = { | ||
| 274 | .bits = 10, | ||
| 275 | .storagebits = 16, | ||
| 276 | .left_shift = 4, | ||
| 277 | .store_sample = ad5542_store_sample, | ||
| 278 | .store_pwr_down = ad5620_store_pwr_down, | ||
| 279 | }, | ||
| 280 | [ID_AD5621] = { | ||
| 281 | .bits = 12, | ||
| 282 | .storagebits = 16, | ||
| 283 | .left_shift = 2, | ||
| 284 | .store_sample = ad5542_store_sample, | ||
| 285 | .store_pwr_down = ad5620_store_pwr_down, | ||
| 286 | }, | ||
| 287 | [ID_AD5620_2500] = { | ||
| 288 | .bits = 12, | ||
| 289 | .storagebits = 16, | ||
| 290 | .left_shift = 2, | ||
| 291 | .int_vref_mv = 2500, | ||
| 292 | .store_sample = ad5620_store_sample, | ||
| 293 | .store_pwr_down = ad5620_store_pwr_down, | ||
| 294 | }, | ||
| 295 | [ID_AD5620_1250] = { | ||
| 296 | .bits = 12, | ||
| 297 | .storagebits = 16, | ||
| 298 | .left_shift = 2, | ||
| 299 | .int_vref_mv = 1250, | ||
| 300 | .store_sample = ad5620_store_sample, | ||
| 301 | .store_pwr_down = ad5620_store_pwr_down, | ||
| 302 | }, | ||
| 303 | [ID_AD5640_2500] = { | ||
| 304 | .bits = 14, | ||
| 305 | .storagebits = 16, | ||
| 306 | .left_shift = 0, | ||
| 307 | .int_vref_mv = 2500, | ||
| 308 | .store_sample = ad5620_store_sample, | ||
| 309 | .store_pwr_down = ad5620_store_pwr_down, | ||
| 310 | }, | ||
| 311 | [ID_AD5640_1250] = { | ||
| 312 | .bits = 14, | ||
| 313 | .storagebits = 16, | ||
| 314 | .left_shift = 0, | ||
| 315 | .int_vref_mv = 1250, | ||
| 316 | .store_sample = ad5620_store_sample, | ||
| 317 | .store_pwr_down = ad5620_store_pwr_down, | ||
| 318 | }, | ||
| 319 | [ID_AD5660_2500] = { | ||
| 320 | .bits = 16, | ||
| 321 | .storagebits = 24, | ||
| 322 | .left_shift = 0, | ||
| 323 | .int_vref_mv = 2500, | ||
| 324 | .store_sample = ad5660_store_sample, | ||
| 325 | .store_pwr_down = ad5660_store_pwr_down, | ||
| 326 | }, | ||
| 327 | [ID_AD5660_1250] = { | ||
| 328 | .bits = 16, | ||
| 329 | .storagebits = 24, | ||
| 330 | .left_shift = 0, | ||
| 331 | .int_vref_mv = 1250, | ||
| 332 | .store_sample = ad5660_store_sample, | ||
| 333 | .store_pwr_down = ad5660_store_pwr_down, | ||
| 334 | }, | ||
| 335 | }; | ||
| 336 | |||
| 337 | static const struct iio_info ad5446_info = { | ||
| 338 | .attrs = &ad5446_attribute_group, | ||
| 339 | .driver_module = THIS_MODULE, | ||
| 340 | }; | ||
| 341 | |||
| 342 | static int __devinit ad5446_probe(struct spi_device *spi) | ||
| 343 | { | ||
| 344 | struct ad5446_state *st; | ||
| 345 | struct iio_dev *indio_dev; | ||
| 346 | struct regulator *reg; | ||
| 347 | int ret, voltage_uv = 0; | ||
| 348 | |||
| 349 | reg = regulator_get(&spi->dev, "vcc"); | ||
| 350 | if (!IS_ERR(reg)) { | ||
| 351 | ret = regulator_enable(reg); | ||
| 352 | if (ret) | ||
| 353 | goto error_put_reg; | ||
| 354 | |||
| 355 | voltage_uv = regulator_get_voltage(reg); | ||
| 356 | } | ||
| 357 | |||
| 358 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
| 359 | if (indio_dev == NULL) { | ||
| 360 | ret = -ENOMEM; | ||
| 361 | goto error_disable_reg; | ||
| 362 | } | ||
| 363 | st = iio_priv(indio_dev); | ||
| 364 | st->chip_info = | ||
| 365 | &ad5446_chip_info_tbl[spi_get_device_id(spi)->driver_data]; | ||
| 366 | |||
| 367 | spi_set_drvdata(spi, indio_dev); | ||
| 368 | st->reg = reg; | ||
| 369 | st->spi = spi; | ||
| 370 | |||
| 371 | /* Estabilish that the iio_dev is a child of the spi device */ | ||
| 372 | indio_dev->dev.parent = &spi->dev; | ||
| 373 | indio_dev->name = spi_get_device_id(spi)->name; | ||
| 374 | indio_dev->info = &ad5446_info; | ||
| 375 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 376 | |||
| 377 | /* Setup default message */ | ||
| 378 | |||
| 379 | st->xfer.tx_buf = &st->data; | ||
| 380 | st->xfer.len = st->chip_info->storagebits / 8; | ||
| 381 | |||
| 382 | spi_message_init(&st->msg); | ||
| 383 | spi_message_add_tail(&st->xfer, &st->msg); | ||
| 384 | |||
| 385 | switch (spi_get_device_id(spi)->driver_data) { | ||
| 386 | case ID_AD5620_2500: | ||
| 387 | case ID_AD5620_1250: | ||
| 388 | case ID_AD5640_2500: | ||
| 389 | case ID_AD5640_1250: | ||
| 390 | case ID_AD5660_2500: | ||
| 391 | case ID_AD5660_1250: | ||
| 392 | st->vref_mv = st->chip_info->int_vref_mv; | ||
| 393 | break; | ||
| 394 | default: | ||
| 395 | if (voltage_uv) | ||
| 396 | st->vref_mv = voltage_uv / 1000; | ||
| 397 | else | ||
| 398 | dev_warn(&spi->dev, | ||
| 399 | "reference voltage unspecified\n"); | ||
| 400 | } | ||
| 401 | |||
| 402 | ret = iio_device_register(indio_dev); | ||
| 403 | if (ret) | ||
| 404 | goto error_free_device; | ||
| 405 | |||
| 406 | return 0; | ||
| 407 | |||
| 408 | error_free_device: | ||
| 409 | iio_free_device(indio_dev); | ||
| 410 | error_disable_reg: | ||
| 411 | if (!IS_ERR(reg)) | ||
| 412 | regulator_disable(reg); | ||
| 413 | error_put_reg: | ||
| 414 | if (!IS_ERR(reg)) | ||
| 415 | regulator_put(reg); | ||
| 416 | |||
| 417 | return ret; | ||
| 418 | } | ||
| 419 | |||
| 420 | static int ad5446_remove(struct spi_device *spi) | ||
| 421 | { | ||
| 422 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 423 | struct ad5446_state *st = iio_priv(indio_dev); | ||
| 424 | struct regulator *reg = st->reg; | ||
| 425 | |||
| 426 | iio_device_unregister(indio_dev); | ||
| 427 | if (!IS_ERR(reg)) { | ||
| 428 | regulator_disable(reg); | ||
| 429 | regulator_put(reg); | ||
| 430 | } | ||
| 431 | return 0; | ||
| 432 | } | ||
| 433 | |||
| 434 | static const struct spi_device_id ad5446_id[] = { | ||
| 435 | {"ad5444", ID_AD5444}, | ||
| 436 | {"ad5446", ID_AD5446}, | ||
| 437 | {"ad5512a", ID_AD5512A}, | ||
| 438 | {"ad5541a", ID_AD5541A}, | ||
| 439 | {"ad5542a", ID_AD5542A}, | ||
| 440 | {"ad5543", ID_AD5543}, | ||
| 441 | {"ad5553", ID_AD5553}, | ||
| 442 | {"ad5601", ID_AD5601}, | ||
| 443 | {"ad5611", ID_AD5611}, | ||
| 444 | {"ad5621", ID_AD5621}, | ||
| 445 | {"ad5620-2500", ID_AD5620_2500}, /* AD5620/40/60: */ | ||
| 446 | {"ad5620-1250", ID_AD5620_1250}, /* part numbers may look differently */ | ||
| 447 | {"ad5640-2500", ID_AD5640_2500}, | ||
| 448 | {"ad5640-1250", ID_AD5640_1250}, | ||
| 449 | {"ad5660-2500", ID_AD5660_2500}, | ||
| 450 | {"ad5660-1250", ID_AD5660_1250}, | ||
| 451 | {} | ||
| 452 | }; | ||
| 453 | |||
| 454 | static struct spi_driver ad5446_driver = { | ||
| 455 | .driver = { | ||
| 456 | .name = "ad5446", | ||
| 457 | .bus = &spi_bus_type, | ||
| 458 | .owner = THIS_MODULE, | ||
| 459 | }, | ||
| 460 | .probe = ad5446_probe, | ||
| 461 | .remove = __devexit_p(ad5446_remove), | ||
| 462 | .id_table = ad5446_id, | ||
| 463 | }; | ||
| 464 | |||
| 465 | static int __init ad5446_init(void) | ||
| 466 | { | ||
| 467 | return spi_register_driver(&ad5446_driver); | ||
| 468 | } | ||
| 469 | module_init(ad5446_init); | ||
| 470 | |||
| 471 | static void __exit ad5446_exit(void) | ||
| 472 | { | ||
| 473 | spi_unregister_driver(&ad5446_driver); | ||
| 474 | } | ||
| 475 | module_exit(ad5446_exit); | ||
| 476 | |||
| 477 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
| 478 | MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC"); | ||
| 479 | MODULE_LICENSE("GPL v2"); | ||
| 480 | MODULE_ALIAS("spi:ad5446"); | ||
diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h new file mode 100644 index 00000000000..7118d653ac3 --- /dev/null +++ b/drivers/staging/iio/dac/ad5446.h | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | /* | ||
| 2 | * AD5446 SPI DAC driver | ||
| 3 | * | ||
| 4 | * Copyright 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | #ifndef IIO_DAC_AD5446_H_ | ||
| 9 | #define IIO_DAC_AD5446_H_ | ||
| 10 | |||
| 11 | /* DAC Control Bits */ | ||
| 12 | |||
| 13 | #define AD5446_LOAD (0x0 << 14) /* Load and update */ | ||
| 14 | #define AD5446_SDO_DIS (0x1 << 14) /* Disable SDO */ | ||
| 15 | #define AD5446_NOP (0x2 << 14) /* No operation */ | ||
| 16 | #define AD5446_CLK_RISING (0x3 << 14) /* Clock data on rising edge */ | ||
| 17 | |||
| 18 | #define AD5620_LOAD (0x0 << 14) /* Load and update Norm Operation*/ | ||
| 19 | #define AD5620_PWRDWN_1k (0x1 << 14) /* Power-down: 1kOhm to GND */ | ||
| 20 | #define AD5620_PWRDWN_100k (0x2 << 14) /* Power-down: 100kOhm to GND */ | ||
| 21 | #define AD5620_PWRDWN_TRISTATE (0x3 << 14) /* Power-down: Three-state */ | ||
| 22 | |||
| 23 | #define AD5660_LOAD (0x0 << 16) /* Load and update Norm Operation*/ | ||
| 24 | #define AD5660_PWRDWN_1k (0x1 << 16) /* Power-down: 1kOhm to GND */ | ||
| 25 | #define AD5660_PWRDWN_100k (0x2 << 16) /* Power-down: 100kOhm to GND */ | ||
| 26 | #define AD5660_PWRDWN_TRISTATE (0x3 << 16) /* Power-down: Three-state */ | ||
| 27 | |||
| 28 | #define RES_MASK(bits) ((1 << (bits)) - 1) | ||
| 29 | |||
| 30 | #define MODE_PWRDWN_1k 0x1 | ||
| 31 | #define MODE_PWRDWN_100k 0x2 | ||
| 32 | #define MODE_PWRDWN_TRISTATE 0x3 | ||
| 33 | |||
| 34 | /** | ||
| 35 | * struct ad5446_state - driver instance specific data | ||
| 36 | * @spi: spi_device | ||
| 37 | * @chip_info: chip model specific constants, available modes etc | ||
| 38 | * @reg: supply regulator | ||
| 39 | * @poll_work: bottom half of polling interrupt handler | ||
| 40 | * @vref_mv: actual reference voltage used | ||
| 41 | * @xfer: default spi transfer | ||
| 42 | * @msg: default spi message | ||
| 43 | * @data: spi transmit buffer | ||
| 44 | */ | ||
| 45 | |||
| 46 | struct ad5446_state { | ||
| 47 | struct spi_device *spi; | ||
| 48 | const struct ad5446_chip_info *chip_info; | ||
| 49 | struct regulator *reg; | ||
| 50 | struct work_struct poll_work; | ||
| 51 | unsigned short vref_mv; | ||
| 52 | unsigned cached_val; | ||
| 53 | unsigned pwr_down_mode; | ||
| 54 | unsigned pwr_down; | ||
| 55 | struct spi_transfer xfer; | ||
| 56 | struct spi_message msg; | ||
| 57 | union { | ||
| 58 | unsigned short d16; | ||
| 59 | unsigned char d24[3]; | ||
| 60 | } data; | ||
| 61 | }; | ||
| 62 | |||
| 63 | /** | ||
| 64 | * struct ad5446_chip_info - chip specific information | ||
| 65 | * @bits: accuracy of the DAC in bits | ||
| 66 | * @storagebits: number of bits written to the DAC | ||
| 67 | * @left_shift: number of bits the datum must be shifted | ||
| 68 | * @int_vref_mv: AD5620/40/60: the internal reference voltage | ||
| 69 | * @store_sample: chip specific helper function to store the datum | ||
| 70 | * @store_sample: chip specific helper function to store the powerpown cmd | ||
| 71 | */ | ||
| 72 | |||
| 73 | struct ad5446_chip_info { | ||
| 74 | u8 bits; | ||
| 75 | u8 storagebits; | ||
| 76 | u8 left_shift; | ||
| 77 | u16 int_vref_mv; | ||
| 78 | void (*store_sample) (struct ad5446_state *st, unsigned val); | ||
| 79 | void (*store_pwr_down) (struct ad5446_state *st, unsigned mode); | ||
| 80 | }; | ||
| 81 | |||
| 82 | /** | ||
| 83 | * ad5446_supported_device_ids: | ||
| 84 | * The AD5620/40/60 parts are available in different fixed internal reference | ||
| 85 | * voltage options. The actual part numbers may look differently | ||
| 86 | * (and a bit cryptic), however this style is used to make clear which | ||
| 87 | * parts are supported here. | ||
| 88 | */ | ||
| 89 | |||
| 90 | enum ad5446_supported_device_ids { | ||
| 91 | ID_AD5444, | ||
| 92 | ID_AD5446, | ||
| 93 | ID_AD5541A, | ||
| 94 | ID_AD5542A, | ||
| 95 | ID_AD5543, | ||
| 96 | ID_AD5512A, | ||
| 97 | ID_AD5553, | ||
| 98 | ID_AD5601, | ||
| 99 | ID_AD5611, | ||
| 100 | ID_AD5621, | ||
| 101 | ID_AD5620_2500, | ||
| 102 | ID_AD5620_1250, | ||
| 103 | ID_AD5640_2500, | ||
| 104 | ID_AD5640_1250, | ||
| 105 | ID_AD5660_2500, | ||
| 106 | ID_AD5660_1250, | ||
| 107 | }; | ||
| 108 | |||
| 109 | #endif /* IIO_DAC_AD5446_H_ */ | ||
diff --git a/drivers/staging/iio/dac/ad5504.c b/drivers/staging/iio/dac/ad5504.c new file mode 100644 index 00000000000..1915f459868 --- /dev/null +++ b/drivers/staging/iio/dac/ad5504.c | |||
| @@ -0,0 +1,397 @@ | |||
| 1 | /* | ||
| 2 | * AD5504, AD5501 High Voltage Digital to Analog Converter | ||
| 3 | * | ||
| 4 | * Copyright 2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/gpio.h> | ||
| 11 | #include <linux/fs.h> | ||
| 12 | #include <linux/device.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/spi/spi.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/sysfs.h> | ||
| 17 | #include <linux/regulator/consumer.h> | ||
| 18 | |||
| 19 | #include "../iio.h" | ||
| 20 | #include "../sysfs.h" | ||
| 21 | #include "dac.h" | ||
| 22 | #include "ad5504.h" | ||
| 23 | |||
| 24 | static int ad5504_spi_write(struct spi_device *spi, u8 addr, u16 val) | ||
| 25 | { | ||
| 26 | u16 tmp = cpu_to_be16(AD5504_CMD_WRITE | | ||
| 27 | AD5504_ADDR(addr) | | ||
| 28 | (val & AD5504_RES_MASK)); | ||
| 29 | |||
| 30 | return spi_write(spi, (u8 *)&tmp, 2); | ||
| 31 | } | ||
| 32 | |||
| 33 | static int ad5504_spi_read(struct spi_device *spi, u8 addr, u16 *val) | ||
| 34 | { | ||
| 35 | u16 tmp = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr)); | ||
| 36 | int ret; | ||
| 37 | struct spi_transfer t = { | ||
| 38 | .tx_buf = &tmp, | ||
| 39 | .rx_buf = val, | ||
| 40 | .len = 2, | ||
| 41 | }; | ||
| 42 | struct spi_message m; | ||
| 43 | |||
| 44 | spi_message_init(&m); | ||
| 45 | spi_message_add_tail(&t, &m); | ||
| 46 | ret = spi_sync(spi, &m); | ||
| 47 | |||
| 48 | *val = be16_to_cpu(*val) & AD5504_RES_MASK; | ||
| 49 | |||
| 50 | return ret; | ||
| 51 | } | ||
| 52 | |||
| 53 | static ssize_t ad5504_write_dac(struct device *dev, | ||
| 54 | struct device_attribute *attr, | ||
| 55 | const char *buf, size_t len) | ||
| 56 | { | ||
| 57 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 58 | struct ad5504_state *st = iio_priv(indio_dev); | ||
| 59 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 60 | long readin; | ||
| 61 | int ret; | ||
| 62 | |||
| 63 | ret = strict_strtol(buf, 10, &readin); | ||
| 64 | if (ret) | ||
| 65 | return ret; | ||
| 66 | |||
| 67 | ret = ad5504_spi_write(st->spi, this_attr->address, readin); | ||
| 68 | return ret ? ret : len; | ||
| 69 | } | ||
| 70 | |||
| 71 | static ssize_t ad5504_read_dac(struct device *dev, | ||
| 72 | struct device_attribute *attr, | ||
| 73 | char *buf) | ||
| 74 | { | ||
| 75 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 76 | struct ad5504_state *st = iio_priv(indio_dev); | ||
| 77 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 78 | int ret; | ||
| 79 | u16 val; | ||
| 80 | |||
| 81 | ret = ad5504_spi_read(st->spi, this_attr->address, &val); | ||
| 82 | if (ret) | ||
| 83 | return ret; | ||
| 84 | |||
| 85 | return sprintf(buf, "%d\n", val); | ||
| 86 | } | ||
| 87 | |||
| 88 | static ssize_t ad5504_read_powerdown_mode(struct device *dev, | ||
| 89 | struct device_attribute *attr, char *buf) | ||
| 90 | { | ||
| 91 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 92 | struct ad5504_state *st = iio_priv(indio_dev); | ||
| 93 | |||
| 94 | const char mode[][14] = {"20kohm_to_gnd", "three_state"}; | ||
| 95 | |||
| 96 | return sprintf(buf, "%s\n", mode[st->pwr_down_mode]); | ||
| 97 | } | ||
| 98 | |||
| 99 | static ssize_t ad5504_write_powerdown_mode(struct device *dev, | ||
| 100 | struct device_attribute *attr, | ||
| 101 | const char *buf, size_t len) | ||
| 102 | { | ||
| 103 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 104 | struct ad5504_state *st = iio_priv(indio_dev); | ||
| 105 | int ret; | ||
| 106 | |||
| 107 | if (sysfs_streq(buf, "20kohm_to_gnd")) | ||
| 108 | st->pwr_down_mode = AD5504_DAC_PWRDN_20K; | ||
| 109 | else if (sysfs_streq(buf, "three_state")) | ||
| 110 | st->pwr_down_mode = AD5504_DAC_PWRDN_3STATE; | ||
| 111 | else | ||
| 112 | ret = -EINVAL; | ||
| 113 | |||
| 114 | return ret ? ret : len; | ||
| 115 | } | ||
| 116 | |||
| 117 | static ssize_t ad5504_read_dac_powerdown(struct device *dev, | ||
| 118 | struct device_attribute *attr, | ||
| 119 | char *buf) | ||
| 120 | { | ||
| 121 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 122 | struct ad5504_state *st = iio_priv(indio_dev); | ||
| 123 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 124 | |||
| 125 | return sprintf(buf, "%d\n", | ||
| 126 | !(st->pwr_down_mask & (1 << this_attr->address))); | ||
| 127 | } | ||
| 128 | |||
| 129 | static ssize_t ad5504_write_dac_powerdown(struct device *dev, | ||
| 130 | struct device_attribute *attr, | ||
| 131 | const char *buf, size_t len) | ||
| 132 | { | ||
| 133 | long readin; | ||
| 134 | int ret; | ||
| 135 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 136 | struct ad5504_state *st = iio_priv(indio_dev); | ||
| 137 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 138 | |||
| 139 | ret = strict_strtol(buf, 10, &readin); | ||
| 140 | if (ret) | ||
| 141 | return ret; | ||
| 142 | |||
| 143 | if (readin == 0) | ||
| 144 | st->pwr_down_mask |= (1 << this_attr->address); | ||
| 145 | else if (readin == 1) | ||
| 146 | st->pwr_down_mask &= ~(1 << this_attr->address); | ||
| 147 | else | ||
| 148 | ret = -EINVAL; | ||
| 149 | |||
| 150 | ret = ad5504_spi_write(st->spi, AD5504_ADDR_CTRL, | ||
| 151 | AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) | | ||
| 152 | AD5504_DAC_PWR(st->pwr_down_mask)); | ||
| 153 | |||
| 154 | /* writes to the CTRL register must be followed by a NOOP */ | ||
| 155 | ad5504_spi_write(st->spi, AD5504_ADDR_NOOP, 0); | ||
| 156 | |||
| 157 | return ret ? ret : len; | ||
| 158 | } | ||
| 159 | |||
| 160 | static ssize_t ad5504_show_scale(struct device *dev, | ||
| 161 | struct device_attribute *attr, | ||
| 162 | char *buf) | ||
| 163 | { | ||
| 164 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 165 | struct ad5504_state *st = iio_priv(indio_dev); | ||
| 166 | /* Corresponds to Vref / 2^(bits) */ | ||
| 167 | unsigned int scale_uv = (st->vref_mv * 1000) >> AD5505_BITS; | ||
| 168 | |||
| 169 | return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); | ||
| 170 | } | ||
| 171 | static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5504_show_scale, NULL, 0); | ||
| 172 | |||
| 173 | #define IIO_DEV_ATTR_OUT_RW_RAW(_num, _show, _store, _addr) \ | ||
| 174 | IIO_DEVICE_ATTR(out##_num##_raw, \ | ||
| 175 | S_IRUGO | S_IWUSR, _show, _store, _addr) | ||
| 176 | |||
| 177 | static IIO_DEV_ATTR_OUT_RW_RAW(0, ad5504_read_dac, | ||
| 178 | ad5504_write_dac, AD5504_ADDR_DAC0); | ||
| 179 | static IIO_DEV_ATTR_OUT_RW_RAW(1, ad5504_read_dac, | ||
| 180 | ad5504_write_dac, AD5504_ADDR_DAC1); | ||
| 181 | static IIO_DEV_ATTR_OUT_RW_RAW(2, ad5504_read_dac, | ||
| 182 | ad5504_write_dac, AD5504_ADDR_DAC2); | ||
| 183 | static IIO_DEV_ATTR_OUT_RW_RAW(3, ad5504_read_dac, | ||
| 184 | ad5504_write_dac, AD5504_ADDR_DAC3); | ||
| 185 | |||
| 186 | static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | | ||
| 187 | S_IWUSR, ad5504_read_powerdown_mode, | ||
| 188 | ad5504_write_powerdown_mode, 0); | ||
| 189 | |||
| 190 | static IIO_CONST_ATTR(out_powerdown_mode_available, | ||
| 191 | "20kohm_to_gnd three_state"); | ||
| 192 | |||
| 193 | #define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr) \ | ||
| 194 | IIO_DEVICE_ATTR(out##_num##_powerdown, \ | ||
| 195 | S_IRUGO | S_IWUSR, _show, _store, _addr) | ||
| 196 | |||
| 197 | static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5504_read_dac_powerdown, | ||
| 198 | ad5504_write_dac_powerdown, 0); | ||
| 199 | static IIO_DEV_ATTR_DAC_POWERDOWN(1, ad5504_read_dac_powerdown, | ||
| 200 | ad5504_write_dac_powerdown, 1); | ||
| 201 | static IIO_DEV_ATTR_DAC_POWERDOWN(2, ad5504_read_dac_powerdown, | ||
| 202 | ad5504_write_dac_powerdown, 2); | ||
| 203 | static IIO_DEV_ATTR_DAC_POWERDOWN(3, ad5504_read_dac_powerdown, | ||
| 204 | ad5504_write_dac_powerdown, 3); | ||
| 205 | |||
| 206 | static struct attribute *ad5504_attributes[] = { | ||
| 207 | &iio_dev_attr_out0_raw.dev_attr.attr, | ||
| 208 | &iio_dev_attr_out1_raw.dev_attr.attr, | ||
| 209 | &iio_dev_attr_out2_raw.dev_attr.attr, | ||
| 210 | &iio_dev_attr_out3_raw.dev_attr.attr, | ||
| 211 | &iio_dev_attr_out0_powerdown.dev_attr.attr, | ||
| 212 | &iio_dev_attr_out1_powerdown.dev_attr.attr, | ||
| 213 | &iio_dev_attr_out2_powerdown.dev_attr.attr, | ||
| 214 | &iio_dev_attr_out3_powerdown.dev_attr.attr, | ||
| 215 | &iio_dev_attr_out_powerdown_mode.dev_attr.attr, | ||
| 216 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, | ||
| 217 | &iio_dev_attr_out_scale.dev_attr.attr, | ||
| 218 | NULL, | ||
| 219 | }; | ||
| 220 | |||
| 221 | static const struct attribute_group ad5504_attribute_group = { | ||
| 222 | .attrs = ad5504_attributes, | ||
| 223 | }; | ||
| 224 | |||
| 225 | static struct attribute *ad5501_attributes[] = { | ||
| 226 | &iio_dev_attr_out0_raw.dev_attr.attr, | ||
| 227 | &iio_dev_attr_out0_powerdown.dev_attr.attr, | ||
| 228 | &iio_dev_attr_out_powerdown_mode.dev_attr.attr, | ||
| 229 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, | ||
| 230 | &iio_dev_attr_out_scale.dev_attr.attr, | ||
| 231 | NULL, | ||
| 232 | }; | ||
| 233 | |||
| 234 | static const struct attribute_group ad5501_attribute_group = { | ||
| 235 | .attrs = ad5501_attributes, | ||
| 236 | }; | ||
| 237 | |||
| 238 | static IIO_CONST_ATTR(temp0_thresh_rising_value, "110000"); | ||
| 239 | static IIO_CONST_ATTR(temp0_thresh_rising_en, "1"); | ||
| 240 | |||
| 241 | static struct attribute *ad5504_ev_attributes[] = { | ||
| 242 | &iio_const_attr_temp0_thresh_rising_value.dev_attr.attr, | ||
| 243 | &iio_const_attr_temp0_thresh_rising_en.dev_attr.attr, | ||
| 244 | NULL, | ||
| 245 | }; | ||
| 246 | |||
| 247 | static struct attribute_group ad5504_ev_attribute_group = { | ||
| 248 | .attrs = ad5504_ev_attributes, | ||
| 249 | }; | ||
| 250 | |||
| 251 | static irqreturn_t ad5504_event_handler(int irq, void *private) | ||
| 252 | { | ||
| 253 | iio_push_event(private, 0, | ||
| 254 | IIO_UNMOD_EVENT_CODE(IIO_EV_CLASS_TEMP, | ||
| 255 | 0, | ||
| 256 | IIO_EV_TYPE_THRESH, | ||
| 257 | IIO_EV_DIR_RISING), | ||
| 258 | iio_get_time_ns()); | ||
| 259 | |||
| 260 | return IRQ_HANDLED; | ||
| 261 | } | ||
| 262 | |||
| 263 | static const struct iio_info ad5504_info = { | ||
| 264 | .attrs = &ad5504_attribute_group, | ||
| 265 | .num_interrupt_lines = 1, | ||
| 266 | .event_attrs = &ad5504_ev_attribute_group, | ||
| 267 | .driver_module = THIS_MODULE, | ||
| 268 | }; | ||
| 269 | |||
| 270 | static const struct iio_info ad5501_info = { | ||
| 271 | .attrs = &ad5501_attribute_group, | ||
| 272 | .num_interrupt_lines = 1, | ||
| 273 | .event_attrs = &ad5504_ev_attribute_group, | ||
| 274 | .driver_module = THIS_MODULE, | ||
| 275 | }; | ||
| 276 | |||
| 277 | static int __devinit ad5504_probe(struct spi_device *spi) | ||
| 278 | { | ||
| 279 | struct ad5504_platform_data *pdata = spi->dev.platform_data; | ||
| 280 | struct iio_dev *indio_dev; | ||
| 281 | struct ad5504_state *st; | ||
| 282 | struct regulator *reg; | ||
| 283 | int ret, voltage_uv = 0; | ||
| 284 | |||
| 285 | reg = regulator_get(&spi->dev, "vcc"); | ||
| 286 | if (!IS_ERR(reg)) { | ||
| 287 | ret = regulator_enable(reg); | ||
| 288 | if (ret) | ||
| 289 | goto error_put_reg; | ||
| 290 | |||
| 291 | voltage_uv = regulator_get_voltage(reg); | ||
| 292 | } | ||
| 293 | |||
| 294 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
| 295 | if (indio_dev == NULL) { | ||
| 296 | ret = -ENOMEM; | ||
| 297 | goto error_disable_reg; | ||
| 298 | } | ||
| 299 | spi_set_drvdata(spi, indio_dev); | ||
| 300 | st = iio_priv(indio_dev); | ||
| 301 | if (voltage_uv) | ||
| 302 | st->vref_mv = voltage_uv / 1000; | ||
| 303 | else if (pdata) | ||
| 304 | st->vref_mv = pdata->vref_mv; | ||
| 305 | else | ||
| 306 | dev_warn(&spi->dev, "reference voltage unspecified\n"); | ||
| 307 | |||
| 308 | st->reg = reg; | ||
| 309 | st->spi = spi; | ||
| 310 | indio_dev->dev.parent = &spi->dev; | ||
| 311 | indio_dev->name = spi_get_device_id(st->spi)->name; | ||
| 312 | if (spi_get_device_id(st->spi)->driver_data == ID_AD5501) | ||
| 313 | indio_dev->info = &ad5501_info; | ||
| 314 | else | ||
| 315 | indio_dev->info = &ad5504_info; | ||
| 316 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 317 | |||
| 318 | ret = iio_device_register(indio_dev); | ||
| 319 | if (ret) | ||
| 320 | goto error_free_dev; | ||
| 321 | |||
| 322 | if (spi->irq) { | ||
| 323 | ret = request_threaded_irq(spi->irq, | ||
| 324 | NULL, | ||
| 325 | &ad5504_event_handler, | ||
| 326 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
| 327 | spi_get_device_id(st->spi)->name, | ||
| 328 | indio_dev); | ||
| 329 | if (ret) | ||
| 330 | goto error_unreg_iio_device; | ||
| 331 | } | ||
| 332 | |||
| 333 | return 0; | ||
| 334 | |||
| 335 | error_unreg_iio_device: | ||
| 336 | iio_device_unregister(indio_dev); | ||
| 337 | error_free_dev: | ||
| 338 | iio_free_device(indio_dev); | ||
| 339 | error_disable_reg: | ||
| 340 | if (!IS_ERR(reg)) | ||
| 341 | regulator_disable(st->reg); | ||
| 342 | error_put_reg: | ||
| 343 | if (!IS_ERR(reg)) | ||
| 344 | regulator_put(reg); | ||
| 345 | |||
| 346 | return ret; | ||
| 347 | } | ||
| 348 | |||
| 349 | static int __devexit ad5504_remove(struct spi_device *spi) | ||
| 350 | { | ||
| 351 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 352 | struct ad5504_state *st = iio_priv(indio_dev); | ||
| 353 | struct regulator *reg = st->reg; | ||
| 354 | if (spi->irq) | ||
| 355 | free_irq(spi->irq, indio_dev); | ||
| 356 | |||
| 357 | iio_device_unregister(indio_dev); | ||
| 358 | |||
| 359 | if (!IS_ERR(reg)) { | ||
| 360 | regulator_disable(reg); | ||
| 361 | regulator_put(reg); | ||
| 362 | } | ||
| 363 | |||
| 364 | return 0; | ||
| 365 | } | ||
| 366 | |||
| 367 | static const struct spi_device_id ad5504_id[] = { | ||
| 368 | {"ad5504", ID_AD5504}, | ||
| 369 | {"ad5501", ID_AD5501}, | ||
| 370 | {} | ||
| 371 | }; | ||
| 372 | |||
| 373 | static struct spi_driver ad5504_driver = { | ||
| 374 | .driver = { | ||
| 375 | .name = "ad5504", | ||
| 376 | .owner = THIS_MODULE, | ||
| 377 | }, | ||
| 378 | .probe = ad5504_probe, | ||
| 379 | .remove = __devexit_p(ad5504_remove), | ||
| 380 | .id_table = ad5504_id, | ||
| 381 | }; | ||
| 382 | |||
| 383 | static __init int ad5504_spi_init(void) | ||
| 384 | { | ||
| 385 | return spi_register_driver(&ad5504_driver); | ||
| 386 | } | ||
| 387 | module_init(ad5504_spi_init); | ||
| 388 | |||
| 389 | static __exit void ad5504_spi_exit(void) | ||
| 390 | { | ||
| 391 | spi_unregister_driver(&ad5504_driver); | ||
| 392 | } | ||
| 393 | module_exit(ad5504_spi_exit); | ||
| 394 | |||
| 395 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
| 396 | MODULE_DESCRIPTION("Analog Devices AD5501/AD5501 DAC"); | ||
| 397 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/dac/ad5504.h b/drivers/staging/iio/dac/ad5504.h new file mode 100644 index 00000000000..85beb1dd29b --- /dev/null +++ b/drivers/staging/iio/dac/ad5504.h | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | /* | ||
| 2 | * AD5504 SPI DAC driver | ||
| 3 | * | ||
| 4 | * Copyright 2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef SPI_AD5504_H_ | ||
| 10 | #define SPI_AD5504_H_ | ||
| 11 | |||
| 12 | #define AD5505_BITS 12 | ||
| 13 | #define AD5504_RES_MASK ((1 << (AD5505_BITS)) - 1) | ||
| 14 | |||
| 15 | #define AD5504_CMD_READ (1 << 15) | ||
| 16 | #define AD5504_CMD_WRITE (0 << 15) | ||
| 17 | #define AD5504_ADDR(addr) ((addr) << 12) | ||
| 18 | |||
| 19 | /* Registers */ | ||
| 20 | #define AD5504_ADDR_NOOP 0 | ||
| 21 | #define AD5504_ADDR_DAC0 1 | ||
| 22 | #define AD5504_ADDR_DAC1 2 | ||
| 23 | #define AD5504_ADDR_DAC2 3 | ||
| 24 | #define AD5504_ADDR_DAC3 4 | ||
| 25 | #define AD5504_ADDR_ALL_DAC 5 | ||
| 26 | #define AD5504_ADDR_CTRL 7 | ||
| 27 | |||
| 28 | /* Control Register */ | ||
| 29 | #define AD5504_DAC_PWR(ch) ((ch) << 2) | ||
| 30 | #define AD5504_DAC_PWRDWN_MODE(mode) ((mode) << 6) | ||
| 31 | #define AD5504_DAC_PWRDN_20K 0 | ||
| 32 | #define AD5504_DAC_PWRDN_3STATE 1 | ||
| 33 | |||
| 34 | /* | ||
| 35 | * TODO: struct ad5504_platform_data needs to go into include/linux/iio | ||
| 36 | */ | ||
| 37 | |||
| 38 | struct ad5504_platform_data { | ||
| 39 | u16 vref_mv; | ||
| 40 | }; | ||
| 41 | |||
| 42 | /** | ||
| 43 | * struct ad5446_state - driver instance specific data | ||
| 44 | * @us: spi_device | ||
| 45 | * @reg: supply regulator | ||
| 46 | * @vref_mv: actual reference voltage used | ||
| 47 | * @pwr_down_mask power down mask | ||
| 48 | * @pwr_down_mode current power down mode | ||
| 49 | */ | ||
| 50 | |||
| 51 | struct ad5504_state { | ||
| 52 | struct spi_device *spi; | ||
| 53 | struct regulator *reg; | ||
| 54 | unsigned short vref_mv; | ||
| 55 | unsigned pwr_down_mask; | ||
| 56 | unsigned pwr_down_mode; | ||
| 57 | }; | ||
| 58 | |||
| 59 | /** | ||
| 60 | * ad5504_supported_device_ids: | ||
| 61 | */ | ||
| 62 | |||
| 63 | enum ad5504_supported_device_ids { | ||
| 64 | ID_AD5504, | ||
| 65 | ID_AD5501, | ||
| 66 | }; | ||
| 67 | |||
| 68 | #endif /* SPI_AD5504_H_ */ | ||
diff --git a/drivers/staging/iio/dac/ad5624r.h b/drivers/staging/iio/dac/ad5624r.h new file mode 100644 index 00000000000..b71c6a03e78 --- /dev/null +++ b/drivers/staging/iio/dac/ad5624r.h | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | /* | ||
| 2 | * AD5624R SPI DAC driver | ||
| 3 | * | ||
| 4 | * Copyright 2010-2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | #ifndef SPI_AD5624R_H_ | ||
| 9 | #define SPI_AD5624R_H_ | ||
| 10 | |||
| 11 | #define AD5624R_DAC_CHANNELS 4 | ||
| 12 | |||
| 13 | #define AD5624R_ADDR_DAC0 0x0 | ||
| 14 | #define AD5624R_ADDR_DAC1 0x1 | ||
| 15 | #define AD5624R_ADDR_DAC2 0x2 | ||
| 16 | #define AD5624R_ADDR_DAC3 0x3 | ||
| 17 | #define AD5624R_ADDR_ALL_DAC 0x7 | ||
| 18 | |||
| 19 | #define AD5624R_CMD_WRITE_INPUT_N 0x0 | ||
| 20 | #define AD5624R_CMD_UPDATE_DAC_N 0x1 | ||
| 21 | #define AD5624R_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2 | ||
| 22 | #define AD5624R_CMD_WRITE_INPUT_N_UPDATE_N 0x3 | ||
| 23 | #define AD5624R_CMD_POWERDOWN_DAC 0x4 | ||
| 24 | #define AD5624R_CMD_RESET 0x5 | ||
| 25 | #define AD5624R_CMD_LDAC_SETUP 0x6 | ||
| 26 | #define AD5624R_CMD_INTERNAL_REFER_SETUP 0x7 | ||
| 27 | |||
| 28 | #define AD5624R_LDAC_PWRDN_NONE 0x0 | ||
| 29 | #define AD5624R_LDAC_PWRDN_1K 0x1 | ||
| 30 | #define AD5624R_LDAC_PWRDN_100K 0x2 | ||
| 31 | #define AD5624R_LDAC_PWRDN_3STATE 0x3 | ||
| 32 | |||
| 33 | /** | ||
| 34 | * struct ad5624r_chip_info - chip specific information | ||
| 35 | * @bits: accuracy of the DAC in bits | ||
| 36 | * @int_vref_mv: AD5620/40/60: the internal reference voltage | ||
| 37 | */ | ||
| 38 | |||
| 39 | struct ad5624r_chip_info { | ||
| 40 | u8 bits; | ||
| 41 | u16 int_vref_mv; | ||
| 42 | }; | ||
| 43 | |||
| 44 | /** | ||
| 45 | * struct ad5446_state - driver instance specific data | ||
| 46 | * @indio_dev: the industrial I/O device | ||
| 47 | * @us: spi_device | ||
| 48 | * @chip_info: chip model specific constants, available modes etc | ||
| 49 | * @reg: supply regulator | ||
| 50 | * @vref_mv: actual reference voltage used | ||
| 51 | * @pwr_down_mask power down mask | ||
| 52 | * @pwr_down_mode current power down mode | ||
| 53 | */ | ||
| 54 | |||
| 55 | struct ad5624r_state { | ||
| 56 | struct spi_device *us; | ||
| 57 | const struct ad5624r_chip_info *chip_info; | ||
| 58 | struct regulator *reg; | ||
| 59 | unsigned short vref_mv; | ||
| 60 | unsigned pwr_down_mask; | ||
| 61 | unsigned pwr_down_mode; | ||
| 62 | }; | ||
| 63 | |||
| 64 | /** | ||
| 65 | * ad5624r_supported_device_ids: | ||
| 66 | * The AD5624/44/64 parts are available in different | ||
| 67 | * fixed internal reference voltage options. | ||
| 68 | */ | ||
| 69 | |||
| 70 | enum ad5624r_supported_device_ids { | ||
| 71 | ID_AD5624R3, | ||
| 72 | ID_AD5644R3, | ||
| 73 | ID_AD5664R3, | ||
| 74 | ID_AD5624R5, | ||
| 75 | ID_AD5644R5, | ||
| 76 | ID_AD5664R5, | ||
| 77 | }; | ||
| 78 | |||
| 79 | #endif /* SPI_AD5624R_H_ */ | ||
diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c new file mode 100644 index 00000000000..a5b3776718e --- /dev/null +++ b/drivers/staging/iio/dac/ad5624r_spi.c | |||
| @@ -0,0 +1,336 @@ | |||
| 1 | /* | ||
| 2 | * AD5624R, AD5644R, AD5664R Digital to analog convertors spi driver | ||
| 3 | * | ||
| 4 | * Copyright 2010-2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/gpio.h> | ||
| 11 | #include <linux/fs.h> | ||
| 12 | #include <linux/device.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/spi/spi.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/sysfs.h> | ||
| 17 | #include <linux/regulator/consumer.h> | ||
| 18 | |||
| 19 | #include "../iio.h" | ||
| 20 | #include "../sysfs.h" | ||
| 21 | #include "dac.h" | ||
| 22 | #include "ad5624r.h" | ||
| 23 | |||
| 24 | static const struct ad5624r_chip_info ad5624r_chip_info_tbl[] = { | ||
| 25 | [ID_AD5624R3] = { | ||
| 26 | .bits = 12, | ||
| 27 | .int_vref_mv = 1250, | ||
| 28 | }, | ||
| 29 | [ID_AD5644R3] = { | ||
| 30 | .bits = 14, | ||
| 31 | .int_vref_mv = 1250, | ||
| 32 | }, | ||
| 33 | [ID_AD5664R3] = { | ||
| 34 | .bits = 16, | ||
| 35 | .int_vref_mv = 1250, | ||
| 36 | }, | ||
| 37 | [ID_AD5624R5] = { | ||
| 38 | .bits = 12, | ||
| 39 | .int_vref_mv = 2500, | ||
| 40 | }, | ||
| 41 | [ID_AD5644R5] = { | ||
| 42 | .bits = 14, | ||
| 43 | .int_vref_mv = 2500, | ||
| 44 | }, | ||
| 45 | [ID_AD5664R5] = { | ||
| 46 | .bits = 16, | ||
| 47 | .int_vref_mv = 2500, | ||
| 48 | }, | ||
| 49 | }; | ||
| 50 | |||
| 51 | static int ad5624r_spi_write(struct spi_device *spi, | ||
| 52 | u8 cmd, u8 addr, u16 val, u8 len) | ||
| 53 | { | ||
| 54 | u32 data; | ||
| 55 | u8 msg[3]; | ||
| 56 | |||
| 57 | /* | ||
| 58 | * The input shift register is 24 bits wide. The first two bits are | ||
| 59 | * don't care bits. The next three are the command bits, C2 to C0, | ||
| 60 | * followed by the 3-bit DAC address, A2 to A0, and then the | ||
| 61 | * 16-, 14-, 12-bit data-word. The data-word comprises the 16-, | ||
| 62 | * 14-, 12-bit input code followed by 0, 2, or 4 don't care bits, | ||
| 63 | * for the AD5664R, AD5644R, and AD5624R, respectively. | ||
| 64 | */ | ||
| 65 | data = (0 << 22) | (cmd << 19) | (addr << 16) | (val << (16 - len)); | ||
| 66 | msg[0] = data >> 16; | ||
| 67 | msg[1] = data >> 8; | ||
| 68 | msg[2] = data; | ||
| 69 | |||
| 70 | return spi_write(spi, msg, 3); | ||
| 71 | } | ||
| 72 | |||
| 73 | static ssize_t ad5624r_write_dac(struct device *dev, | ||
| 74 | struct device_attribute *attr, | ||
| 75 | const char *buf, size_t len) | ||
| 76 | { | ||
| 77 | long readin; | ||
| 78 | int ret; | ||
| 79 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 80 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
| 81 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 82 | |||
| 83 | ret = strict_strtol(buf, 10, &readin); | ||
| 84 | if (ret) | ||
| 85 | return ret; | ||
| 86 | |||
| 87 | ret = ad5624r_spi_write(st->us, AD5624R_CMD_WRITE_INPUT_N_UPDATE_N, | ||
| 88 | this_attr->address, readin, | ||
| 89 | st->chip_info->bits); | ||
| 90 | return ret ? ret : len; | ||
| 91 | } | ||
| 92 | |||
| 93 | static ssize_t ad5624r_read_powerdown_mode(struct device *dev, | ||
| 94 | struct device_attribute *attr, char *buf) | ||
| 95 | { | ||
| 96 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 97 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
| 98 | |||
| 99 | char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"}; | ||
| 100 | |||
| 101 | return sprintf(buf, "%s\n", mode[st->pwr_down_mode]); | ||
| 102 | } | ||
| 103 | |||
| 104 | static ssize_t ad5624r_write_powerdown_mode(struct device *dev, | ||
| 105 | struct device_attribute *attr, | ||
| 106 | const char *buf, size_t len) | ||
| 107 | { | ||
| 108 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 109 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
| 110 | int ret; | ||
| 111 | |||
| 112 | if (sysfs_streq(buf, "1kohm_to_gnd")) | ||
| 113 | st->pwr_down_mode = AD5624R_LDAC_PWRDN_1K; | ||
| 114 | else if (sysfs_streq(buf, "100kohm_to_gnd")) | ||
| 115 | st->pwr_down_mode = AD5624R_LDAC_PWRDN_100K; | ||
| 116 | else if (sysfs_streq(buf, "three_state")) | ||
| 117 | st->pwr_down_mode = AD5624R_LDAC_PWRDN_3STATE; | ||
| 118 | else | ||
| 119 | ret = -EINVAL; | ||
| 120 | |||
| 121 | return ret ? ret : len; | ||
| 122 | } | ||
| 123 | |||
| 124 | static ssize_t ad5624r_read_dac_powerdown(struct device *dev, | ||
| 125 | struct device_attribute *attr, | ||
| 126 | char *buf) | ||
| 127 | { | ||
| 128 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 129 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
| 130 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 131 | |||
| 132 | return sprintf(buf, "%d\n", | ||
| 133 | !!(st->pwr_down_mask & (1 << this_attr->address))); | ||
| 134 | } | ||
| 135 | |||
| 136 | static ssize_t ad5624r_write_dac_powerdown(struct device *dev, | ||
| 137 | struct device_attribute *attr, | ||
| 138 | const char *buf, size_t len) | ||
| 139 | { | ||
| 140 | long readin; | ||
| 141 | int ret; | ||
| 142 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 143 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
| 144 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 145 | |||
| 146 | ret = strict_strtol(buf, 10, &readin); | ||
| 147 | if (ret) | ||
| 148 | return ret; | ||
| 149 | |||
| 150 | if (readin == 1) | ||
| 151 | st->pwr_down_mask |= (1 << this_attr->address); | ||
| 152 | else if (!readin) | ||
| 153 | st->pwr_down_mask &= ~(1 << this_attr->address); | ||
| 154 | else | ||
| 155 | ret = -EINVAL; | ||
| 156 | |||
| 157 | ret = ad5624r_spi_write(st->us, AD5624R_CMD_POWERDOWN_DAC, 0, | ||
| 158 | (st->pwr_down_mode << 4) | | ||
| 159 | st->pwr_down_mask, 16); | ||
| 160 | |||
| 161 | return ret ? ret : len; | ||
| 162 | } | ||
| 163 | |||
| 164 | static ssize_t ad5624r_show_scale(struct device *dev, | ||
| 165 | struct device_attribute *attr, | ||
| 166 | char *buf) | ||
| 167 | { | ||
| 168 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 169 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
| 170 | /* Corresponds to Vref / 2^(bits) */ | ||
| 171 | unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits; | ||
| 172 | |||
| 173 | return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); | ||
| 174 | } | ||
| 175 | static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5624r_show_scale, NULL, 0); | ||
| 176 | |||
| 177 | static IIO_DEV_ATTR_OUT_RAW(0, ad5624r_write_dac, AD5624R_ADDR_DAC0); | ||
| 178 | static IIO_DEV_ATTR_OUT_RAW(1, ad5624r_write_dac, AD5624R_ADDR_DAC1); | ||
| 179 | static IIO_DEV_ATTR_OUT_RAW(2, ad5624r_write_dac, AD5624R_ADDR_DAC2); | ||
| 180 | static IIO_DEV_ATTR_OUT_RAW(3, ad5624r_write_dac, AD5624R_ADDR_DAC3); | ||
| 181 | |||
| 182 | static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | | ||
| 183 | S_IWUSR, ad5624r_read_powerdown_mode, | ||
| 184 | ad5624r_write_powerdown_mode, 0); | ||
| 185 | |||
| 186 | static IIO_CONST_ATTR(out_powerdown_mode_available, | ||
| 187 | "1kohm_to_gnd 100kohm_to_gnd three_state"); | ||
| 188 | |||
| 189 | #define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr) \ | ||
| 190 | IIO_DEVICE_ATTR(out##_num##_powerdown, \ | ||
| 191 | S_IRUGO | S_IWUSR, _show, _store, _addr) | ||
| 192 | |||
| 193 | static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5624r_read_dac_powerdown, | ||
| 194 | ad5624r_write_dac_powerdown, 0); | ||
| 195 | static IIO_DEV_ATTR_DAC_POWERDOWN(1, ad5624r_read_dac_powerdown, | ||
| 196 | ad5624r_write_dac_powerdown, 1); | ||
| 197 | static IIO_DEV_ATTR_DAC_POWERDOWN(2, ad5624r_read_dac_powerdown, | ||
| 198 | ad5624r_write_dac_powerdown, 2); | ||
| 199 | static IIO_DEV_ATTR_DAC_POWERDOWN(3, ad5624r_read_dac_powerdown, | ||
| 200 | ad5624r_write_dac_powerdown, 3); | ||
| 201 | |||
| 202 | static struct attribute *ad5624r_attributes[] = { | ||
| 203 | &iio_dev_attr_out0_raw.dev_attr.attr, | ||
| 204 | &iio_dev_attr_out1_raw.dev_attr.attr, | ||
| 205 | &iio_dev_attr_out2_raw.dev_attr.attr, | ||
| 206 | &iio_dev_attr_out3_raw.dev_attr.attr, | ||
| 207 | &iio_dev_attr_out0_powerdown.dev_attr.attr, | ||
| 208 | &iio_dev_attr_out1_powerdown.dev_attr.attr, | ||
| 209 | &iio_dev_attr_out2_powerdown.dev_attr.attr, | ||
| 210 | &iio_dev_attr_out3_powerdown.dev_attr.attr, | ||
| 211 | &iio_dev_attr_out_powerdown_mode.dev_attr.attr, | ||
| 212 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, | ||
| 213 | &iio_dev_attr_out_scale.dev_attr.attr, | ||
| 214 | NULL, | ||
| 215 | }; | ||
| 216 | |||
| 217 | static const struct attribute_group ad5624r_attribute_group = { | ||
| 218 | .attrs = ad5624r_attributes, | ||
| 219 | }; | ||
| 220 | |||
| 221 | static const struct iio_info ad5624r_info = { | ||
| 222 | .attrs = &ad5624r_attribute_group, | ||
| 223 | .driver_module = THIS_MODULE, | ||
| 224 | }; | ||
| 225 | |||
| 226 | static int __devinit ad5624r_probe(struct spi_device *spi) | ||
| 227 | { | ||
| 228 | struct ad5624r_state *st; | ||
| 229 | struct iio_dev *indio_dev; | ||
| 230 | struct regulator *reg; | ||
| 231 | int ret, voltage_uv = 0; | ||
| 232 | |||
| 233 | reg = regulator_get(&spi->dev, "vcc"); | ||
| 234 | if (!IS_ERR(reg)) { | ||
| 235 | ret = regulator_enable(reg); | ||
| 236 | if (ret) | ||
| 237 | goto error_put_reg; | ||
| 238 | |||
| 239 | voltage_uv = regulator_get_voltage(reg); | ||
| 240 | } | ||
| 241 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
| 242 | if (indio_dev == NULL) { | ||
| 243 | ret = -ENOMEM; | ||
| 244 | goto error_disable_reg; | ||
| 245 | } | ||
| 246 | st = iio_priv(indio_dev); | ||
| 247 | st->reg = reg; | ||
| 248 | spi_set_drvdata(spi, indio_dev); | ||
| 249 | st->chip_info = | ||
| 250 | &ad5624r_chip_info_tbl[spi_get_device_id(spi)->driver_data]; | ||
| 251 | |||
| 252 | if (voltage_uv) | ||
| 253 | st->vref_mv = voltage_uv / 1000; | ||
| 254 | else | ||
| 255 | st->vref_mv = st->chip_info->int_vref_mv; | ||
| 256 | |||
| 257 | st->us = spi; | ||
| 258 | |||
| 259 | indio_dev->dev.parent = &spi->dev; | ||
| 260 | indio_dev->name = spi_get_device_id(spi)->name; | ||
| 261 | indio_dev->info = &ad5624r_info; | ||
| 262 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 263 | |||
| 264 | ret = iio_device_register(indio_dev); | ||
| 265 | if (ret) | ||
| 266 | goto error_free_dev; | ||
| 267 | |||
| 268 | ret = ad5624r_spi_write(spi, AD5624R_CMD_INTERNAL_REFER_SETUP, 0, | ||
| 269 | !!voltage_uv, 16); | ||
| 270 | if (ret) | ||
| 271 | goto error_free_dev; | ||
| 272 | |||
| 273 | return 0; | ||
| 274 | |||
| 275 | error_free_dev: | ||
| 276 | iio_free_device(indio_dev); | ||
| 277 | error_disable_reg: | ||
| 278 | if (!IS_ERR(reg)) | ||
| 279 | regulator_disable(reg); | ||
| 280 | error_put_reg: | ||
| 281 | if (!IS_ERR(reg)) | ||
| 282 | regulator_put(reg); | ||
| 283 | |||
| 284 | return ret; | ||
| 285 | } | ||
| 286 | |||
| 287 | static int __devexit ad5624r_remove(struct spi_device *spi) | ||
| 288 | { | ||
| 289 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 290 | struct ad5624r_state *st = iio_priv(indio_dev); | ||
| 291 | struct regulator *reg = st->reg; | ||
| 292 | |||
| 293 | iio_device_unregister(indio_dev); | ||
| 294 | if (!IS_ERR(reg)) { | ||
| 295 | regulator_disable(reg); | ||
| 296 | regulator_put(reg); | ||
| 297 | } | ||
| 298 | |||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | |||
| 302 | static const struct spi_device_id ad5624r_id[] = { | ||
| 303 | {"ad5624r3", ID_AD5624R3}, | ||
| 304 | {"ad5644r3", ID_AD5644R3}, | ||
| 305 | {"ad5664r3", ID_AD5664R3}, | ||
| 306 | {"ad5624r5", ID_AD5624R5}, | ||
| 307 | {"ad5644r5", ID_AD5644R5}, | ||
| 308 | {"ad5664r5", ID_AD5664R5}, | ||
| 309 | {} | ||
| 310 | }; | ||
| 311 | |||
| 312 | static struct spi_driver ad5624r_driver = { | ||
| 313 | .driver = { | ||
| 314 | .name = "ad5624r", | ||
| 315 | .owner = THIS_MODULE, | ||
| 316 | }, | ||
| 317 | .probe = ad5624r_probe, | ||
| 318 | .remove = __devexit_p(ad5624r_remove), | ||
| 319 | .id_table = ad5624r_id, | ||
| 320 | }; | ||
| 321 | |||
| 322 | static __init int ad5624r_spi_init(void) | ||
| 323 | { | ||
| 324 | return spi_register_driver(&ad5624r_driver); | ||
| 325 | } | ||
| 326 | module_init(ad5624r_spi_init); | ||
| 327 | |||
| 328 | static __exit void ad5624r_spi_exit(void) | ||
| 329 | { | ||
| 330 | spi_unregister_driver(&ad5624r_driver); | ||
| 331 | } | ||
| 332 | module_exit(ad5624r_spi_exit); | ||
| 333 | |||
| 334 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | ||
| 335 | MODULE_DESCRIPTION("Analog Devices AD5624/44/64R DAC spi driver"); | ||
| 336 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/dac/ad5686.c b/drivers/staging/iio/dac/ad5686.c new file mode 100644 index 00000000000..fd67cfa5edb --- /dev/null +++ b/drivers/staging/iio/dac/ad5686.c | |||
| @@ -0,0 +1,497 @@ | |||
| 1 | /* | ||
| 2 | * AD5686R, AD5685R, AD5684R Digital to analog converters driver | ||
| 3 | * | ||
| 4 | * Copyright 2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/gpio.h> | ||
| 11 | #include <linux/fs.h> | ||
| 12 | #include <linux/device.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/spi/spi.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/sysfs.h> | ||
| 17 | #include <linux/regulator/consumer.h> | ||
| 18 | |||
| 19 | #include "../iio.h" | ||
| 20 | #include "../sysfs.h" | ||
| 21 | #include "dac.h" | ||
| 22 | |||
| 23 | #define AD5686_DAC_CHANNELS 4 | ||
| 24 | |||
| 25 | #define AD5686_ADDR(x) ((x) << 16) | ||
| 26 | #define AD5686_CMD(x) ((x) << 20) | ||
| 27 | |||
| 28 | #define AD5686_ADDR_DAC0 0x1 | ||
| 29 | #define AD5686_ADDR_DAC1 0x2 | ||
| 30 | #define AD5686_ADDR_DAC2 0x4 | ||
| 31 | #define AD5686_ADDR_DAC3 0x8 | ||
| 32 | #define AD5686_ADDR_ALL_DAC 0xF | ||
| 33 | |||
| 34 | #define AD5686_CMD_NOOP 0x0 | ||
| 35 | #define AD5686_CMD_WRITE_INPUT_N 0x1 | ||
| 36 | #define AD5686_CMD_UPDATE_DAC_N 0x2 | ||
| 37 | #define AD5686_CMD_WRITE_INPUT_N_UPDATE_N 0x3 | ||
| 38 | #define AD5686_CMD_POWERDOWN_DAC 0x4 | ||
| 39 | #define AD5686_CMD_LDAC_MASK 0x5 | ||
| 40 | #define AD5686_CMD_RESET 0x6 | ||
| 41 | #define AD5686_CMD_INTERNAL_REFER_SETUP 0x7 | ||
| 42 | #define AD5686_CMD_DAISY_CHAIN_ENABLE 0x8 | ||
| 43 | #define AD5686_CMD_READBACK_ENABLE 0x9 | ||
| 44 | |||
| 45 | #define AD5686_LDAC_PWRDN_NONE 0x0 | ||
| 46 | #define AD5686_LDAC_PWRDN_1K 0x1 | ||
| 47 | #define AD5686_LDAC_PWRDN_100K 0x2 | ||
| 48 | #define AD5686_LDAC_PWRDN_3STATE 0x3 | ||
| 49 | |||
| 50 | /** | ||
| 51 | * struct ad5686_chip_info - chip specific information | ||
| 52 | * @int_vref_mv: AD5620/40/60: the internal reference voltage | ||
| 53 | * @channel: channel specification | ||
| 54 | */ | ||
| 55 | |||
| 56 | struct ad5686_chip_info { | ||
| 57 | u16 int_vref_mv; | ||
| 58 | struct iio_chan_spec channel[AD5686_DAC_CHANNELS]; | ||
| 59 | }; | ||
| 60 | |||
| 61 | /** | ||
| 62 | * struct ad5446_state - driver instance specific data | ||
| 63 | * @spi: spi_device | ||
| 64 | * @chip_info: chip model specific constants, available modes etc | ||
| 65 | * @reg: supply regulator | ||
| 66 | * @vref_mv: actual reference voltage used | ||
| 67 | * @pwr_down_mask: power down mask | ||
| 68 | * @pwr_down_mode: current power down mode | ||
| 69 | * @data: spi transfer buffers | ||
| 70 | */ | ||
| 71 | |||
| 72 | struct ad5686_state { | ||
| 73 | struct spi_device *spi; | ||
| 74 | const struct ad5686_chip_info *chip_info; | ||
| 75 | struct regulator *reg; | ||
| 76 | unsigned short vref_mv; | ||
| 77 | unsigned pwr_down_mask; | ||
| 78 | unsigned pwr_down_mode; | ||
| 79 | /* | ||
| 80 | * DMA (thus cache coherency maintenance) requires the | ||
| 81 | * transfer buffers to live in their own cache lines. | ||
| 82 | */ | ||
| 83 | |||
| 84 | union { | ||
| 85 | u32 d32; | ||
| 86 | u8 d8[4]; | ||
| 87 | } data[3] ____cacheline_aligned; | ||
| 88 | }; | ||
| 89 | |||
| 90 | /** | ||
| 91 | * ad5686_supported_device_ids: | ||
| 92 | */ | ||
| 93 | |||
| 94 | enum ad5686_supported_device_ids { | ||
| 95 | ID_AD5684, | ||
| 96 | ID_AD5685, | ||
| 97 | ID_AD5686, | ||
| 98 | }; | ||
| 99 | |||
| 100 | static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { | ||
| 101 | [ID_AD5684] = { | ||
| 102 | .channel[0] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 0, 0, | ||
| 103 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 104 | AD5686_ADDR_DAC0, | ||
| 105 | 0, IIO_ST('u', 12, 16, 4), 0), | ||
| 106 | .channel[1] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 1, 0, | ||
| 107 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 108 | AD5686_ADDR_DAC1, | ||
| 109 | 1, IIO_ST('u', 12, 16, 4), 0), | ||
| 110 | .channel[2] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 2, 0, | ||
| 111 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 112 | AD5686_ADDR_DAC2, | ||
| 113 | 2, IIO_ST('u', 12, 16, 4), 0), | ||
| 114 | .channel[3] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 3, 0, | ||
| 115 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 116 | AD5686_ADDR_DAC3, | ||
| 117 | 3, IIO_ST('u', 12, 16, 4), 0), | ||
| 118 | .int_vref_mv = 2500, | ||
| 119 | }, | ||
| 120 | [ID_AD5685] = { | ||
| 121 | .channel[0] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 0, 0, | ||
| 122 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 123 | AD5686_ADDR_DAC0, | ||
| 124 | 0, IIO_ST('u', 14, 16, 2), 0), | ||
| 125 | .channel[1] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 1, 0, | ||
| 126 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 127 | AD5686_ADDR_DAC1, | ||
| 128 | 1, IIO_ST('u', 14, 16, 2), 0), | ||
| 129 | .channel[2] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 2, 0, | ||
| 130 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 131 | AD5686_ADDR_DAC2, | ||
| 132 | 2, IIO_ST('u', 14, 16, 2), 0), | ||
| 133 | .channel[3] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 3, 0, | ||
| 134 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 135 | AD5686_ADDR_DAC3, | ||
| 136 | 3, IIO_ST('u', 14, 16, 2), 0), | ||
| 137 | .int_vref_mv = 2500, | ||
| 138 | }, | ||
| 139 | [ID_AD5686] = { | ||
| 140 | .channel[0] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 0, 0, | ||
| 141 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 142 | AD5686_ADDR_DAC0, | ||
| 143 | 0, IIO_ST('u', 16, 16, 0), 0), | ||
| 144 | .channel[1] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 1, 0, | ||
| 145 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 146 | AD5686_ADDR_DAC1, | ||
| 147 | 1, IIO_ST('u', 16, 16, 0), 0), | ||
| 148 | .channel[2] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 2, 0, | ||
| 149 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 150 | AD5686_ADDR_DAC2, | ||
| 151 | 2, IIO_ST('u', 16, 16, 0), 0), | ||
| 152 | .channel[3] = IIO_CHAN(IIO_OUT, 0, 1, 0, NULL, 3, 0, | ||
| 153 | (1 << IIO_CHAN_INFO_SCALE_SHARED), | ||
| 154 | AD5686_ADDR_DAC3, | ||
| 155 | 3, IIO_ST('u', 16, 16, 0), 0), | ||
| 156 | .int_vref_mv = 2500, | ||
| 157 | }, | ||
| 158 | }; | ||
| 159 | |||
| 160 | static int ad5686_spi_write(struct ad5686_state *st, | ||
| 161 | u8 cmd, u8 addr, u16 val, u8 shift) | ||
| 162 | { | ||
| 163 | val <<= shift; | ||
| 164 | |||
| 165 | st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | | ||
| 166 | AD5686_ADDR(addr) | | ||
| 167 | val); | ||
| 168 | |||
| 169 | return spi_write(st->spi, &st->data[0].d8[1], 3); | ||
| 170 | } | ||
| 171 | |||
| 172 | static int ad5686_spi_read(struct ad5686_state *st, u8 addr) | ||
| 173 | { | ||
| 174 | struct spi_transfer t[] = { | ||
| 175 | { | ||
| 176 | .tx_buf = &st->data[0].d8[1], | ||
| 177 | .len = 3, | ||
| 178 | .cs_change = 1, | ||
| 179 | }, { | ||
| 180 | .tx_buf = &st->data[1].d8[1], | ||
| 181 | .rx_buf = &st->data[2].d8[1], | ||
| 182 | .len = 3, | ||
| 183 | }, | ||
| 184 | }; | ||
| 185 | struct spi_message m; | ||
| 186 | int ret; | ||
| 187 | |||
| 188 | spi_message_init(&m); | ||
| 189 | spi_message_add_tail(&t[0], &m); | ||
| 190 | spi_message_add_tail(&t[1], &m); | ||
| 191 | |||
| 192 | st->data[0].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_READBACK_ENABLE) | | ||
| 193 | AD5686_ADDR(addr)); | ||
| 194 | st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP)); | ||
| 195 | |||
| 196 | ret = spi_sync(st->spi, &m); | ||
| 197 | if (ret < 0) | ||
| 198 | return ret; | ||
| 199 | |||
| 200 | return be32_to_cpu(st->data[2].d32); | ||
| 201 | } | ||
| 202 | |||
| 203 | static ssize_t ad5686_read_powerdown_mode(struct device *dev, | ||
| 204 | struct device_attribute *attr, char *buf) | ||
| 205 | { | ||
| 206 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 207 | struct ad5686_state *st = iio_priv(indio_dev); | ||
| 208 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 209 | |||
| 210 | char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"}; | ||
| 211 | |||
| 212 | return sprintf(buf, "%s\n", mode[(st->pwr_down_mode >> | ||
| 213 | (this_attr->address * 2)) & 0x3]); | ||
| 214 | } | ||
| 215 | |||
| 216 | static ssize_t ad5686_write_powerdown_mode(struct device *dev, | ||
| 217 | struct device_attribute *attr, | ||
| 218 | const char *buf, size_t len) | ||
| 219 | { | ||
| 220 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 221 | struct ad5686_state *st = iio_priv(indio_dev); | ||
| 222 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 223 | unsigned mode; | ||
| 224 | |||
| 225 | if (sysfs_streq(buf, "1kohm_to_gnd")) | ||
| 226 | mode = AD5686_LDAC_PWRDN_1K; | ||
| 227 | else if (sysfs_streq(buf, "100kohm_to_gnd")) | ||
| 228 | mode = AD5686_LDAC_PWRDN_100K; | ||
| 229 | else if (sysfs_streq(buf, "three_state")) | ||
| 230 | mode = AD5686_LDAC_PWRDN_3STATE; | ||
| 231 | else | ||
| 232 | return -EINVAL; | ||
| 233 | |||
| 234 | st->pwr_down_mode &= ~(0x3 << (this_attr->address * 2)); | ||
| 235 | st->pwr_down_mode |= (mode << (this_attr->address * 2)); | ||
| 236 | |||
| 237 | return len; | ||
| 238 | } | ||
| 239 | |||
| 240 | static ssize_t ad5686_read_dac_powerdown(struct device *dev, | ||
| 241 | struct device_attribute *attr, | ||
| 242 | char *buf) | ||
| 243 | { | ||
| 244 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 245 | struct ad5686_state *st = iio_priv(indio_dev); | ||
| 246 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 247 | |||
| 248 | return sprintf(buf, "%d\n", !!(st->pwr_down_mask & | ||
| 249 | (0x3 << (this_attr->address * 2)))); | ||
| 250 | } | ||
| 251 | |||
| 252 | static ssize_t ad5686_write_dac_powerdown(struct device *dev, | ||
| 253 | struct device_attribute *attr, | ||
| 254 | const char *buf, size_t len) | ||
| 255 | { | ||
| 256 | bool readin; | ||
| 257 | int ret; | ||
| 258 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 259 | struct ad5686_state *st = iio_priv(indio_dev); | ||
| 260 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 261 | |||
| 262 | ret = strtobool(buf, &readin); | ||
| 263 | if (ret) | ||
| 264 | return ret; | ||
| 265 | |||
| 266 | if (readin == true) | ||
| 267 | st->pwr_down_mask |= (0x3 << (this_attr->address * 2)); | ||
| 268 | else | ||
| 269 | st->pwr_down_mask &= ~(0x3 << (this_attr->address * 2)); | ||
| 270 | |||
| 271 | ret = ad5686_spi_write(st, AD5686_CMD_POWERDOWN_DAC, 0, | ||
| 272 | st->pwr_down_mask & st->pwr_down_mode, 0); | ||
| 273 | |||
| 274 | return ret ? ret : len; | ||
| 275 | } | ||
| 276 | |||
| 277 | static IIO_CONST_ATTR(out_powerdown_mode_available, | ||
| 278 | "1kohm_to_gnd 100kohm_to_gnd three_state"); | ||
| 279 | |||
| 280 | #define IIO_DEV_ATTR_DAC_POWERDOWN_MODE(_num) \ | ||
| 281 | IIO_DEVICE_ATTR(out##_num##_powerdown_mode, S_IRUGO | S_IWUSR, \ | ||
| 282 | ad5686_read_powerdown_mode, \ | ||
| 283 | ad5686_write_powerdown_mode, _num) | ||
| 284 | |||
| 285 | static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(0); | ||
| 286 | static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(1); | ||
| 287 | static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(2); | ||
| 288 | static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(3); | ||
| 289 | |||
| 290 | #define IIO_DEV_ATTR_DAC_POWERDOWN(_num) \ | ||
| 291 | IIO_DEVICE_ATTR(out##_num##_powerdown, S_IRUGO | S_IWUSR, \ | ||
| 292 | ad5686_read_dac_powerdown, \ | ||
| 293 | ad5686_write_dac_powerdown, _num) | ||
| 294 | |||
| 295 | static IIO_DEV_ATTR_DAC_POWERDOWN(0); | ||
| 296 | static IIO_DEV_ATTR_DAC_POWERDOWN(1); | ||
| 297 | static IIO_DEV_ATTR_DAC_POWERDOWN(2); | ||
| 298 | static IIO_DEV_ATTR_DAC_POWERDOWN(3); | ||
| 299 | |||
| 300 | static struct attribute *ad5686_attributes[] = { | ||
| 301 | &iio_dev_attr_out0_powerdown.dev_attr.attr, | ||
| 302 | &iio_dev_attr_out1_powerdown.dev_attr.attr, | ||
| 303 | &iio_dev_attr_out2_powerdown.dev_attr.attr, | ||
| 304 | &iio_dev_attr_out3_powerdown.dev_attr.attr, | ||
| 305 | &iio_dev_attr_out0_powerdown_mode.dev_attr.attr, | ||
| 306 | &iio_dev_attr_out1_powerdown_mode.dev_attr.attr, | ||
| 307 | &iio_dev_attr_out2_powerdown_mode.dev_attr.attr, | ||
| 308 | &iio_dev_attr_out3_powerdown_mode.dev_attr.attr, | ||
| 309 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, | ||
| 310 | NULL, | ||
| 311 | }; | ||
| 312 | |||
| 313 | static const struct attribute_group ad5686_attribute_group = { | ||
| 314 | .attrs = ad5686_attributes, | ||
| 315 | }; | ||
| 316 | |||
| 317 | static int ad5686_read_raw(struct iio_dev *indio_dev, | ||
| 318 | struct iio_chan_spec const *chan, | ||
| 319 | int *val, | ||
| 320 | int *val2, | ||
| 321 | long m) | ||
| 322 | { | ||
| 323 | struct ad5686_state *st = iio_priv(indio_dev); | ||
| 324 | unsigned long scale_uv; | ||
| 325 | int ret; | ||
| 326 | |||
| 327 | switch (m) { | ||
| 328 | case 0: | ||
| 329 | mutex_lock(&indio_dev->mlock); | ||
| 330 | ret = ad5686_spi_read(st, chan->address); | ||
| 331 | mutex_unlock(&indio_dev->mlock); | ||
| 332 | if (ret < 0) | ||
| 333 | return ret; | ||
| 334 | *val = ret; | ||
| 335 | return IIO_VAL_INT; | ||
| 336 | break; | ||
| 337 | case (1 << IIO_CHAN_INFO_SCALE_SHARED): | ||
| 338 | scale_uv = (st->vref_mv * 100000) | ||
| 339 | >> (chan->scan_type.realbits); | ||
| 340 | *val = scale_uv / 100000; | ||
| 341 | *val2 = (scale_uv % 100000) * 10; | ||
| 342 | return IIO_VAL_INT_PLUS_MICRO; | ||
| 343 | |||
| 344 | } | ||
| 345 | return -EINVAL; | ||
| 346 | } | ||
| 347 | |||
| 348 | static int ad5686_write_raw(struct iio_dev *indio_dev, | ||
| 349 | struct iio_chan_spec const *chan, | ||
| 350 | int val, | ||
| 351 | int val2, | ||
| 352 | long mask) | ||
| 353 | { | ||
| 354 | struct ad5686_state *st = iio_priv(indio_dev); | ||
| 355 | int ret; | ||
| 356 | |||
| 357 | switch (mask) { | ||
| 358 | case 0: | ||
| 359 | if (val > (1 << chan->scan_type.realbits)) | ||
| 360 | return -EINVAL; | ||
| 361 | |||
| 362 | mutex_lock(&indio_dev->mlock); | ||
| 363 | ret = ad5686_spi_write(st, | ||
| 364 | AD5686_CMD_WRITE_INPUT_N_UPDATE_N, | ||
| 365 | chan->address, | ||
| 366 | val, | ||
| 367 | chan->scan_type.shift); | ||
| 368 | mutex_unlock(&indio_dev->mlock); | ||
| 369 | break; | ||
| 370 | default: | ||
| 371 | ret = -EINVAL; | ||
| 372 | } | ||
| 373 | |||
| 374 | return ret; | ||
| 375 | } | ||
| 376 | |||
| 377 | static const struct iio_info ad5686_info = { | ||
| 378 | .read_raw = ad5686_read_raw, | ||
| 379 | .write_raw = ad5686_write_raw, | ||
| 380 | .attrs = &ad5686_attribute_group, | ||
| 381 | .driver_module = THIS_MODULE, | ||
| 382 | }; | ||
| 383 | |||
| 384 | static int __devinit ad5686_probe(struct spi_device *spi) | ||
| 385 | { | ||
| 386 | struct ad5686_state *st; | ||
| 387 | struct iio_dev *indio_dev; | ||
| 388 | int ret, regdone = 0, voltage_uv = 0; | ||
| 389 | |||
| 390 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
| 391 | if (indio_dev == NULL) | ||
| 392 | return -ENOMEM; | ||
| 393 | |||
| 394 | st = iio_priv(indio_dev); | ||
| 395 | spi_set_drvdata(spi, indio_dev); | ||
| 396 | |||
| 397 | st->reg = regulator_get(&spi->dev, "vcc"); | ||
| 398 | if (!IS_ERR(st->reg)) { | ||
| 399 | ret = regulator_enable(st->reg); | ||
| 400 | if (ret) | ||
| 401 | goto error_put_reg; | ||
| 402 | |||
| 403 | voltage_uv = regulator_get_voltage(st->reg); | ||
| 404 | } | ||
| 405 | |||
| 406 | st->chip_info = | ||
| 407 | &ad5686_chip_info_tbl[spi_get_device_id(spi)->driver_data]; | ||
| 408 | |||
| 409 | if (voltage_uv) | ||
| 410 | st->vref_mv = voltage_uv / 1000; | ||
| 411 | else | ||
| 412 | st->vref_mv = st->chip_info->int_vref_mv; | ||
| 413 | |||
| 414 | st->spi = spi; | ||
| 415 | |||
| 416 | indio_dev->dev.parent = &spi->dev; | ||
| 417 | indio_dev->name = spi_get_device_id(spi)->name; | ||
| 418 | indio_dev->info = &ad5686_info; | ||
| 419 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 420 | indio_dev->channels = st->chip_info->channel; | ||
| 421 | indio_dev->num_channels = AD5686_DAC_CHANNELS; | ||
| 422 | |||
| 423 | ret = iio_device_register(indio_dev); | ||
| 424 | if (ret) | ||
| 425 | goto error_disable_reg; | ||
| 426 | |||
| 427 | regdone = 1; | ||
| 428 | ret = ad5686_spi_write(st, AD5686_CMD_INTERNAL_REFER_SETUP, 0, | ||
| 429 | !!voltage_uv, 0); | ||
| 430 | if (ret) | ||
| 431 | goto error_disable_reg; | ||
| 432 | |||
| 433 | return 0; | ||
| 434 | |||
| 435 | error_disable_reg: | ||
| 436 | if (!IS_ERR(st->reg)) | ||
| 437 | regulator_disable(st->reg); | ||
| 438 | error_put_reg: | ||
| 439 | if (!IS_ERR(st->reg)) | ||
| 440 | regulator_put(st->reg); | ||
| 441 | |||
| 442 | if (regdone) | ||
| 443 | iio_device_unregister(indio_dev); | ||
| 444 | else | ||
| 445 | iio_free_device(indio_dev); | ||
| 446 | |||
| 447 | return ret; | ||
| 448 | } | ||
| 449 | |||
| 450 | static int __devexit ad5686_remove(struct spi_device *spi) | ||
| 451 | { | ||
| 452 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 453 | struct ad5686_state *st = iio_priv(indio_dev); | ||
| 454 | struct regulator *reg = st->reg; | ||
| 455 | |||
| 456 | if (!IS_ERR(reg)) { | ||
| 457 | regulator_disable(reg); | ||
| 458 | regulator_put(reg); | ||
| 459 | } | ||
| 460 | |||
| 461 | iio_device_unregister(indio_dev); | ||
| 462 | |||
| 463 | return 0; | ||
| 464 | } | ||
| 465 | |||
| 466 | static const struct spi_device_id ad5686_id[] = { | ||
| 467 | {"ad5684", ID_AD5684}, | ||
| 468 | {"ad5685", ID_AD5685}, | ||
| 469 | {"ad5686", ID_AD5686}, | ||
| 470 | {} | ||
| 471 | }; | ||
| 472 | |||
| 473 | static struct spi_driver ad5686_driver = { | ||
| 474 | .driver = { | ||
| 475 | .name = "ad5686", | ||
| 476 | .owner = THIS_MODULE, | ||
| 477 | }, | ||
| 478 | .probe = ad5686_probe, | ||
| 479 | .remove = __devexit_p(ad5686_remove), | ||
| 480 | .id_table = ad5686_id, | ||
| 481 | }; | ||
| 482 | |||
| 483 | static __init int ad5686_spi_init(void) | ||
| 484 | { | ||
| 485 | return spi_register_driver(&ad5686_driver); | ||
| 486 | } | ||
| 487 | module_init(ad5686_spi_init); | ||
| 488 | |||
| 489 | static __exit void ad5686_spi_exit(void) | ||
| 490 | { | ||
| 491 | spi_unregister_driver(&ad5686_driver); | ||
| 492 | } | ||
| 493 | module_exit(ad5686_spi_exit); | ||
| 494 | |||
| 495 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
| 496 | MODULE_DESCRIPTION("Analog Devices AD5686/85/84 DAC"); | ||
| 497 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/dac/ad5791.c b/drivers/staging/iio/dac/ad5791.c new file mode 100644 index 00000000000..64770d2a1b4 --- /dev/null +++ b/drivers/staging/iio/dac/ad5791.c | |||
| @@ -0,0 +1,442 @@ | |||
| 1 | /* | ||
| 2 | * AD5760, AD5780, AD5781, AD5791 Voltage Output Digital to Analog Converter | ||
| 3 | * | ||
| 4 | * Copyright 2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/gpio.h> | ||
| 11 | #include <linux/fs.h> | ||
| 12 | #include <linux/device.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/spi/spi.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/sysfs.h> | ||
| 17 | #include <linux/regulator/consumer.h> | ||
| 18 | |||
| 19 | #include "../iio.h" | ||
| 20 | #include "../sysfs.h" | ||
| 21 | #include "dac.h" | ||
| 22 | #include "ad5791.h" | ||
| 23 | |||
| 24 | static int ad5791_spi_write(struct spi_device *spi, u8 addr, u32 val) | ||
| 25 | { | ||
| 26 | union { | ||
| 27 | u32 d32; | ||
| 28 | u8 d8[4]; | ||
| 29 | } data; | ||
| 30 | |||
| 31 | data.d32 = cpu_to_be32(AD5791_CMD_WRITE | | ||
| 32 | AD5791_ADDR(addr) | | ||
| 33 | (val & AD5791_DAC_MASK)); | ||
| 34 | |||
| 35 | return spi_write(spi, &data.d8[1], 3); | ||
| 36 | } | ||
| 37 | |||
| 38 | static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val) | ||
| 39 | { | ||
| 40 | union { | ||
| 41 | u32 d32; | ||
| 42 | u8 d8[4]; | ||
| 43 | } data[3]; | ||
| 44 | int ret; | ||
| 45 | struct spi_message msg; | ||
| 46 | struct spi_transfer xfers[] = { | ||
| 47 | { | ||
| 48 | .tx_buf = &data[0].d8[1], | ||
| 49 | .bits_per_word = 8, | ||
| 50 | .len = 3, | ||
| 51 | .cs_change = 1, | ||
| 52 | }, { | ||
| 53 | .tx_buf = &data[1].d8[1], | ||
| 54 | .rx_buf = &data[2].d8[1], | ||
| 55 | .bits_per_word = 8, | ||
| 56 | .len = 3, | ||
| 57 | }, | ||
| 58 | }; | ||
| 59 | |||
| 60 | data[0].d32 = cpu_to_be32(AD5791_CMD_READ | | ||
| 61 | AD5791_ADDR(addr)); | ||
| 62 | data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP)); | ||
| 63 | |||
| 64 | spi_message_init(&msg); | ||
| 65 | spi_message_add_tail(&xfers[0], &msg); | ||
| 66 | spi_message_add_tail(&xfers[1], &msg); | ||
| 67 | ret = spi_sync(spi, &msg); | ||
| 68 | |||
| 69 | *val = be32_to_cpu(data[2].d32); | ||
| 70 | |||
| 71 | return ret; | ||
| 72 | } | ||
| 73 | |||
| 74 | static ssize_t ad5791_write_dac(struct device *dev, | ||
| 75 | struct device_attribute *attr, | ||
| 76 | const char *buf, size_t len) | ||
| 77 | { | ||
| 78 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 79 | struct ad5791_state *st = iio_priv(indio_dev); | ||
| 80 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 81 | long readin; | ||
| 82 | int ret; | ||
| 83 | |||
| 84 | ret = strict_strtol(buf, 10, &readin); | ||
| 85 | if (ret) | ||
| 86 | return ret; | ||
| 87 | |||
| 88 | readin += (1 << (st->chip_info->bits - 1)); | ||
| 89 | readin &= AD5791_RES_MASK(st->chip_info->bits); | ||
| 90 | readin <<= st->chip_info->left_shift; | ||
| 91 | |||
| 92 | ret = ad5791_spi_write(st->spi, this_attr->address, readin); | ||
| 93 | return ret ? ret : len; | ||
| 94 | } | ||
| 95 | |||
| 96 | static ssize_t ad5791_read_dac(struct device *dev, | ||
| 97 | struct device_attribute *attr, | ||
| 98 | char *buf) | ||
| 99 | { | ||
| 100 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 101 | struct ad5791_state *st = iio_priv(indio_dev); | ||
| 102 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 103 | int ret; | ||
| 104 | int val; | ||
| 105 | |||
| 106 | ret = ad5791_spi_read(st->spi, this_attr->address, &val); | ||
| 107 | if (ret) | ||
| 108 | return ret; | ||
| 109 | |||
| 110 | val &= AD5791_DAC_MASK; | ||
| 111 | val >>= st->chip_info->left_shift; | ||
| 112 | val -= (1 << (st->chip_info->bits - 1)); | ||
| 113 | |||
| 114 | return sprintf(buf, "%d\n", val); | ||
| 115 | } | ||
| 116 | |||
| 117 | static ssize_t ad5791_read_powerdown_mode(struct device *dev, | ||
| 118 | struct device_attribute *attr, char *buf) | ||
| 119 | { | ||
| 120 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 121 | struct ad5791_state *st = iio_priv(indio_dev); | ||
| 122 | |||
| 123 | const char mode[][14] = {"6kohm_to_gnd", "three_state"}; | ||
| 124 | |||
| 125 | return sprintf(buf, "%s\n", mode[st->pwr_down_mode]); | ||
| 126 | } | ||
| 127 | |||
| 128 | static ssize_t ad5791_write_powerdown_mode(struct device *dev, | ||
| 129 | struct device_attribute *attr, | ||
| 130 | const char *buf, size_t len) | ||
| 131 | { | ||
| 132 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 133 | struct ad5791_state *st = iio_priv(indio_dev); | ||
| 134 | int ret; | ||
| 135 | |||
| 136 | if (sysfs_streq(buf, "6kohm_to_gnd")) | ||
| 137 | st->pwr_down_mode = AD5791_DAC_PWRDN_6K; | ||
| 138 | else if (sysfs_streq(buf, "three_state")) | ||
| 139 | st->pwr_down_mode = AD5791_DAC_PWRDN_3STATE; | ||
| 140 | else | ||
| 141 | ret = -EINVAL; | ||
| 142 | |||
| 143 | return ret ? ret : len; | ||
| 144 | } | ||
| 145 | |||
| 146 | static ssize_t ad5791_read_dac_powerdown(struct device *dev, | ||
| 147 | struct device_attribute *attr, | ||
| 148 | char *buf) | ||
| 149 | { | ||
| 150 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 151 | struct ad5791_state *st = iio_priv(indio_dev); | ||
| 152 | |||
| 153 | return sprintf(buf, "%d\n", st->pwr_down); | ||
| 154 | } | ||
| 155 | |||
| 156 | static ssize_t ad5791_write_dac_powerdown(struct device *dev, | ||
| 157 | struct device_attribute *attr, | ||
| 158 | const char *buf, size_t len) | ||
| 159 | { | ||
| 160 | long readin; | ||
| 161 | int ret; | ||
| 162 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 163 | struct ad5791_state *st = iio_priv(indio_dev); | ||
| 164 | |||
| 165 | ret = strict_strtol(buf, 10, &readin); | ||
| 166 | if (ret) | ||
| 167 | return ret; | ||
| 168 | |||
| 169 | if (readin == 0) { | ||
| 170 | st->pwr_down = false; | ||
| 171 | st->ctrl &= ~(AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI); | ||
| 172 | } else if (readin == 1) { | ||
| 173 | st->pwr_down = true; | ||
| 174 | if (st->pwr_down_mode == AD5791_DAC_PWRDN_6K) | ||
| 175 | st->ctrl |= AD5791_CTRL_OPGND; | ||
| 176 | else if (st->pwr_down_mode == AD5791_DAC_PWRDN_3STATE) | ||
| 177 | st->ctrl |= AD5791_CTRL_DACTRI; | ||
| 178 | } else | ||
| 179 | ret = -EINVAL; | ||
| 180 | |||
| 181 | ret = ad5791_spi_write(st->spi, AD5791_ADDR_CTRL, st->ctrl); | ||
| 182 | |||
| 183 | return ret ? ret : len; | ||
| 184 | } | ||
| 185 | |||
| 186 | static ssize_t ad5791_show_scale(struct device *dev, | ||
| 187 | struct device_attribute *attr, | ||
| 188 | char *buf) | ||
| 189 | { | ||
| 190 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 191 | struct ad5791_state *st = iio_priv(indio_dev); | ||
| 192 | /* Corresponds to Vref / 2^(bits) */ | ||
| 193 | unsigned int scale_uv = (st->vref_mv * 1000) >> st->chip_info->bits; | ||
| 194 | |||
| 195 | return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); | ||
| 196 | } | ||
| 197 | static IIO_DEVICE_ATTR(out_scale, S_IRUGO, ad5791_show_scale, NULL, 0); | ||
| 198 | |||
| 199 | static ssize_t ad5791_show_name(struct device *dev, | ||
| 200 | struct device_attribute *attr, | ||
| 201 | char *buf) | ||
| 202 | { | ||
| 203 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 204 | struct ad5791_state *st = iio_priv(indio_dev); | ||
| 205 | |||
| 206 | return sprintf(buf, "%s\n", spi_get_device_id(st->spi)->name); | ||
| 207 | } | ||
| 208 | static IIO_DEVICE_ATTR(name, S_IRUGO, ad5791_show_name, NULL, 0); | ||
| 209 | |||
| 210 | #define IIO_DEV_ATTR_OUT_RW_RAW(_num, _show, _store, _addr) \ | ||
| 211 | IIO_DEVICE_ATTR(out##_num##_raw, \ | ||
| 212 | S_IRUGO | S_IWUSR, _show, _store, _addr) | ||
| 213 | |||
| 214 | static IIO_DEV_ATTR_OUT_RW_RAW(0, ad5791_read_dac, | ||
| 215 | ad5791_write_dac, AD5791_ADDR_DAC0); | ||
| 216 | |||
| 217 | static IIO_DEVICE_ATTR(out_powerdown_mode, S_IRUGO | | ||
| 218 | S_IWUSR, ad5791_read_powerdown_mode, | ||
| 219 | ad5791_write_powerdown_mode, 0); | ||
| 220 | |||
| 221 | static IIO_CONST_ATTR(out_powerdown_mode_available, | ||
| 222 | "6kohm_to_gnd three_state"); | ||
| 223 | |||
| 224 | #define IIO_DEV_ATTR_DAC_POWERDOWN(_num, _show, _store, _addr) \ | ||
| 225 | IIO_DEVICE_ATTR(out##_num##_powerdown, \ | ||
| 226 | S_IRUGO | S_IWUSR, _show, _store, _addr) | ||
| 227 | |||
| 228 | static IIO_DEV_ATTR_DAC_POWERDOWN(0, ad5791_read_dac_powerdown, | ||
| 229 | ad5791_write_dac_powerdown, 0); | ||
| 230 | |||
| 231 | static struct attribute *ad5791_attributes[] = { | ||
| 232 | &iio_dev_attr_out0_raw.dev_attr.attr, | ||
| 233 | &iio_dev_attr_out0_powerdown.dev_attr.attr, | ||
| 234 | &iio_dev_attr_out_powerdown_mode.dev_attr.attr, | ||
| 235 | &iio_const_attr_out_powerdown_mode_available.dev_attr.attr, | ||
| 236 | &iio_dev_attr_out_scale.dev_attr.attr, | ||
| 237 | &iio_dev_attr_name.dev_attr.attr, | ||
| 238 | NULL, | ||
| 239 | }; | ||
| 240 | |||
| 241 | static const struct attribute_group ad5791_attribute_group = { | ||
| 242 | .attrs = ad5791_attributes, | ||
| 243 | }; | ||
| 244 | |||
| 245 | static int ad5791_get_lin_comp(unsigned int span) | ||
| 246 | { | ||
| 247 | if (span <= 10000) | ||
| 248 | return AD5791_LINCOMP_0_10; | ||
| 249 | else if (span <= 12000) | ||
| 250 | return AD5791_LINCOMP_10_12; | ||
| 251 | else if (span <= 16000) | ||
| 252 | return AD5791_LINCOMP_12_16; | ||
| 253 | else if (span <= 19000) | ||
| 254 | return AD5791_LINCOMP_16_19; | ||
| 255 | else | ||
| 256 | return AD5791_LINCOMP_19_20; | ||
| 257 | } | ||
| 258 | |||
| 259 | static int ad5780_get_lin_comp(unsigned int span) | ||
| 260 | { | ||
| 261 | if (span <= 10000) | ||
| 262 | return AD5780_LINCOMP_0_10; | ||
| 263 | else | ||
| 264 | return AD5780_LINCOMP_10_20; | ||
| 265 | } | ||
| 266 | |||
| 267 | static const struct ad5791_chip_info ad5791_chip_info_tbl[] = { | ||
| 268 | [ID_AD5760] = { | ||
| 269 | .bits = 16, | ||
| 270 | .left_shift = 4, | ||
| 271 | .get_lin_comp = ad5780_get_lin_comp, | ||
| 272 | }, | ||
| 273 | [ID_AD5780] = { | ||
| 274 | .bits = 18, | ||
| 275 | .left_shift = 2, | ||
| 276 | .get_lin_comp = ad5780_get_lin_comp, | ||
| 277 | }, | ||
| 278 | [ID_AD5781] = { | ||
| 279 | .bits = 18, | ||
| 280 | .left_shift = 2, | ||
| 281 | .get_lin_comp = ad5791_get_lin_comp, | ||
| 282 | }, | ||
| 283 | [ID_AD5791] = { | ||
| 284 | .bits = 20, | ||
| 285 | .left_shift = 0, | ||
| 286 | .get_lin_comp = ad5791_get_lin_comp, | ||
| 287 | }, | ||
| 288 | }; | ||
| 289 | |||
| 290 | static const struct iio_info ad5791_info = { | ||
| 291 | .attrs = &ad5791_attribute_group, | ||
| 292 | .driver_module = THIS_MODULE, | ||
| 293 | }; | ||
| 294 | |||
| 295 | static int __devinit ad5791_probe(struct spi_device *spi) | ||
| 296 | { | ||
| 297 | struct ad5791_platform_data *pdata = spi->dev.platform_data; | ||
| 298 | struct iio_dev *indio_dev; | ||
| 299 | struct regulator *reg_vdd, *reg_vss; | ||
| 300 | struct ad5791_state *st; | ||
| 301 | int ret, pos_voltage_uv = 0, neg_voltage_uv = 0; | ||
| 302 | |||
| 303 | reg_vdd = regulator_get(&spi->dev, "vdd"); | ||
| 304 | if (!IS_ERR(reg_vdd)) { | ||
| 305 | ret = regulator_enable(reg_vdd); | ||
| 306 | if (ret) | ||
| 307 | goto error_put_reg_pos; | ||
| 308 | |||
| 309 | pos_voltage_uv = regulator_get_voltage(reg_vdd); | ||
| 310 | } | ||
| 311 | |||
| 312 | reg_vss = regulator_get(&spi->dev, "vss"); | ||
| 313 | if (!IS_ERR(reg_vss)) { | ||
| 314 | ret = regulator_enable(reg_vss); | ||
| 315 | if (ret) | ||
| 316 | goto error_put_reg_neg; | ||
| 317 | |||
| 318 | neg_voltage_uv = regulator_get_voltage(reg_vss); | ||
| 319 | } | ||
| 320 | |||
| 321 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
| 322 | if (indio_dev == NULL) { | ||
| 323 | ret = -ENOMEM; | ||
| 324 | goto error_disable_reg_neg; | ||
| 325 | } | ||
| 326 | st = iio_priv(indio_dev); | ||
| 327 | st->pwr_down = true; | ||
| 328 | st->spi = spi; | ||
| 329 | |||
| 330 | if (!IS_ERR(reg_vss) && !IS_ERR(reg_vdd)) | ||
| 331 | st->vref_mv = (pos_voltage_uv - neg_voltage_uv) / 1000; | ||
| 332 | else if (pdata) | ||
| 333 | st->vref_mv = pdata->vref_pos_mv - pdata->vref_neg_mv; | ||
| 334 | else | ||
| 335 | dev_warn(&spi->dev, "reference voltage unspecified\n"); | ||
| 336 | |||
| 337 | ret = ad5791_spi_write(spi, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET); | ||
| 338 | if (ret) | ||
| 339 | goto error_free_dev; | ||
| 340 | |||
| 341 | st->chip_info = | ||
| 342 | &ad5791_chip_info_tbl[spi_get_device_id(spi)->driver_data]; | ||
| 343 | |||
| 344 | |||
| 345 | st->ctrl = AD5761_CTRL_LINCOMP(st->chip_info->get_lin_comp(st->vref_mv)) | ||
| 346 | | ((pdata && pdata->use_rbuf_gain2) ? 0 : AD5791_CTRL_RBUF) | | ||
| 347 | AD5791_CTRL_BIN2SC; | ||
| 348 | |||
| 349 | ret = ad5791_spi_write(spi, AD5791_ADDR_CTRL, st->ctrl | | ||
| 350 | AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI); | ||
| 351 | if (ret) | ||
| 352 | goto error_free_dev; | ||
| 353 | |||
| 354 | st->reg_vdd = reg_vdd; | ||
| 355 | st->reg_vss = reg_vss; | ||
| 356 | |||
| 357 | spi_set_drvdata(spi, indio_dev); | ||
| 358 | indio_dev->dev.parent = &spi->dev; | ||
| 359 | indio_dev->info = &ad5791_info; | ||
| 360 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 361 | |||
| 362 | ret = iio_device_register(indio_dev); | ||
| 363 | if (ret) | ||
| 364 | goto error_free_dev; | ||
| 365 | |||
| 366 | return 0; | ||
| 367 | |||
| 368 | error_free_dev: | ||
| 369 | iio_free_device(indio_dev); | ||
| 370 | |||
| 371 | error_disable_reg_neg: | ||
| 372 | if (!IS_ERR(reg_vss)) | ||
| 373 | regulator_disable(reg_vss); | ||
| 374 | error_put_reg_neg: | ||
| 375 | if (!IS_ERR(reg_vss)) | ||
| 376 | regulator_put(reg_vss); | ||
| 377 | |||
| 378 | if (!IS_ERR(reg_vdd)) | ||
| 379 | regulator_disable(reg_vdd); | ||
| 380 | error_put_reg_pos: | ||
| 381 | if (!IS_ERR(reg_vdd)) | ||
| 382 | regulator_put(reg_vdd); | ||
| 383 | |||
| 384 | error_ret: | ||
| 385 | return ret; | ||
| 386 | } | ||
| 387 | |||
| 388 | static int __devexit ad5791_remove(struct spi_device *spi) | ||
| 389 | { | ||
| 390 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 391 | struct ad5791_state *st = iio_priv(indio_dev); | ||
| 392 | struct regulator *reg_vdd = st->reg_vdd; | ||
| 393 | struct regulator *reg_vss = st->reg_vss; | ||
| 394 | |||
| 395 | iio_device_unregister(indio_dev); | ||
| 396 | |||
| 397 | if (!IS_ERR(st->reg_vdd)) { | ||
| 398 | regulator_disable(reg_vdd); | ||
| 399 | regulator_put(reg_vdd); | ||
| 400 | } | ||
| 401 | |||
| 402 | if (!IS_ERR(st->reg_vss)) { | ||
| 403 | regulator_disable(reg_vss); | ||
| 404 | regulator_put(reg_vss); | ||
| 405 | } | ||
| 406 | |||
| 407 | return 0; | ||
| 408 | } | ||
| 409 | |||
| 410 | static const struct spi_device_id ad5791_id[] = { | ||
| 411 | {"ad5760", ID_AD5760}, | ||
| 412 | {"ad5780", ID_AD5780}, | ||
| 413 | {"ad5781", ID_AD5781}, | ||
| 414 | {"ad5791", ID_AD5791}, | ||
| 415 | {} | ||
| 416 | }; | ||
| 417 | |||
| 418 | static struct spi_driver ad5791_driver = { | ||
| 419 | .driver = { | ||
| 420 | .name = "ad5791", | ||
| 421 | .owner = THIS_MODULE, | ||
| 422 | }, | ||
| 423 | .probe = ad5791_probe, | ||
| 424 | .remove = __devexit_p(ad5791_remove), | ||
| 425 | .id_table = ad5791_id, | ||
| 426 | }; | ||
| 427 | |||
| 428 | static __init int ad5791_spi_init(void) | ||
| 429 | { | ||
| 430 | return spi_register_driver(&ad5791_driver); | ||
| 431 | } | ||
| 432 | module_init(ad5791_spi_init); | ||
| 433 | |||
| 434 | static __exit void ad5791_spi_exit(void) | ||
| 435 | { | ||
| 436 | spi_unregister_driver(&ad5791_driver); | ||
| 437 | } | ||
| 438 | module_exit(ad5791_spi_exit); | ||
| 439 | |||
| 440 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
| 441 | MODULE_DESCRIPTION("Analog Devices AD5760/AD5780/AD5781/AD5791 DAC"); | ||
| 442 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/dac/ad5791.h b/drivers/staging/iio/dac/ad5791.h new file mode 100644 index 00000000000..c807f26539d --- /dev/null +++ b/drivers/staging/iio/dac/ad5791.h | |||
| @@ -0,0 +1,114 @@ | |||
| 1 | /* | ||
| 2 | * AD5791 SPI DAC driver | ||
| 3 | * | ||
| 4 | * Copyright 2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef SPI_AD5791_H_ | ||
| 10 | #define SPI_AD5791_H_ | ||
| 11 | |||
| 12 | #define AD5791_RES_MASK(x) ((1 << (x)) - 1) | ||
| 13 | #define AD5791_DAC_MASK AD5791_RES_MASK(20) | ||
| 14 | #define AD5791_DAC_MSB (1 << 19) | ||
| 15 | |||
| 16 | #define AD5791_CMD_READ (1 << 23) | ||
| 17 | #define AD5791_CMD_WRITE (0 << 23) | ||
| 18 | #define AD5791_ADDR(addr) ((addr) << 20) | ||
| 19 | |||
| 20 | /* Registers */ | ||
| 21 | #define AD5791_ADDR_NOOP 0 | ||
| 22 | #define AD5791_ADDR_DAC0 1 | ||
| 23 | #define AD5791_ADDR_CTRL 2 | ||
| 24 | #define AD5791_ADDR_CLRCODE 3 | ||
| 25 | #define AD5791_ADDR_SW_CTRL 4 | ||
| 26 | |||
| 27 | /* Control Register */ | ||
| 28 | #define AD5791_CTRL_RBUF (1 << 1) | ||
| 29 | #define AD5791_CTRL_OPGND (1 << 2) | ||
| 30 | #define AD5791_CTRL_DACTRI (1 << 3) | ||
| 31 | #define AD5791_CTRL_BIN2SC (1 << 4) | ||
| 32 | #define AD5791_CTRL_SDODIS (1 << 5) | ||
| 33 | #define AD5761_CTRL_LINCOMP(x) ((x) << 6) | ||
| 34 | |||
| 35 | #define AD5791_LINCOMP_0_10 0 | ||
| 36 | #define AD5791_LINCOMP_10_12 1 | ||
| 37 | #define AD5791_LINCOMP_12_16 2 | ||
| 38 | #define AD5791_LINCOMP_16_19 3 | ||
| 39 | #define AD5791_LINCOMP_19_20 12 | ||
| 40 | |||
| 41 | #define AD5780_LINCOMP_0_10 0 | ||
| 42 | #define AD5780_LINCOMP_10_20 12 | ||
| 43 | |||
| 44 | /* Software Control Register */ | ||
| 45 | #define AD5791_SWCTRL_LDAC (1 << 0) | ||
| 46 | #define AD5791_SWCTRL_CLR (1 << 1) | ||
| 47 | #define AD5791_SWCTRL_RESET (1 << 2) | ||
| 48 | |||
| 49 | #define AD5791_DAC_PWRDN_6K 0 | ||
| 50 | #define AD5791_DAC_PWRDN_3STATE 1 | ||
| 51 | |||
| 52 | /* | ||
| 53 | * TODO: struct ad5791_platform_data needs to go into include/linux/iio | ||
| 54 | */ | ||
| 55 | |||
| 56 | /** | ||
| 57 | * struct ad5791_platform_data - platform specific information | ||
| 58 | * @vref_pos_mv: Vdd Positive Analog Supply Volatge (mV) | ||
| 59 | * @vref_neg_mv: Vdd Negative Analog Supply Volatge (mV) | ||
| 60 | * @use_rbuf_gain2: ext. amplifier connected in gain of two configuration | ||
| 61 | */ | ||
| 62 | |||
| 63 | struct ad5791_platform_data { | ||
| 64 | u16 vref_pos_mv; | ||
| 65 | u16 vref_neg_mv; | ||
| 66 | bool use_rbuf_gain2; | ||
| 67 | }; | ||
| 68 | |||
| 69 | /** | ||
| 70 | * struct ad5791_chip_info - chip specific information | ||
| 71 | * @bits: accuracy of the DAC in bits | ||
| 72 | * @left_shift: number of bits the datum must be shifted | ||
| 73 | * @get_lin_comp: function pointer to the device specific function | ||
| 74 | */ | ||
| 75 | |||
| 76 | struct ad5791_chip_info { | ||
| 77 | u8 bits; | ||
| 78 | u8 left_shift; | ||
| 79 | int (*get_lin_comp) (unsigned int span); | ||
| 80 | }; | ||
| 81 | |||
| 82 | /** | ||
| 83 | * struct ad5791_state - driver instance specific data | ||
| 84 | * @us: spi_device | ||
| 85 | * @reg_vdd: positive supply regulator | ||
| 86 | * @reg_vss: negative supply regulator | ||
| 87 | * @chip_info: chip model specific constants | ||
| 88 | * @vref_mv: actual reference voltage used | ||
| 89 | * @pwr_down_mode current power down mode | ||
| 90 | */ | ||
| 91 | |||
| 92 | struct ad5791_state { | ||
| 93 | struct spi_device *spi; | ||
| 94 | struct regulator *reg_vdd; | ||
| 95 | struct regulator *reg_vss; | ||
| 96 | const struct ad5791_chip_info *chip_info; | ||
| 97 | unsigned short vref_mv; | ||
| 98 | unsigned ctrl; | ||
| 99 | unsigned pwr_down_mode; | ||
| 100 | bool pwr_down; | ||
| 101 | }; | ||
| 102 | |||
| 103 | /** | ||
| 104 | * ad5791_supported_device_ids: | ||
| 105 | */ | ||
| 106 | |||
| 107 | enum ad5791_supported_device_ids { | ||
| 108 | ID_AD5760, | ||
| 109 | ID_AD5780, | ||
| 110 | ID_AD5781, | ||
| 111 | ID_AD5791, | ||
| 112 | }; | ||
| 113 | |||
| 114 | #endif /* SPI_AD5791_H_ */ | ||
diff --git a/drivers/staging/iio/dac/dac.h b/drivers/staging/iio/dac/dac.h new file mode 100644 index 00000000000..1d82f353241 --- /dev/null +++ b/drivers/staging/iio/dac/dac.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | /* | ||
| 2 | * dac.h - sysfs attributes associated with DACs | ||
| 3 | */ | ||
| 4 | |||
| 5 | #define IIO_DEV_ATTR_OUT_RAW(_num, _store, _addr) \ | ||
| 6 | IIO_DEVICE_ATTR(out##_num##_raw, S_IWUSR, NULL, _store, _addr) | ||
diff --git a/drivers/staging/iio/dac/max517.c b/drivers/staging/iio/dac/max517.c new file mode 100644 index 00000000000..ed5d351b238 --- /dev/null +++ b/drivers/staging/iio/dac/max517.c | |||
| @@ -0,0 +1,295 @@ | |||
| 1 | /* | ||
| 2 | * max517.c - Support for Maxim MAX517, MAX518 and MAX519 | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/jiffies.h> | ||
| 25 | #include <linux/i2c.h> | ||
| 26 | #include <linux/err.h> | ||
| 27 | |||
| 28 | #include "../iio.h" | ||
| 29 | #include "dac.h" | ||
| 30 | |||
| 31 | #include "max517.h" | ||
| 32 | |||
| 33 | #define MAX517_DRV_NAME "max517" | ||
| 34 | |||
| 35 | /* Commands */ | ||
| 36 | #define COMMAND_CHANNEL0 0x00 | ||
| 37 | #define COMMAND_CHANNEL1 0x01 /* for MAX518 and MAX519 */ | ||
| 38 | #define COMMAND_PD 0x08 /* Power Down */ | ||
| 39 | |||
| 40 | enum max517_device_ids { | ||
| 41 | ID_MAX517, | ||
| 42 | ID_MAX518, | ||
| 43 | ID_MAX519, | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct max517_data { | ||
| 47 | struct iio_dev *indio_dev; | ||
| 48 | struct i2c_client *client; | ||
| 49 | unsigned short vref_mv[2]; | ||
| 50 | }; | ||
| 51 | |||
| 52 | /* | ||
| 53 | * channel: bit 0: channel 1 | ||
| 54 | * bit 1: channel 2 | ||
| 55 | * (this way, it's possible to set both channels at once) | ||
| 56 | */ | ||
| 57 | static ssize_t max517_set_value(struct device *dev, | ||
| 58 | struct device_attribute *attr, | ||
| 59 | const char *buf, size_t count, int channel) | ||
| 60 | { | ||
| 61 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 62 | struct max517_data *data = iio_priv(dev_info); | ||
| 63 | struct i2c_client *client = data->client; | ||
| 64 | u8 outbuf[4]; /* 1x or 2x command + value */ | ||
| 65 | int outbuf_size = 0; | ||
| 66 | int res; | ||
| 67 | long val; | ||
| 68 | |||
| 69 | res = strict_strtol(buf, 10, &val); | ||
| 70 | |||
| 71 | if (res) | ||
| 72 | return res; | ||
| 73 | |||
| 74 | if (val < 0 || val > 255) | ||
| 75 | return -EINVAL; | ||
| 76 | |||
| 77 | if (channel & 1) { | ||
| 78 | outbuf[outbuf_size++] = COMMAND_CHANNEL0; | ||
| 79 | outbuf[outbuf_size++] = val; | ||
| 80 | } | ||
| 81 | if (channel & 2) { | ||
| 82 | outbuf[outbuf_size++] = COMMAND_CHANNEL1; | ||
| 83 | outbuf[outbuf_size++] = val; | ||
| 84 | } | ||
| 85 | |||
| 86 | /* | ||
| 87 | * At this point, there are always 1 or 2 two-byte commands in | ||
| 88 | * outbuf. With 2 commands, the device can set two outputs | ||
| 89 | * simultaneously, latching the values upon the end of the I2C | ||
| 90 | * transfer. | ||
| 91 | */ | ||
| 92 | |||
| 93 | res = i2c_master_send(client, outbuf, outbuf_size); | ||
| 94 | if (res < 0) | ||
| 95 | return res; | ||
| 96 | |||
| 97 | return count; | ||
| 98 | } | ||
| 99 | |||
| 100 | static ssize_t max517_set_value_1(struct device *dev, | ||
| 101 | struct device_attribute *attr, | ||
| 102 | const char *buf, size_t count) | ||
| 103 | { | ||
| 104 | return max517_set_value(dev, attr, buf, count, 1); | ||
| 105 | } | ||
| 106 | static IIO_DEV_ATTR_OUT_RAW(1, max517_set_value_1, 0); | ||
| 107 | |||
| 108 | static ssize_t max517_set_value_2(struct device *dev, | ||
| 109 | struct device_attribute *attr, | ||
| 110 | const char *buf, size_t count) | ||
| 111 | { | ||
| 112 | return max517_set_value(dev, attr, buf, count, 2); | ||
| 113 | } | ||
| 114 | static IIO_DEV_ATTR_OUT_RAW(2, max517_set_value_2, 1); | ||
| 115 | |||
| 116 | static ssize_t max517_set_value_both(struct device *dev, | ||
| 117 | struct device_attribute *attr, | ||
| 118 | const char *buf, size_t count) | ||
| 119 | { | ||
| 120 | return max517_set_value(dev, attr, buf, count, 3); | ||
| 121 | } | ||
| 122 | static IIO_DEVICE_ATTR_NAMED(out1and2_raw, out1&2_raw, S_IWUSR, NULL, | ||
| 123 | max517_set_value_both, -1); | ||
| 124 | |||
| 125 | static ssize_t max517_show_scale(struct device *dev, | ||
| 126 | struct device_attribute *attr, | ||
| 127 | char *buf, int channel) | ||
| 128 | { | ||
| 129 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 130 | struct max517_data *data = iio_priv(dev_info); | ||
| 131 | /* Corresponds to Vref / 2^(bits) */ | ||
| 132 | unsigned int scale_uv = (data->vref_mv[channel - 1] * 1000) >> 8; | ||
| 133 | |||
| 134 | return sprintf(buf, "%d.%03d\n", scale_uv / 1000, scale_uv % 1000); | ||
| 135 | } | ||
| 136 | |||
| 137 | static ssize_t max517_show_scale1(struct device *dev, | ||
| 138 | struct device_attribute *attr, | ||
| 139 | char *buf) | ||
| 140 | { | ||
| 141 | return max517_show_scale(dev, attr, buf, 1); | ||
| 142 | } | ||
| 143 | static IIO_DEVICE_ATTR(out1_scale, S_IRUGO, max517_show_scale1, NULL, 0); | ||
| 144 | |||
| 145 | static ssize_t max517_show_scale2(struct device *dev, | ||
| 146 | struct device_attribute *attr, | ||
| 147 | char *buf) | ||
| 148 | { | ||
| 149 | return max517_show_scale(dev, attr, buf, 2); | ||
| 150 | } | ||
| 151 | static IIO_DEVICE_ATTR(out2_scale, S_IRUGO, max517_show_scale2, NULL, 0); | ||
| 152 | |||
| 153 | /* On MAX517 variant, we have one output */ | ||
| 154 | static struct attribute *max517_attributes[] = { | ||
| 155 | &iio_dev_attr_out1_raw.dev_attr.attr, | ||
| 156 | &iio_dev_attr_out1_scale.dev_attr.attr, | ||
| 157 | NULL | ||
| 158 | }; | ||
| 159 | |||
| 160 | static struct attribute_group max517_attribute_group = { | ||
| 161 | .attrs = max517_attributes, | ||
| 162 | }; | ||
| 163 | |||
| 164 | /* On MAX518 and MAX519 variant, we have two outputs */ | ||
| 165 | static struct attribute *max518_attributes[] = { | ||
| 166 | &iio_dev_attr_out1_raw.dev_attr.attr, | ||
| 167 | &iio_dev_attr_out1_scale.dev_attr.attr, | ||
| 168 | &iio_dev_attr_out2_raw.dev_attr.attr, | ||
| 169 | &iio_dev_attr_out2_scale.dev_attr.attr, | ||
| 170 | &iio_dev_attr_out1and2_raw.dev_attr.attr, | ||
| 171 | NULL | ||
| 172 | }; | ||
| 173 | |||
| 174 | static struct attribute_group max518_attribute_group = { | ||
| 175 | .attrs = max518_attributes, | ||
| 176 | }; | ||
| 177 | |||
| 178 | static int max517_suspend(struct i2c_client *client, pm_message_t mesg) | ||
| 179 | { | ||
| 180 | u8 outbuf = COMMAND_PD; | ||
| 181 | |||
| 182 | return i2c_master_send(client, &outbuf, 1); | ||
| 183 | } | ||
| 184 | |||
| 185 | static int max517_resume(struct i2c_client *client) | ||
| 186 | { | ||
| 187 | u8 outbuf = 0; | ||
| 188 | |||
| 189 | return i2c_master_send(client, &outbuf, 1); | ||
| 190 | } | ||
| 191 | |||
| 192 | static const struct iio_info max517_info = { | ||
| 193 | .attrs = &max517_attribute_group, | ||
| 194 | .driver_module = THIS_MODULE, | ||
| 195 | }; | ||
| 196 | |||
| 197 | static const struct iio_info max518_info = { | ||
| 198 | .attrs = &max518_attribute_group, | ||
| 199 | .driver_module = THIS_MODULE, | ||
| 200 | }; | ||
| 201 | |||
| 202 | static int max517_probe(struct i2c_client *client, | ||
| 203 | const struct i2c_device_id *id) | ||
| 204 | { | ||
| 205 | struct max517_data *data; | ||
| 206 | struct iio_dev *indio_dev; | ||
| 207 | struct max517_platform_data *platform_data = client->dev.platform_data; | ||
| 208 | int err; | ||
| 209 | |||
| 210 | indio_dev = iio_allocate_device(sizeof(*data)); | ||
| 211 | if (indio_dev == NULL) { | ||
| 212 | err = -ENOMEM; | ||
| 213 | goto exit; | ||
| 214 | } | ||
| 215 | data = iio_priv(indio_dev); | ||
| 216 | i2c_set_clientdata(client, indio_dev); | ||
| 217 | data->client = client; | ||
| 218 | |||
| 219 | /* establish that the iio_dev is a child of the i2c device */ | ||
| 220 | indio_dev->dev.parent = &client->dev; | ||
| 221 | |||
| 222 | /* reduced attribute set for MAX517 */ | ||
| 223 | if (id->driver_data == ID_MAX517) | ||
| 224 | indio_dev->info = &max517_info; | ||
| 225 | else | ||
| 226 | indio_dev->info = &max518_info; | ||
| 227 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 228 | |||
| 229 | /* | ||
| 230 | * Reference voltage on MAX518 and default is 5V, else take vref_mv | ||
| 231 | * from platform_data | ||
| 232 | */ | ||
| 233 | if (id->driver_data == ID_MAX518 || !platform_data) { | ||
| 234 | data->vref_mv[0] = data->vref_mv[1] = 5000; /* mV */ | ||
| 235 | } else { | ||
| 236 | data->vref_mv[0] = platform_data->vref_mv[0]; | ||
| 237 | data->vref_mv[1] = platform_data->vref_mv[1]; | ||
| 238 | } | ||
| 239 | |||
| 240 | err = iio_device_register(indio_dev); | ||
| 241 | if (err) | ||
| 242 | goto exit_free_device; | ||
| 243 | |||
| 244 | dev_info(&client->dev, "DAC registered\n"); | ||
| 245 | |||
| 246 | return 0; | ||
| 247 | |||
| 248 | exit_free_device: | ||
| 249 | iio_free_device(indio_dev); | ||
| 250 | exit: | ||
| 251 | return err; | ||
| 252 | } | ||
| 253 | |||
| 254 | static int max517_remove(struct i2c_client *client) | ||
| 255 | { | ||
| 256 | iio_free_device(i2c_get_clientdata(client)); | ||
| 257 | |||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | |||
| 261 | static const struct i2c_device_id max517_id[] = { | ||
| 262 | { "max517", ID_MAX517 }, | ||
| 263 | { "max518", ID_MAX518 }, | ||
| 264 | { "max519", ID_MAX519 }, | ||
| 265 | { } | ||
| 266 | }; | ||
| 267 | MODULE_DEVICE_TABLE(i2c, max517_id); | ||
| 268 | |||
| 269 | static struct i2c_driver max517_driver = { | ||
| 270 | .driver = { | ||
| 271 | .name = MAX517_DRV_NAME, | ||
| 272 | }, | ||
| 273 | .probe = max517_probe, | ||
| 274 | .remove = max517_remove, | ||
| 275 | .suspend = max517_suspend, | ||
| 276 | .resume = max517_resume, | ||
| 277 | .id_table = max517_id, | ||
| 278 | }; | ||
| 279 | |||
| 280 | static int __init max517_init(void) | ||
| 281 | { | ||
| 282 | return i2c_add_driver(&max517_driver); | ||
| 283 | } | ||
| 284 | |||
| 285 | static void __exit max517_exit(void) | ||
| 286 | { | ||
| 287 | i2c_del_driver(&max517_driver); | ||
| 288 | } | ||
| 289 | |||
| 290 | MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); | ||
| 291 | MODULE_DESCRIPTION("MAX517/MAX518/MAX519 8-bit DAC"); | ||
| 292 | MODULE_LICENSE("GPL"); | ||
| 293 | |||
| 294 | module_init(max517_init); | ||
| 295 | module_exit(max517_exit); | ||
diff --git a/drivers/staging/iio/dac/max517.h b/drivers/staging/iio/dac/max517.h new file mode 100644 index 00000000000..8106cf24642 --- /dev/null +++ b/drivers/staging/iio/dac/max517.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* | ||
| 2 | * MAX517 DAC driver | ||
| 3 | * | ||
| 4 | * Copyright 2011 Roland Stigge <stigge@antcom.de> | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | #ifndef IIO_DAC_MAX517_H_ | ||
| 9 | #define IIO_DAC_MAX517_H_ | ||
| 10 | |||
| 11 | /* | ||
| 12 | * TODO: struct max517_platform_data needs to go into include/linux/iio | ||
| 13 | */ | ||
| 14 | |||
| 15 | struct max517_platform_data { | ||
| 16 | u16 vref_mv[2]; | ||
| 17 | }; | ||
| 18 | |||
| 19 | #endif /* IIO_DAC_MAX517_H_ */ | ||
diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/dds/Kconfig new file mode 100644 index 00000000000..e07431d8009 --- /dev/null +++ b/drivers/staging/iio/dds/Kconfig | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | # | ||
| 2 | # Direct Digital Synthesis drivers | ||
| 3 | # | ||
| 4 | comment "Direct Digital Synthesis" | ||
| 5 | |||
| 6 | config AD5930 | ||
| 7 | tristate "Analog Devices ad5930/5932 driver" | ||
| 8 | depends on SPI | ||
| 9 | help | ||
| 10 | Say yes here to build support for Analog Devices DDS chip | ||
| 11 | ad5930/ad5932, provides direct access via sysfs. | ||
| 12 | |||
| 13 | config AD9832 | ||
| 14 | tristate "Analog Devices ad9832/5 driver" | ||
| 15 | depends on SPI | ||
| 16 | help | ||
| 17 | Say yes here to build support for Analog Devices DDS chip | ||
| 18 | AD9832 and AD9835, provides direct access via sysfs. | ||
| 19 | |||
| 20 | To compile this driver as a module, choose M here: the | ||
| 21 | module will be called ad9832. | ||
| 22 | |||
| 23 | config AD9834 | ||
| 24 | tristate "Analog Devices AD9833/4/7/8 driver" | ||
| 25 | depends on SPI | ||
| 26 | help | ||
| 27 | Say yes here to build support for Analog Devices DDS chip | ||
| 28 | AD9833, AD9834, AD9837 and AD9838, provides direct access via sysfs. | ||
| 29 | |||
| 30 | To compile this driver as a module, choose M here: the | ||
| 31 | module will be called ad9834. | ||
| 32 | |||
| 33 | config AD9850 | ||
| 34 | tristate "Analog Devices ad9850/1 driver" | ||
| 35 | depends on SPI | ||
| 36 | help | ||
| 37 | Say yes here to build support for Analog Devices DDS chip | ||
| 38 | ad9850/1, provides direct access via sysfs. | ||
| 39 | |||
| 40 | config AD9852 | ||
| 41 | tristate "Analog Devices ad9852/4 driver" | ||
| 42 | depends on SPI | ||
| 43 | help | ||
| 44 | Say yes here to build support for Analog Devices DDS chip | ||
| 45 | ad9852/4, provides direct access via sysfs. | ||
| 46 | |||
| 47 | config AD9910 | ||
| 48 | tristate "Analog Devices ad9910 driver" | ||
| 49 | depends on SPI | ||
| 50 | help | ||
| 51 | Say yes here to build support for Analog Devices DDS chip | ||
| 52 | ad9910, provides direct access via sysfs. | ||
| 53 | |||
| 54 | config AD9951 | ||
| 55 | tristate "Analog Devices ad9951 driver" | ||
| 56 | depends on SPI | ||
| 57 | help | ||
| 58 | Say yes here to build support for Analog Devices DDS chip | ||
| 59 | ad9951, provides direct access via sysfs. | ||
diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/dds/Makefile new file mode 100644 index 00000000000..147746176b9 --- /dev/null +++ b/drivers/staging/iio/dds/Makefile | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | # | ||
| 2 | # Makefile for Direct Digital Synthesis drivers | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_AD5930) += ad5930.o | ||
| 6 | obj-$(CONFIG_AD9832) += ad9832.o | ||
| 7 | obj-$(CONFIG_AD9834) += ad9834.o | ||
| 8 | obj-$(CONFIG_AD9850) += ad9850.o | ||
| 9 | obj-$(CONFIG_AD9852) += ad9852.o | ||
| 10 | obj-$(CONFIG_AD9910) += ad9910.o | ||
| 11 | obj-$(CONFIG_AD9951) += ad9951.o | ||
diff --git a/drivers/staging/iio/dds/ad5930.c b/drivers/staging/iio/dds/ad5930.c new file mode 100644 index 00000000000..0b2aa4cafdd --- /dev/null +++ b/drivers/staging/iio/dds/ad5930.c | |||
| @@ -0,0 +1,159 @@ | |||
| 1 | /* | ||
| 2 | * Driver for ADI Direct Digital Synthesis ad5930 | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010-2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | #include <linux/types.h> | ||
| 12 | #include <linux/mutex.h> | ||
| 13 | #include <linux/device.h> | ||
| 14 | #include <linux/spi/spi.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/sysfs.h> | ||
| 17 | |||
| 18 | #include "../iio.h" | ||
| 19 | #include "../sysfs.h" | ||
| 20 | |||
| 21 | #define DRV_NAME "ad5930" | ||
| 22 | |||
| 23 | #define value_mask (u16)0xf000 | ||
| 24 | #define addr_shift 12 | ||
| 25 | |||
| 26 | /* Register format: 4 bits addr + 12 bits value */ | ||
| 27 | struct ad5903_config { | ||
| 28 | u16 control; | ||
| 29 | u16 incnum; | ||
| 30 | u16 frqdelt[2]; | ||
| 31 | u16 incitvl; | ||
| 32 | u16 buritvl; | ||
| 33 | u16 strtfrq[2]; | ||
| 34 | }; | ||
| 35 | |||
| 36 | struct ad5930_state { | ||
| 37 | struct mutex lock; | ||
| 38 | struct spi_device *sdev; | ||
| 39 | }; | ||
| 40 | |||
| 41 | static ssize_t ad5930_set_parameter(struct device *dev, | ||
| 42 | struct device_attribute *attr, | ||
| 43 | const char *buf, | ||
| 44 | size_t len) | ||
| 45 | { | ||
| 46 | struct spi_message msg; | ||
| 47 | struct spi_transfer xfer; | ||
| 48 | int ret; | ||
| 49 | struct ad5903_config *config = (struct ad5903_config *)buf; | ||
| 50 | struct iio_dev *idev = dev_get_drvdata(dev); | ||
| 51 | struct ad5930_state *st = iio_priv(idev); | ||
| 52 | |||
| 53 | config->control = (config->control & ~value_mask); | ||
| 54 | config->incnum = (config->control & ~value_mask) | (1 << addr_shift); | ||
| 55 | config->frqdelt[0] = (config->control & ~value_mask) | (2 << addr_shift); | ||
| 56 | config->frqdelt[1] = (config->control & ~value_mask) | 3 << addr_shift; | ||
| 57 | config->incitvl = (config->control & ~value_mask) | 4 << addr_shift; | ||
| 58 | config->buritvl = (config->control & ~value_mask) | 8 << addr_shift; | ||
| 59 | config->strtfrq[0] = (config->control & ~value_mask) | 0xc << addr_shift; | ||
| 60 | config->strtfrq[1] = (config->control & ~value_mask) | 0xd << addr_shift; | ||
| 61 | |||
| 62 | xfer.len = len; | ||
| 63 | xfer.tx_buf = config; | ||
| 64 | mutex_lock(&st->lock); | ||
| 65 | |||
| 66 | spi_message_init(&msg); | ||
| 67 | spi_message_add_tail(&xfer, &msg); | ||
| 68 | ret = spi_sync(st->sdev, &msg); | ||
| 69 | if (ret) | ||
| 70 | goto error_ret; | ||
| 71 | error_ret: | ||
| 72 | mutex_unlock(&st->lock); | ||
| 73 | |||
| 74 | return ret ? ret : len; | ||
| 75 | } | ||
| 76 | |||
| 77 | static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad5930_set_parameter, 0); | ||
| 78 | |||
| 79 | static struct attribute *ad5930_attributes[] = { | ||
| 80 | &iio_dev_attr_dds.dev_attr.attr, | ||
| 81 | NULL, | ||
| 82 | }; | ||
| 83 | |||
| 84 | static const struct attribute_group ad5930_attribute_group = { | ||
| 85 | .attrs = ad5930_attributes, | ||
| 86 | }; | ||
| 87 | |||
| 88 | static const struct iio_info ad5930_info = { | ||
| 89 | .attrs = &ad5930_attribute_group, | ||
| 90 | .driver_module = THIS_MODULE, | ||
| 91 | }; | ||
| 92 | |||
| 93 | static int __devinit ad5930_probe(struct spi_device *spi) | ||
| 94 | { | ||
| 95 | struct ad5930_state *st; | ||
| 96 | struct iio_dev *idev; | ||
| 97 | int ret = 0; | ||
| 98 | |||
| 99 | idev = iio_allocate_device(sizeof(*st)); | ||
| 100 | if (idev == NULL) { | ||
| 101 | ret = -ENOMEM; | ||
| 102 | goto error_ret; | ||
| 103 | } | ||
| 104 | spi_set_drvdata(spi, idev); | ||
| 105 | st = iio_priv(idev); | ||
| 106 | |||
| 107 | mutex_init(&st->lock); | ||
| 108 | st->sdev = spi; | ||
| 109 | idev->dev.parent = &spi->dev; | ||
| 110 | idev->info = &ad5930_info; | ||
| 111 | idev->modes = INDIO_DIRECT_MODE; | ||
| 112 | |||
| 113 | ret = iio_device_register(idev); | ||
| 114 | if (ret) | ||
| 115 | goto error_free_dev; | ||
| 116 | spi->max_speed_hz = 2000000; | ||
| 117 | spi->mode = SPI_MODE_3; | ||
| 118 | spi->bits_per_word = 16; | ||
| 119 | spi_setup(spi); | ||
| 120 | |||
| 121 | return 0; | ||
| 122 | |||
| 123 | error_free_dev: | ||
| 124 | iio_free_device(idev); | ||
| 125 | error_ret: | ||
| 126 | return ret; | ||
| 127 | } | ||
| 128 | |||
| 129 | static int __devexit ad5930_remove(struct spi_device *spi) | ||
| 130 | { | ||
| 131 | iio_device_unregister(spi_get_drvdata(spi)); | ||
| 132 | |||
| 133 | return 0; | ||
| 134 | } | ||
| 135 | |||
| 136 | static struct spi_driver ad5930_driver = { | ||
| 137 | .driver = { | ||
| 138 | .name = DRV_NAME, | ||
| 139 | .owner = THIS_MODULE, | ||
| 140 | }, | ||
| 141 | .probe = ad5930_probe, | ||
| 142 | .remove = __devexit_p(ad5930_remove), | ||
| 143 | }; | ||
| 144 | |||
| 145 | static __init int ad5930_spi_init(void) | ||
| 146 | { | ||
| 147 | return spi_register_driver(&ad5930_driver); | ||
| 148 | } | ||
| 149 | module_init(ad5930_spi_init); | ||
| 150 | |||
| 151 | static __exit void ad5930_spi_exit(void) | ||
| 152 | { | ||
| 153 | spi_unregister_driver(&ad5930_driver); | ||
| 154 | } | ||
| 155 | module_exit(ad5930_spi_exit); | ||
| 156 | |||
| 157 | MODULE_AUTHOR("Cliff Cai"); | ||
| 158 | MODULE_DESCRIPTION("Analog Devices ad5930 driver"); | ||
| 159 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/dds/ad9832.c b/drivers/staging/iio/dds/ad9832.c new file mode 100644 index 00000000000..e3e61a469bb --- /dev/null +++ b/drivers/staging/iio/dds/ad9832.c | |||
| @@ -0,0 +1,372 @@ | |||
| 1 | /* | ||
| 2 | * AD9832 SPI DDS driver | ||
| 3 | * | ||
| 4 | * Copyright 2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/device.h> | ||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/sysfs.h> | ||
| 13 | #include <linux/spi/spi.h> | ||
| 14 | #include <linux/regulator/consumer.h> | ||
| 15 | #include <linux/err.h> | ||
| 16 | #include <asm/div64.h> | ||
| 17 | |||
| 18 | #include "../iio.h" | ||
| 19 | #include "../sysfs.h" | ||
| 20 | #include "dds.h" | ||
| 21 | |||
| 22 | #include "ad9832.h" | ||
| 23 | |||
| 24 | static unsigned long ad9832_calc_freqreg(unsigned long mclk, unsigned long fout) | ||
| 25 | { | ||
| 26 | unsigned long long freqreg = (u64) fout * | ||
| 27 | (u64) ((u64) 1L << AD9832_FREQ_BITS); | ||
| 28 | do_div(freqreg, mclk); | ||
| 29 | return freqreg; | ||
| 30 | } | ||
| 31 | |||
| 32 | static int ad9832_write_frequency(struct ad9832_state *st, | ||
| 33 | unsigned addr, unsigned long fout) | ||
| 34 | { | ||
| 35 | unsigned long regval; | ||
| 36 | |||
| 37 | if (fout > (st->mclk / 2)) | ||
| 38 | return -EINVAL; | ||
| 39 | |||
| 40 | regval = ad9832_calc_freqreg(st->mclk, fout); | ||
| 41 | |||
| 42 | st->freq_data[0] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) | | ||
| 43 | (addr << ADD_SHIFT) | | ||
| 44 | ((regval >> 24) & 0xFF)); | ||
| 45 | st->freq_data[1] = cpu_to_be16((AD9832_CMD_FRE16BITSW << CMD_SHIFT) | | ||
| 46 | ((addr - 1) << ADD_SHIFT) | | ||
| 47 | ((regval >> 16) & 0xFF)); | ||
| 48 | st->freq_data[2] = cpu_to_be16((AD9832_CMD_FRE8BITSW << CMD_SHIFT) | | ||
| 49 | ((addr - 2) << ADD_SHIFT) | | ||
| 50 | ((regval >> 8) & 0xFF)); | ||
| 51 | st->freq_data[3] = cpu_to_be16((AD9832_CMD_FRE16BITSW << CMD_SHIFT) | | ||
| 52 | ((addr - 3) << ADD_SHIFT) | | ||
| 53 | ((regval >> 0) & 0xFF)); | ||
| 54 | |||
| 55 | return spi_sync(st->spi, &st->freq_msg);; | ||
| 56 | } | ||
| 57 | |||
| 58 | static int ad9832_write_phase(struct ad9832_state *st, | ||
| 59 | unsigned long addr, unsigned long phase) | ||
| 60 | { | ||
| 61 | if (phase > (1 << AD9832_PHASE_BITS)) | ||
| 62 | return -EINVAL; | ||
| 63 | |||
| 64 | st->phase_data[0] = cpu_to_be16((AD9832_CMD_PHA8BITSW << CMD_SHIFT) | | ||
| 65 | (addr << ADD_SHIFT) | | ||
| 66 | ((phase >> 8) & 0xFF)); | ||
| 67 | st->phase_data[1] = cpu_to_be16((AD9832_CMD_PHA16BITSW << CMD_SHIFT) | | ||
| 68 | ((addr - 1) << ADD_SHIFT) | | ||
| 69 | (phase & 0xFF)); | ||
| 70 | |||
| 71 | return spi_sync(st->spi, &st->phase_msg); | ||
| 72 | } | ||
| 73 | |||
| 74 | static ssize_t ad9832_write(struct device *dev, | ||
| 75 | struct device_attribute *attr, | ||
| 76 | const char *buf, | ||
| 77 | size_t len) | ||
| 78 | { | ||
| 79 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 80 | struct ad9832_state *st = iio_priv(dev_info); | ||
| 81 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 82 | int ret; | ||
| 83 | long val; | ||
| 84 | |||
| 85 | ret = strict_strtoul(buf, 10, &val); | ||
| 86 | if (ret) | ||
| 87 | goto error_ret; | ||
| 88 | |||
| 89 | mutex_lock(&dev_info->mlock); | ||
| 90 | switch (this_attr->address) { | ||
| 91 | case AD9832_FREQ0HM: | ||
| 92 | case AD9832_FREQ1HM: | ||
| 93 | ret = ad9832_write_frequency(st, this_attr->address, val); | ||
| 94 | break; | ||
| 95 | case AD9832_PHASE0H: | ||
| 96 | case AD9832_PHASE1H: | ||
| 97 | case AD9832_PHASE2H: | ||
| 98 | case AD9832_PHASE3H: | ||
| 99 | ret = ad9832_write_phase(st, this_attr->address, val); | ||
| 100 | break; | ||
| 101 | case AD9832_PINCTRL_EN: | ||
| 102 | if (val) | ||
| 103 | st->ctrl_ss &= ~AD9832_SELSRC; | ||
| 104 | else | ||
| 105 | st->ctrl_ss |= AD9832_SELSRC; | ||
| 106 | st->data = cpu_to_be16((AD9832_CMD_SYNCSELSRC << CMD_SHIFT) | | ||
| 107 | st->ctrl_ss); | ||
| 108 | ret = spi_sync(st->spi, &st->msg); | ||
| 109 | break; | ||
| 110 | case AD9832_FREQ_SYM: | ||
| 111 | if (val == 1) | ||
| 112 | st->ctrl_fp |= AD9832_FREQ; | ||
| 113 | else if (val == 0) | ||
| 114 | st->ctrl_fp &= ~AD9832_FREQ; | ||
| 115 | else { | ||
| 116 | ret = -EINVAL; | ||
| 117 | break; | ||
| 118 | } | ||
| 119 | st->data = cpu_to_be16((AD9832_CMD_FPSELECT << CMD_SHIFT) | | ||
| 120 | st->ctrl_fp); | ||
| 121 | ret = spi_sync(st->spi, &st->msg); | ||
| 122 | break; | ||
| 123 | case AD9832_PHASE_SYM: | ||
| 124 | if (val < 0 || val > 3) { | ||
| 125 | ret = -EINVAL; | ||
| 126 | break; | ||
| 127 | } | ||
| 128 | |||
| 129 | st->ctrl_fp &= ~AD9832_PHASE(3); | ||
| 130 | st->ctrl_fp |= AD9832_PHASE(val); | ||
| 131 | |||
| 132 | st->data = cpu_to_be16((AD9832_CMD_FPSELECT << CMD_SHIFT) | | ||
| 133 | st->ctrl_fp); | ||
| 134 | ret = spi_sync(st->spi, &st->msg); | ||
| 135 | break; | ||
| 136 | case AD9832_OUTPUT_EN: | ||
| 137 | if (val) | ||
| 138 | st->ctrl_src &= ~(AD9832_RESET | AD9832_SLEEP | | ||
| 139 | AD9832_CLR); | ||
| 140 | else | ||
| 141 | st->ctrl_src |= AD9832_RESET; | ||
| 142 | |||
| 143 | st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) | | ||
| 144 | st->ctrl_src); | ||
| 145 | ret = spi_sync(st->spi, &st->msg); | ||
| 146 | break; | ||
| 147 | default: | ||
| 148 | ret = -ENODEV; | ||
| 149 | } | ||
| 150 | mutex_unlock(&dev_info->mlock); | ||
| 151 | |||
| 152 | error_ret: | ||
| 153 | return ret ? ret : len; | ||
| 154 | } | ||
| 155 | |||
| 156 | /** | ||
| 157 | * see dds.h for further information | ||
| 158 | */ | ||
| 159 | |||
| 160 | static IIO_DEV_ATTR_FREQ(0, 0, S_IWUSR, NULL, ad9832_write, AD9832_FREQ0HM); | ||
| 161 | static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9832_write, AD9832_FREQ1HM); | ||
| 162 | static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9832_write, AD9832_FREQ_SYM); | ||
| 163 | static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */ | ||
| 164 | |||
| 165 | static IIO_DEV_ATTR_PHASE(0, 0, S_IWUSR, NULL, ad9832_write, AD9832_PHASE0H); | ||
| 166 | static IIO_DEV_ATTR_PHASE(0, 1, S_IWUSR, NULL, ad9832_write, AD9832_PHASE1H); | ||
| 167 | static IIO_DEV_ATTR_PHASE(0, 2, S_IWUSR, NULL, ad9832_write, AD9832_PHASE2H); | ||
| 168 | static IIO_DEV_ATTR_PHASE(0, 3, S_IWUSR, NULL, ad9832_write, AD9832_PHASE3H); | ||
| 169 | static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL, | ||
| 170 | ad9832_write, AD9832_PHASE_SYM); | ||
| 171 | static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/ | ||
| 172 | |||
| 173 | static IIO_DEV_ATTR_PINCONTROL_EN(0, S_IWUSR, NULL, | ||
| 174 | ad9832_write, AD9832_PINCTRL_EN); | ||
| 175 | static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL, | ||
| 176 | ad9832_write, AD9832_OUTPUT_EN); | ||
| 177 | |||
| 178 | static struct attribute *ad9832_attributes[] = { | ||
| 179 | &iio_dev_attr_dds0_freq0.dev_attr.attr, | ||
| 180 | &iio_dev_attr_dds0_freq1.dev_attr.attr, | ||
| 181 | &iio_const_attr_dds0_freq_scale.dev_attr.attr, | ||
| 182 | &iio_dev_attr_dds0_phase0.dev_attr.attr, | ||
| 183 | &iio_dev_attr_dds0_phase1.dev_attr.attr, | ||
| 184 | &iio_dev_attr_dds0_phase2.dev_attr.attr, | ||
| 185 | &iio_dev_attr_dds0_phase3.dev_attr.attr, | ||
| 186 | &iio_const_attr_dds0_phase_scale.dev_attr.attr, | ||
| 187 | &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr, | ||
| 188 | &iio_dev_attr_dds0_freqsymbol.dev_attr.attr, | ||
| 189 | &iio_dev_attr_dds0_phasesymbol.dev_attr.attr, | ||
| 190 | &iio_dev_attr_dds0_out_enable.dev_attr.attr, | ||
| 191 | NULL, | ||
| 192 | }; | ||
| 193 | |||
| 194 | static const struct attribute_group ad9832_attribute_group = { | ||
| 195 | .attrs = ad9832_attributes, | ||
| 196 | }; | ||
| 197 | |||
| 198 | static const struct iio_info ad9832_info = { | ||
| 199 | .attrs = &ad9832_attribute_group, | ||
| 200 | .driver_module = THIS_MODULE, | ||
| 201 | }; | ||
| 202 | |||
| 203 | static int __devinit ad9832_probe(struct spi_device *spi) | ||
| 204 | { | ||
| 205 | struct ad9832_platform_data *pdata = spi->dev.platform_data; | ||
| 206 | struct iio_dev *indio_dev; | ||
| 207 | struct ad9832_state *st; | ||
| 208 | struct regulator *reg; | ||
| 209 | int ret; | ||
| 210 | |||
| 211 | if (!pdata) { | ||
| 212 | dev_dbg(&spi->dev, "no platform data?\n"); | ||
| 213 | return -ENODEV; | ||
| 214 | } | ||
| 215 | |||
| 216 | reg = regulator_get(&spi->dev, "vcc"); | ||
| 217 | if (!IS_ERR(reg)) { | ||
| 218 | ret = regulator_enable(reg); | ||
| 219 | if (ret) | ||
| 220 | goto error_put_reg; | ||
| 221 | } | ||
| 222 | |||
| 223 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
| 224 | if (indio_dev == NULL) { | ||
| 225 | ret = -ENOMEM; | ||
| 226 | goto error_disable_reg; | ||
| 227 | } | ||
| 228 | spi_set_drvdata(spi, indio_dev); | ||
| 229 | st = iio_priv(indio_dev); | ||
| 230 | st->reg = reg; | ||
| 231 | st->mclk = pdata->mclk; | ||
| 232 | st->spi = spi; | ||
| 233 | |||
| 234 | indio_dev->dev.parent = &spi->dev; | ||
| 235 | indio_dev->name = spi_get_device_id(spi)->name; | ||
| 236 | indio_dev->info = &ad9832_info; | ||
| 237 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 238 | |||
| 239 | /* Setup default messages */ | ||
| 240 | |||
| 241 | st->xfer.tx_buf = &st->data; | ||
| 242 | st->xfer.len = 2; | ||
| 243 | |||
| 244 | spi_message_init(&st->msg); | ||
| 245 | spi_message_add_tail(&st->xfer, &st->msg); | ||
| 246 | |||
| 247 | st->freq_xfer[0].tx_buf = &st->freq_data[0]; | ||
| 248 | st->freq_xfer[0].len = 2; | ||
| 249 | st->freq_xfer[0].cs_change = 1; | ||
| 250 | st->freq_xfer[1].tx_buf = &st->freq_data[1]; | ||
| 251 | st->freq_xfer[1].len = 2; | ||
| 252 | st->freq_xfer[1].cs_change = 1; | ||
| 253 | st->freq_xfer[2].tx_buf = &st->freq_data[2]; | ||
| 254 | st->freq_xfer[2].len = 2; | ||
| 255 | st->freq_xfer[2].cs_change = 1; | ||
| 256 | st->freq_xfer[3].tx_buf = &st->freq_data[3]; | ||
| 257 | st->freq_xfer[3].len = 2; | ||
| 258 | |||
| 259 | spi_message_init(&st->freq_msg); | ||
| 260 | spi_message_add_tail(&st->freq_xfer[0], &st->freq_msg); | ||
| 261 | spi_message_add_tail(&st->freq_xfer[1], &st->freq_msg); | ||
| 262 | spi_message_add_tail(&st->freq_xfer[2], &st->freq_msg); | ||
| 263 | spi_message_add_tail(&st->freq_xfer[3], &st->freq_msg); | ||
| 264 | |||
| 265 | st->phase_xfer[0].tx_buf = &st->phase_data[0]; | ||
| 266 | st->phase_xfer[0].len = 2; | ||
| 267 | st->phase_xfer[0].cs_change = 1; | ||
| 268 | st->phase_xfer[1].tx_buf = &st->phase_data[1]; | ||
| 269 | st->phase_xfer[1].len = 2; | ||
| 270 | |||
| 271 | spi_message_init(&st->phase_msg); | ||
| 272 | spi_message_add_tail(&st->phase_xfer[0], &st->phase_msg); | ||
| 273 | spi_message_add_tail(&st->phase_xfer[1], &st->phase_msg); | ||
| 274 | |||
| 275 | st->ctrl_src = AD9832_SLEEP | AD9832_RESET | AD9832_CLR; | ||
| 276 | st->data = cpu_to_be16((AD9832_CMD_SLEEPRESCLR << CMD_SHIFT) | | ||
| 277 | st->ctrl_src); | ||
| 278 | ret = spi_sync(st->spi, &st->msg); | ||
| 279 | if (ret) { | ||
| 280 | dev_err(&spi->dev, "device init failed\n"); | ||
| 281 | goto error_free_device; | ||
| 282 | } | ||
| 283 | |||
| 284 | ret = ad9832_write_frequency(st, AD9832_FREQ0HM, pdata->freq0); | ||
| 285 | if (ret) | ||
| 286 | goto error_free_device; | ||
| 287 | |||
| 288 | ret = ad9832_write_frequency(st, AD9832_FREQ1HM, pdata->freq1); | ||
| 289 | if (ret) | ||
| 290 | goto error_free_device; | ||
| 291 | |||
| 292 | ret = ad9832_write_phase(st, AD9832_PHASE0H, pdata->phase0); | ||
| 293 | if (ret) | ||
| 294 | goto error_free_device; | ||
| 295 | |||
| 296 | ret = ad9832_write_phase(st, AD9832_PHASE1H, pdata->phase1); | ||
| 297 | if (ret) | ||
| 298 | goto error_free_device; | ||
| 299 | |||
| 300 | ret = ad9832_write_phase(st, AD9832_PHASE2H, pdata->phase2); | ||
| 301 | if (ret) | ||
| 302 | goto error_free_device; | ||
| 303 | |||
| 304 | ret = ad9832_write_phase(st, AD9832_PHASE3H, pdata->phase3); | ||
| 305 | if (ret) | ||
| 306 | goto error_free_device; | ||
| 307 | |||
| 308 | ret = iio_device_register(indio_dev); | ||
| 309 | if (ret) | ||
| 310 | goto error_free_device; | ||
| 311 | |||
| 312 | return 0; | ||
| 313 | |||
| 314 | error_free_device: | ||
| 315 | iio_free_device(indio_dev); | ||
| 316 | error_disable_reg: | ||
| 317 | if (!IS_ERR(reg)) | ||
| 318 | regulator_disable(reg); | ||
| 319 | error_put_reg: | ||
| 320 | if (!IS_ERR(reg)) | ||
| 321 | regulator_put(reg); | ||
| 322 | |||
| 323 | return ret; | ||
| 324 | } | ||
| 325 | |||
| 326 | static int __devexit ad9832_remove(struct spi_device *spi) | ||
| 327 | { | ||
| 328 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 329 | struct ad9832_state *st = iio_priv(indio_dev); | ||
| 330 | struct regulator *reg = st->reg; | ||
| 331 | |||
| 332 | iio_device_unregister(indio_dev); | ||
| 333 | if (!IS_ERR(reg)) { | ||
| 334 | regulator_disable(reg); | ||
| 335 | regulator_put(reg); | ||
| 336 | } | ||
| 337 | return 0; | ||
| 338 | } | ||
| 339 | |||
| 340 | static const struct spi_device_id ad9832_id[] = { | ||
| 341 | {"ad9832", 0}, | ||
| 342 | {"ad9835", 0}, | ||
| 343 | {} | ||
| 344 | }; | ||
| 345 | |||
| 346 | static struct spi_driver ad9832_driver = { | ||
| 347 | .driver = { | ||
| 348 | .name = "ad9832", | ||
| 349 | .bus = &spi_bus_type, | ||
| 350 | .owner = THIS_MODULE, | ||
| 351 | }, | ||
| 352 | .probe = ad9832_probe, | ||
| 353 | .remove = __devexit_p(ad9832_remove), | ||
| 354 | .id_table = ad9832_id, | ||
| 355 | }; | ||
| 356 | |||
| 357 | static int __init ad9832_init(void) | ||
| 358 | { | ||
| 359 | return spi_register_driver(&ad9832_driver); | ||
| 360 | } | ||
| 361 | module_init(ad9832_init); | ||
| 362 | |||
| 363 | static void __exit ad9832_exit(void) | ||
| 364 | { | ||
| 365 | spi_unregister_driver(&ad9832_driver); | ||
| 366 | } | ||
| 367 | module_exit(ad9832_exit); | ||
| 368 | |||
| 369 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
| 370 | MODULE_DESCRIPTION("Analog Devices AD9832/AD9835 DDS"); | ||
| 371 | MODULE_LICENSE("GPL v2"); | ||
| 372 | MODULE_ALIAS("spi:ad9832"); | ||
diff --git a/drivers/staging/iio/dds/ad9832.h b/drivers/staging/iio/dds/ad9832.h new file mode 100644 index 00000000000..c5b701f8aab --- /dev/null +++ b/drivers/staging/iio/dds/ad9832.h | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | /* | ||
| 2 | * AD9832 SPI DDS driver | ||
| 3 | * | ||
| 4 | * Copyright 2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | #ifndef IIO_DDS_AD9832_H_ | ||
| 9 | #define IIO_DDS_AD9832_H_ | ||
| 10 | |||
| 11 | /* Registers */ | ||
| 12 | |||
| 13 | #define AD9832_FREQ0LL 0x0 | ||
| 14 | #define AD9832_FREQ0HL 0x1 | ||
| 15 | #define AD9832_FREQ0LM 0x2 | ||
| 16 | #define AD9832_FREQ0HM 0x3 | ||
| 17 | #define AD9832_FREQ1LL 0x4 | ||
| 18 | #define AD9832_FREQ1HL 0x5 | ||
| 19 | #define AD9832_FREQ1LM 0x6 | ||
| 20 | #define AD9832_FREQ1HM 0x7 | ||
| 21 | #define AD9832_PHASE0L 0x8 | ||
| 22 | #define AD9832_PHASE0H 0x9 | ||
| 23 | #define AD9832_PHASE1L 0xA | ||
| 24 | #define AD9832_PHASE1H 0xB | ||
| 25 | #define AD9832_PHASE2L 0xC | ||
| 26 | #define AD9832_PHASE2H 0xD | ||
| 27 | #define AD9832_PHASE3L 0xE | ||
| 28 | #define AD9832_PHASE3H 0xF | ||
| 29 | |||
| 30 | #define AD9832_PHASE_SYM 0x10 | ||
| 31 | #define AD9832_FREQ_SYM 0x11 | ||
| 32 | #define AD9832_PINCTRL_EN 0x12 | ||
| 33 | #define AD9832_OUTPUT_EN 0x13 | ||
| 34 | |||
| 35 | /* Command Control Bits */ | ||
| 36 | |||
| 37 | #define AD9832_CMD_PHA8BITSW 0x1 | ||
| 38 | #define AD9832_CMD_PHA16BITSW 0x0 | ||
| 39 | #define AD9832_CMD_FRE8BITSW 0x3 | ||
| 40 | #define AD9832_CMD_FRE16BITSW 0x2 | ||
| 41 | #define AD9832_CMD_FPSELECT 0x6 | ||
| 42 | #define AD9832_CMD_SYNCSELSRC 0x8 | ||
| 43 | #define AD9832_CMD_SLEEPRESCLR 0xC | ||
| 44 | |||
| 45 | #define AD9832_FREQ (1 << 11) | ||
| 46 | #define AD9832_PHASE(x) (((x) & 3) << 9) | ||
| 47 | #define AD9832_SYNC (1 << 13) | ||
| 48 | #define AD9832_SELSRC (1 << 12) | ||
| 49 | #define AD9832_SLEEP (1 << 13) | ||
| 50 | #define AD9832_RESET (1 << 12) | ||
| 51 | #define AD9832_CLR (1 << 11) | ||
| 52 | #define CMD_SHIFT 12 | ||
| 53 | #define ADD_SHIFT 8 | ||
| 54 | #define AD9832_FREQ_BITS 32 | ||
| 55 | #define AD9832_PHASE_BITS 12 | ||
| 56 | #define RES_MASK(bits) ((1 << (bits)) - 1) | ||
| 57 | |||
| 58 | /** | ||
| 59 | * struct ad9832_state - driver instance specific data | ||
| 60 | * @spi: spi_device | ||
| 61 | * @reg: supply regulator | ||
| 62 | * @mclk: external master clock | ||
| 63 | * @ctrl_fp: cached frequency/phase control word | ||
| 64 | * @ctrl_ss: cached sync/selsrc control word | ||
| 65 | * @ctrl_src: cached sleep/reset/clr word | ||
| 66 | * @xfer: default spi transfer | ||
| 67 | * @msg: default spi message | ||
| 68 | * @freq_xfer: tuning word spi transfer | ||
| 69 | * @freq_msg: tuning word spi message | ||
| 70 | * @phase_xfer: tuning word spi transfer | ||
| 71 | * @phase_msg: tuning word spi message | ||
| 72 | * @data: spi transmit buffer | ||
| 73 | * @phase_data: tuning word spi transmit buffer | ||
| 74 | * @freq_data: tuning word spi transmit buffer | ||
| 75 | */ | ||
| 76 | |||
| 77 | struct ad9832_state { | ||
| 78 | struct spi_device *spi; | ||
| 79 | struct regulator *reg; | ||
| 80 | unsigned long mclk; | ||
| 81 | unsigned short ctrl_fp; | ||
| 82 | unsigned short ctrl_ss; | ||
| 83 | unsigned short ctrl_src; | ||
| 84 | struct spi_transfer xfer; | ||
| 85 | struct spi_message msg; | ||
| 86 | struct spi_transfer freq_xfer[4]; | ||
| 87 | struct spi_message freq_msg; | ||
| 88 | struct spi_transfer phase_xfer[2]; | ||
| 89 | struct spi_message phase_msg; | ||
| 90 | /* | ||
| 91 | * DMA (thus cache coherency maintenance) requires the | ||
| 92 | * transfer buffers to live in their own cache lines. | ||
| 93 | */ | ||
| 94 | union { | ||
| 95 | unsigned short freq_data[4]____cacheline_aligned; | ||
| 96 | unsigned short phase_data[2]; | ||
| 97 | unsigned short data; | ||
| 98 | }; | ||
| 99 | }; | ||
| 100 | |||
| 101 | /* | ||
| 102 | * TODO: struct ad9832_platform_data needs to go into include/linux/iio | ||
| 103 | */ | ||
| 104 | |||
| 105 | /** | ||
| 106 | * struct ad9832_platform_data - platform specific information | ||
| 107 | * @mclk: master clock in Hz | ||
| 108 | * @freq0: power up freq0 tuning word in Hz | ||
| 109 | * @freq1: power up freq1 tuning word in Hz | ||
| 110 | * @phase0: power up phase0 value [0..4095] correlates with 0..2PI | ||
| 111 | * @phase1: power up phase1 value [0..4095] correlates with 0..2PI | ||
| 112 | * @phase2: power up phase2 value [0..4095] correlates with 0..2PI | ||
| 113 | * @phase3: power up phase3 value [0..4095] correlates with 0..2PI | ||
| 114 | */ | ||
| 115 | |||
| 116 | struct ad9832_platform_data { | ||
| 117 | unsigned long mclk; | ||
| 118 | unsigned long freq0; | ||
| 119 | unsigned long freq1; | ||
| 120 | unsigned short phase0; | ||
| 121 | unsigned short phase1; | ||
| 122 | unsigned short phase2; | ||
| 123 | unsigned short phase3; | ||
| 124 | }; | ||
| 125 | |||
| 126 | #endif /* IIO_DDS_AD9832_H_ */ | ||
diff --git a/drivers/staging/iio/dds/ad9834.c b/drivers/staging/iio/dds/ad9834.c new file mode 100644 index 00000000000..e6454d58fe4 --- /dev/null +++ b/drivers/staging/iio/dds/ad9834.c | |||
| @@ -0,0 +1,464 @@ | |||
| 1 | /* | ||
| 2 | * AD9833/AD9834/AD9837/AD9838 SPI DDS driver | ||
| 3 | * | ||
| 4 | * Copyright 2010-2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/workqueue.h> | ||
| 11 | #include <linux/device.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/sysfs.h> | ||
| 15 | #include <linux/list.h> | ||
| 16 | #include <linux/spi/spi.h> | ||
| 17 | #include <linux/regulator/consumer.h> | ||
| 18 | #include <linux/err.h> | ||
| 19 | #include <asm/div64.h> | ||
| 20 | |||
| 21 | #include "../iio.h" | ||
| 22 | #include "../sysfs.h" | ||
| 23 | #include "dds.h" | ||
| 24 | |||
| 25 | #include "ad9834.h" | ||
| 26 | |||
| 27 | static unsigned int ad9834_calc_freqreg(unsigned long mclk, unsigned long fout) | ||
| 28 | { | ||
| 29 | unsigned long long freqreg = (u64) fout * (u64) (1 << AD9834_FREQ_BITS); | ||
| 30 | do_div(freqreg, mclk); | ||
| 31 | return freqreg; | ||
| 32 | } | ||
| 33 | |||
| 34 | static int ad9834_write_frequency(struct ad9834_state *st, | ||
| 35 | unsigned long addr, unsigned long fout) | ||
| 36 | { | ||
| 37 | unsigned long regval; | ||
| 38 | |||
| 39 | if (fout > (st->mclk / 2)) | ||
| 40 | return -EINVAL; | ||
| 41 | |||
| 42 | regval = ad9834_calc_freqreg(st->mclk, fout); | ||
| 43 | |||
| 44 | st->freq_data[0] = cpu_to_be16(addr | (regval & | ||
| 45 | RES_MASK(AD9834_FREQ_BITS / 2))); | ||
| 46 | st->freq_data[1] = cpu_to_be16(addr | ((regval >> | ||
| 47 | (AD9834_FREQ_BITS / 2)) & | ||
| 48 | RES_MASK(AD9834_FREQ_BITS / 2))); | ||
| 49 | |||
| 50 | return spi_sync(st->spi, &st->freq_msg); | ||
| 51 | } | ||
| 52 | |||
| 53 | static int ad9834_write_phase(struct ad9834_state *st, | ||
| 54 | unsigned long addr, unsigned long phase) | ||
| 55 | { | ||
| 56 | if (phase > (1 << AD9834_PHASE_BITS)) | ||
| 57 | return -EINVAL; | ||
| 58 | st->data = cpu_to_be16(addr | phase); | ||
| 59 | |||
| 60 | return spi_sync(st->spi, &st->msg); | ||
| 61 | } | ||
| 62 | |||
| 63 | static ssize_t ad9834_write(struct device *dev, | ||
| 64 | struct device_attribute *attr, | ||
| 65 | const char *buf, | ||
| 66 | size_t len) | ||
| 67 | { | ||
| 68 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 69 | struct ad9834_state *st = iio_priv(dev_info); | ||
| 70 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 71 | int ret; | ||
| 72 | long val; | ||
| 73 | |||
| 74 | ret = strict_strtoul(buf, 10, &val); | ||
| 75 | if (ret) | ||
| 76 | goto error_ret; | ||
| 77 | |||
| 78 | mutex_lock(&dev_info->mlock); | ||
| 79 | switch (this_attr->address) { | ||
| 80 | case AD9834_REG_FREQ0: | ||
| 81 | case AD9834_REG_FREQ1: | ||
| 82 | ret = ad9834_write_frequency(st, this_attr->address, val); | ||
| 83 | break; | ||
| 84 | case AD9834_REG_PHASE0: | ||
| 85 | case AD9834_REG_PHASE1: | ||
| 86 | ret = ad9834_write_phase(st, this_attr->address, val); | ||
| 87 | break; | ||
| 88 | case AD9834_OPBITEN: | ||
| 89 | if (st->control & AD9834_MODE) { | ||
| 90 | ret = -EINVAL; /* AD9843 reserved mode */ | ||
| 91 | break; | ||
| 92 | } | ||
| 93 | |||
| 94 | if (val) | ||
| 95 | st->control |= AD9834_OPBITEN; | ||
| 96 | else | ||
| 97 | st->control &= ~AD9834_OPBITEN; | ||
| 98 | |||
| 99 | st->data = cpu_to_be16(AD9834_REG_CMD | st->control); | ||
| 100 | ret = spi_sync(st->spi, &st->msg); | ||
| 101 | break; | ||
| 102 | case AD9834_PIN_SW: | ||
| 103 | if (val) | ||
| 104 | st->control |= AD9834_PIN_SW; | ||
| 105 | else | ||
| 106 | st->control &= ~AD9834_PIN_SW; | ||
| 107 | st->data = cpu_to_be16(AD9834_REG_CMD | st->control); | ||
| 108 | ret = spi_sync(st->spi, &st->msg); | ||
| 109 | break; | ||
| 110 | case AD9834_FSEL: | ||
| 111 | case AD9834_PSEL: | ||
| 112 | if (val == 0) | ||
| 113 | st->control &= ~(this_attr->address | AD9834_PIN_SW); | ||
| 114 | else if (val == 1) { | ||
| 115 | st->control |= this_attr->address; | ||
| 116 | st->control &= ~AD9834_PIN_SW; | ||
| 117 | } else { | ||
| 118 | ret = -EINVAL; | ||
| 119 | break; | ||
| 120 | } | ||
| 121 | st->data = cpu_to_be16(AD9834_REG_CMD | st->control); | ||
| 122 | ret = spi_sync(st->spi, &st->msg); | ||
| 123 | break; | ||
| 124 | case AD9834_RESET: | ||
| 125 | if (val) | ||
| 126 | st->control &= ~AD9834_RESET; | ||
| 127 | else | ||
| 128 | st->control |= AD9834_RESET; | ||
| 129 | |||
| 130 | st->data = cpu_to_be16(AD9834_REG_CMD | st->control); | ||
| 131 | ret = spi_sync(st->spi, &st->msg); | ||
| 132 | break; | ||
| 133 | default: | ||
| 134 | ret = -ENODEV; | ||
| 135 | } | ||
| 136 | mutex_unlock(&dev_info->mlock); | ||
| 137 | |||
| 138 | error_ret: | ||
| 139 | return ret ? ret : len; | ||
| 140 | } | ||
| 141 | |||
| 142 | static ssize_t ad9834_store_wavetype(struct device *dev, | ||
| 143 | struct device_attribute *attr, | ||
| 144 | const char *buf, | ||
| 145 | size_t len) | ||
| 146 | { | ||
| 147 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 148 | struct ad9834_state *st = iio_priv(dev_info); | ||
| 149 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 150 | int ret = 0; | ||
| 151 | bool is_ad9833_7 = (st->devid == ID_AD9833) || (st->devid == ID_AD9837); | ||
| 152 | |||
| 153 | mutex_lock(&dev_info->mlock); | ||
| 154 | |||
| 155 | switch (this_attr->address) { | ||
| 156 | case 0: | ||
| 157 | if (sysfs_streq(buf, "sine")) { | ||
| 158 | st->control &= ~AD9834_MODE; | ||
| 159 | if (is_ad9833_7) | ||
| 160 | st->control &= ~AD9834_OPBITEN; | ||
| 161 | } else if (sysfs_streq(buf, "triangle")) { | ||
| 162 | if (is_ad9833_7) { | ||
| 163 | st->control &= ~AD9834_OPBITEN; | ||
| 164 | st->control |= AD9834_MODE; | ||
| 165 | } else if (st->control & AD9834_OPBITEN) { | ||
| 166 | ret = -EINVAL; /* AD9843 reserved mode */ | ||
| 167 | } else { | ||
| 168 | st->control |= AD9834_MODE; | ||
| 169 | } | ||
| 170 | } else if (is_ad9833_7 && sysfs_streq(buf, "square")) { | ||
| 171 | st->control &= ~AD9834_MODE; | ||
| 172 | st->control |= AD9834_OPBITEN; | ||
| 173 | } else { | ||
| 174 | ret = -EINVAL; | ||
| 175 | } | ||
| 176 | |||
| 177 | break; | ||
| 178 | case 1: | ||
| 179 | if (sysfs_streq(buf, "square") && | ||
| 180 | !(st->control & AD9834_MODE)) { | ||
| 181 | st->control &= ~AD9834_MODE; | ||
| 182 | st->control |= AD9834_OPBITEN; | ||
| 183 | } else { | ||
| 184 | ret = -EINVAL; | ||
| 185 | } | ||
| 186 | break; | ||
| 187 | default: | ||
| 188 | ret = -EINVAL; | ||
| 189 | break; | ||
| 190 | } | ||
| 191 | |||
| 192 | if (!ret) { | ||
| 193 | st->data = cpu_to_be16(AD9834_REG_CMD | st->control); | ||
| 194 | ret = spi_sync(st->spi, &st->msg); | ||
| 195 | } | ||
| 196 | mutex_unlock(&dev_info->mlock); | ||
| 197 | |||
| 198 | return ret ? ret : len; | ||
| 199 | } | ||
| 200 | |||
| 201 | static ssize_t ad9834_show_out0_wavetype_available(struct device *dev, | ||
| 202 | struct device_attribute *attr, | ||
| 203 | char *buf) | ||
| 204 | { | ||
| 205 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 206 | struct ad9834_state *st = iio_priv(dev_info); | ||
| 207 | char *str; | ||
| 208 | |||
| 209 | if ((st->devid == ID_AD9833) || (st->devid == ID_AD9837)) | ||
| 210 | str = "sine triangle square"; | ||
| 211 | else if (st->control & AD9834_OPBITEN) | ||
| 212 | str = "sine"; | ||
| 213 | else | ||
| 214 | str = "sine triangle"; | ||
| 215 | |||
| 216 | return sprintf(buf, "%s\n", str); | ||
| 217 | } | ||
| 218 | |||
| 219 | |||
| 220 | static IIO_DEVICE_ATTR(dds0_out0_wavetype_available, S_IRUGO, | ||
| 221 | ad9834_show_out0_wavetype_available, NULL, 0); | ||
| 222 | |||
| 223 | static ssize_t ad9834_show_out1_wavetype_available(struct device *dev, | ||
| 224 | struct device_attribute *attr, | ||
| 225 | char *buf) | ||
| 226 | { | ||
| 227 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 228 | struct ad9834_state *st = iio_priv(dev_info); | ||
| 229 | char *str; | ||
| 230 | |||
| 231 | if (st->control & AD9834_MODE) | ||
| 232 | str = ""; | ||
| 233 | else | ||
| 234 | str = "square"; | ||
| 235 | |||
| 236 | return sprintf(buf, "%s\n", str); | ||
| 237 | } | ||
| 238 | |||
| 239 | static IIO_DEVICE_ATTR(dds0_out1_wavetype_available, S_IRUGO, | ||
| 240 | ad9834_show_out1_wavetype_available, NULL, 0); | ||
| 241 | |||
| 242 | /** | ||
| 243 | * see dds.h for further information | ||
| 244 | */ | ||
| 245 | |||
| 246 | static IIO_DEV_ATTR_FREQ(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ0); | ||
| 247 | static IIO_DEV_ATTR_FREQ(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_FREQ1); | ||
| 248 | static IIO_DEV_ATTR_FREQSYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_FSEL); | ||
| 249 | static IIO_CONST_ATTR_FREQ_SCALE(0, "1"); /* 1Hz */ | ||
| 250 | |||
| 251 | static IIO_DEV_ATTR_PHASE(0, 0, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE0); | ||
| 252 | static IIO_DEV_ATTR_PHASE(0, 1, S_IWUSR, NULL, ad9834_write, AD9834_REG_PHASE1); | ||
| 253 | static IIO_DEV_ATTR_PHASESYMBOL(0, S_IWUSR, NULL, ad9834_write, AD9834_PSEL); | ||
| 254 | static IIO_CONST_ATTR_PHASE_SCALE(0, "0.0015339808"); /* 2PI/2^12 rad*/ | ||
| 255 | |||
| 256 | static IIO_DEV_ATTR_PINCONTROL_EN(0, S_IWUSR, NULL, | ||
| 257 | ad9834_write, AD9834_PIN_SW); | ||
| 258 | static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL, ad9834_write, AD9834_RESET); | ||
| 259 | static IIO_DEV_ATTR_OUTY_ENABLE(0, 1, S_IWUSR, NULL, | ||
| 260 | ad9834_write, AD9834_OPBITEN); | ||
| 261 | static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0); | ||
| 262 | static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1); | ||
| 263 | |||
| 264 | static struct attribute *ad9834_attributes[] = { | ||
| 265 | &iio_dev_attr_dds0_freq0.dev_attr.attr, | ||
| 266 | &iio_dev_attr_dds0_freq1.dev_attr.attr, | ||
| 267 | &iio_const_attr_dds0_freq_scale.dev_attr.attr, | ||
| 268 | &iio_dev_attr_dds0_phase0.dev_attr.attr, | ||
| 269 | &iio_dev_attr_dds0_phase1.dev_attr.attr, | ||
| 270 | &iio_const_attr_dds0_phase_scale.dev_attr.attr, | ||
| 271 | &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr, | ||
| 272 | &iio_dev_attr_dds0_freqsymbol.dev_attr.attr, | ||
| 273 | &iio_dev_attr_dds0_phasesymbol.dev_attr.attr, | ||
| 274 | &iio_dev_attr_dds0_out_enable.dev_attr.attr, | ||
| 275 | &iio_dev_attr_dds0_out1_enable.dev_attr.attr, | ||
| 276 | &iio_dev_attr_dds0_out0_wavetype.dev_attr.attr, | ||
| 277 | &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr, | ||
| 278 | &iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr, | ||
| 279 | &iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr, | ||
| 280 | NULL, | ||
| 281 | }; | ||
| 282 | |||
| 283 | static mode_t ad9834_attr_is_visible(struct kobject *kobj, | ||
| 284 | struct attribute *attr, int n) | ||
| 285 | { | ||
| 286 | struct device *dev = container_of(kobj, struct device, kobj); | ||
| 287 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 288 | struct ad9834_state *st = iio_priv(dev_info); | ||
| 289 | |||
| 290 | mode_t mode = attr->mode; | ||
| 291 | |||
| 292 | if (((st->devid == ID_AD9833) || (st->devid == ID_AD9837)) && | ||
| 293 | ((attr == &iio_dev_attr_dds0_out1_enable.dev_attr.attr) || | ||
| 294 | (attr == &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr) || | ||
| 295 | (attr == | ||
| 296 | &iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr) || | ||
| 297 | (attr == &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr))) | ||
| 298 | mode = 0; | ||
| 299 | |||
| 300 | return mode; | ||
| 301 | } | ||
| 302 | |||
| 303 | static const struct attribute_group ad9834_attribute_group = { | ||
| 304 | .attrs = ad9834_attributes, | ||
| 305 | .is_visible = ad9834_attr_is_visible, | ||
| 306 | }; | ||
| 307 | |||
| 308 | static const struct iio_info ad9834_info = { | ||
| 309 | .attrs = &ad9834_attribute_group, | ||
| 310 | .driver_module = THIS_MODULE, | ||
| 311 | }; | ||
| 312 | |||
| 313 | static int __devinit ad9834_probe(struct spi_device *spi) | ||
| 314 | { | ||
| 315 | struct ad9834_platform_data *pdata = spi->dev.platform_data; | ||
| 316 | struct ad9834_state *st; | ||
| 317 | struct iio_dev *indio_dev; | ||
| 318 | struct regulator *reg; | ||
| 319 | int ret; | ||
| 320 | |||
| 321 | if (!pdata) { | ||
| 322 | dev_dbg(&spi->dev, "no platform data?\n"); | ||
| 323 | return -ENODEV; | ||
| 324 | } | ||
| 325 | |||
| 326 | reg = regulator_get(&spi->dev, "vcc"); | ||
| 327 | if (!IS_ERR(reg)) { | ||
| 328 | ret = regulator_enable(reg); | ||
| 329 | if (ret) | ||
| 330 | goto error_put_reg; | ||
| 331 | } | ||
| 332 | |||
| 333 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
| 334 | if (indio_dev == NULL) { | ||
| 335 | ret = -ENOMEM; | ||
| 336 | goto error_disable_reg; | ||
| 337 | } | ||
| 338 | spi_set_drvdata(spi, indio_dev); | ||
| 339 | st = iio_priv(indio_dev); | ||
| 340 | st->mclk = pdata->mclk; | ||
| 341 | st->spi = spi; | ||
| 342 | st->devid = spi_get_device_id(spi)->driver_data; | ||
| 343 | st->reg = reg; | ||
| 344 | indio_dev->dev.parent = &spi->dev; | ||
| 345 | indio_dev->name = spi_get_device_id(spi)->name; | ||
| 346 | indio_dev->info = &ad9834_info; | ||
| 347 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 348 | |||
| 349 | /* Setup default messages */ | ||
| 350 | |||
| 351 | st->xfer.tx_buf = &st->data; | ||
| 352 | st->xfer.len = 2; | ||
| 353 | |||
| 354 | spi_message_init(&st->msg); | ||
| 355 | spi_message_add_tail(&st->xfer, &st->msg); | ||
| 356 | |||
| 357 | st->freq_xfer[0].tx_buf = &st->freq_data[0]; | ||
| 358 | st->freq_xfer[0].len = 2; | ||
| 359 | st->freq_xfer[0].cs_change = 1; | ||
| 360 | st->freq_xfer[1].tx_buf = &st->freq_data[1]; | ||
| 361 | st->freq_xfer[1].len = 2; | ||
| 362 | |||
| 363 | spi_message_init(&st->freq_msg); | ||
| 364 | spi_message_add_tail(&st->freq_xfer[0], &st->freq_msg); | ||
| 365 | spi_message_add_tail(&st->freq_xfer[1], &st->freq_msg); | ||
| 366 | |||
| 367 | st->control = AD9834_B28 | AD9834_RESET; | ||
| 368 | |||
| 369 | if (!pdata->en_div2) | ||
| 370 | st->control |= AD9834_DIV2; | ||
| 371 | |||
| 372 | if (!pdata->en_signbit_msb_out && (st->devid == ID_AD9834)) | ||
| 373 | st->control |= AD9834_SIGN_PIB; | ||
| 374 | |||
| 375 | st->data = cpu_to_be16(AD9834_REG_CMD | st->control); | ||
| 376 | ret = spi_sync(st->spi, &st->msg); | ||
| 377 | if (ret) { | ||
| 378 | dev_err(&spi->dev, "device init failed\n"); | ||
| 379 | goto error_free_device; | ||
| 380 | } | ||
| 381 | |||
| 382 | ret = ad9834_write_frequency(st, AD9834_REG_FREQ0, pdata->freq0); | ||
| 383 | if (ret) | ||
| 384 | goto error_free_device; | ||
| 385 | |||
| 386 | ret = ad9834_write_frequency(st, AD9834_REG_FREQ1, pdata->freq1); | ||
| 387 | if (ret) | ||
| 388 | goto error_free_device; | ||
| 389 | |||
| 390 | ret = ad9834_write_phase(st, AD9834_REG_PHASE0, pdata->phase0); | ||
| 391 | if (ret) | ||
| 392 | goto error_free_device; | ||
| 393 | |||
| 394 | ret = ad9834_write_phase(st, AD9834_REG_PHASE1, pdata->phase1); | ||
| 395 | if (ret) | ||
| 396 | goto error_free_device; | ||
| 397 | |||
| 398 | ret = iio_device_register(indio_dev); | ||
| 399 | if (ret) | ||
| 400 | goto error_free_device; | ||
| 401 | |||
| 402 | return 0; | ||
| 403 | |||
| 404 | error_free_device: | ||
| 405 | iio_free_device(indio_dev); | ||
| 406 | error_disable_reg: | ||
| 407 | if (!IS_ERR(reg)) | ||
| 408 | regulator_disable(reg); | ||
| 409 | error_put_reg: | ||
| 410 | if (!IS_ERR(reg)) | ||
| 411 | regulator_put(reg); | ||
| 412 | return ret; | ||
| 413 | } | ||
| 414 | |||
| 415 | static int __devexit ad9834_remove(struct spi_device *spi) | ||
| 416 | { | ||
| 417 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | ||
| 418 | struct ad9834_state *st = iio_priv(indio_dev); | ||
| 419 | struct regulator *reg = st->reg; | ||
| 420 | |||
| 421 | iio_device_unregister(indio_dev); | ||
| 422 | if (!IS_ERR(reg)) { | ||
| 423 | regulator_disable(reg); | ||
| 424 | regulator_put(reg); | ||
| 425 | } | ||
| 426 | |||
| 427 | return 0; | ||
| 428 | } | ||
| 429 | |||
| 430 | static const struct spi_device_id ad9834_id[] = { | ||
| 431 | {"ad9833", ID_AD9833}, | ||
| 432 | {"ad9834", ID_AD9834}, | ||
| 433 | {"ad9837", ID_AD9837}, | ||
| 434 | {"ad9838", ID_AD9838}, | ||
| 435 | {} | ||
| 436 | }; | ||
| 437 | |||
| 438 | static struct spi_driver ad9834_driver = { | ||
| 439 | .driver = { | ||
| 440 | .name = "ad9834", | ||
| 441 | .bus = &spi_bus_type, | ||
| 442 | .owner = THIS_MODULE, | ||
| 443 | }, | ||
| 444 | .probe = ad9834_probe, | ||
| 445 | .remove = __devexit_p(ad9834_remove), | ||
| 446 | .id_table = ad9834_id, | ||
| 447 | }; | ||
| 448 | |||
| 449 | static int __init ad9834_init(void) | ||
| 450 | { | ||
| 451 | return spi_register_driver(&ad9834_driver); | ||
| 452 | } | ||
| 453 | module_init(ad9834_init); | ||
| 454 | |||
| 455 | static void __exit ad9834_exit(void) | ||
| 456 | { | ||
| 457 | spi_unregister_driver(&ad9834_driver); | ||
| 458 | } | ||
| 459 | module_exit(ad9834_exit); | ||
| 460 | |||
| 461 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
| 462 | MODULE_DESCRIPTION("Analog Devices AD9833/AD9834/AD9837/AD9838 DDS"); | ||
| 463 | MODULE_LICENSE("GPL v2"); | ||
| 464 | MODULE_ALIAS("spi:ad9834"); | ||
diff --git a/drivers/staging/iio/dds/ad9834.h b/drivers/staging/iio/dds/ad9834.h new file mode 100644 index 00000000000..ed5ed8d0007 --- /dev/null +++ b/drivers/staging/iio/dds/ad9834.h | |||
| @@ -0,0 +1,112 @@ | |||
| 1 | /* | ||
| 2 | * AD9833/AD9834/AD9837/AD9838 SPI DDS driver | ||
| 3 | * | ||
| 4 | * Copyright 2010-2011 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | #ifndef IIO_DDS_AD9834_H_ | ||
| 9 | #define IIO_DDS_AD9834_H_ | ||
| 10 | |||
| 11 | /* Registers */ | ||
| 12 | |||
| 13 | #define AD9834_REG_CMD (0 << 14) | ||
| 14 | #define AD9834_REG_FREQ0 (1 << 14) | ||
| 15 | #define AD9834_REG_FREQ1 (2 << 14) | ||
| 16 | #define AD9834_REG_PHASE0 (6 << 13) | ||
| 17 | #define AD9834_REG_PHASE1 (7 << 13) | ||
| 18 | |||
| 19 | /* Command Control Bits */ | ||
| 20 | |||
| 21 | #define AD9834_B28 (1 << 13) | ||
| 22 | #define AD9834_HLB (1 << 12) | ||
| 23 | #define AD9834_FSEL (1 << 11) | ||
| 24 | #define AD9834_PSEL (1 << 10) | ||
| 25 | #define AD9834_PIN_SW (1 << 9) | ||
| 26 | #define AD9834_RESET (1 << 8) | ||
| 27 | #define AD9834_SLEEP1 (1 << 7) | ||
| 28 | #define AD9834_SLEEP12 (1 << 6) | ||
| 29 | #define AD9834_OPBITEN (1 << 5) | ||
| 30 | #define AD9834_SIGN_PIB (1 << 4) | ||
| 31 | #define AD9834_DIV2 (1 << 3) | ||
| 32 | #define AD9834_MODE (1 << 1) | ||
| 33 | |||
| 34 | #define AD9834_FREQ_BITS 28 | ||
| 35 | #define AD9834_PHASE_BITS 12 | ||
| 36 | |||
| 37 | #define RES_MASK(bits) ((1 << (bits)) - 1) | ||
| 38 | |||
| 39 | /** | ||
| 40 | * struct ad9834_state - driver instance specific data | ||
| 41 | * @spi: spi_device | ||
| 42 | * @reg: supply regulator | ||
| 43 | * @mclk: external master clock | ||
| 44 | * @control: cached control word | ||
| 45 | * @xfer: default spi transfer | ||
| 46 | * @msg: default spi message | ||
| 47 | * @freq_xfer: tuning word spi transfer | ||
| 48 | * @freq_msg: tuning word spi message | ||
| 49 | * @data: spi transmit buffer | ||
| 50 | * @freq_data: tuning word spi transmit buffer | ||
| 51 | */ | ||
| 52 | |||
| 53 | struct ad9834_state { | ||
| 54 | struct spi_device *spi; | ||
| 55 | struct regulator *reg; | ||
| 56 | unsigned int mclk; | ||
| 57 | unsigned short control; | ||
| 58 | unsigned short devid; | ||
| 59 | struct spi_transfer xfer; | ||
| 60 | struct spi_message msg; | ||
| 61 | struct spi_transfer freq_xfer[2]; | ||
| 62 | struct spi_message freq_msg; | ||
| 63 | |||
| 64 | /* | ||
| 65 | * DMA (thus cache coherency maintenance) requires the | ||
| 66 | * transfer buffers to live in their own cache lines. | ||
| 67 | */ | ||
| 68 | unsigned short data ____cacheline_aligned; | ||
| 69 | unsigned short freq_data[2] ; | ||
| 70 | }; | ||
| 71 | |||
| 72 | |||
| 73 | /* | ||
| 74 | * TODO: struct ad7887_platform_data needs to go into include/linux/iio | ||
| 75 | */ | ||
| 76 | |||
| 77 | /** | ||
| 78 | * struct ad9834_platform_data - platform specific information | ||
| 79 | * @mclk: master clock in Hz | ||
| 80 | * @freq0: power up freq0 tuning word in Hz | ||
| 81 | * @freq1: power up freq1 tuning word in Hz | ||
| 82 | * @phase0: power up phase0 value [0..4095] correlates with 0..2PI | ||
| 83 | * @phase1: power up phase1 value [0..4095] correlates with 0..2PI | ||
| 84 | * @en_div2: digital output/2 is passed to the SIGN BIT OUT pin | ||
| 85 | * @en_signbit_msb_out: the MSB (or MSB/2) of the DAC data is connected to the | ||
| 86 | * SIGN BIT OUT pin. en_div2 controls whether it is the MSB | ||
| 87 | * or MSB/2 that is output. if en_signbit_msb_out=false, | ||
| 88 | * the on-board comparator is connected to SIGN BIT OUT | ||
| 89 | */ | ||
| 90 | |||
| 91 | struct ad9834_platform_data { | ||
| 92 | unsigned int mclk; | ||
| 93 | unsigned int freq0; | ||
| 94 | unsigned int freq1; | ||
| 95 | unsigned short phase0; | ||
| 96 | unsigned short phase1; | ||
| 97 | bool en_div2; | ||
| 98 | bool en_signbit_msb_out; | ||
| 99 | }; | ||
| 100 | |||
| 101 | /** | ||
| 102 | * ad9834_supported_device_ids: | ||
| 103 | */ | ||
| 104 | |||
| 105 | enum ad9834_supported_device_ids { | ||
| 106 | ID_AD9833, | ||
| 107 | ID_AD9834, | ||
| 108 | ID_AD9837, | ||
| 109 | ID_AD9838, | ||
| 110 | }; | ||
| 111 | |||
| 112 | #endif /* IIO_DDS_AD9834_H_ */ | ||
diff --git a/drivers/staging/iio/dds/ad9850.c b/drivers/staging/iio/dds/ad9850.c new file mode 100644 index 00000000000..d7c9d05f635 --- /dev/null +++ b/drivers/staging/iio/dds/ad9850.c | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | /* | ||
| 2 | * Driver for ADI Direct Digital Synthesis ad9850 | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010-2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | #include <linux/types.h> | ||
| 12 | #include <linux/mutex.h> | ||
| 13 | #include <linux/device.h> | ||
| 14 | #include <linux/spi/spi.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/sysfs.h> | ||
| 17 | |||
| 18 | #include "../iio.h" | ||
| 19 | #include "../sysfs.h" | ||
| 20 | |||
| 21 | #define DRV_NAME "ad9850" | ||
| 22 | |||
| 23 | #define value_mask (u16)0xf000 | ||
| 24 | #define addr_shift 12 | ||
| 25 | |||
| 26 | /* Register format: 4 bits addr + 12 bits value */ | ||
| 27 | struct ad9850_config { | ||
| 28 | u8 control[5]; | ||
| 29 | }; | ||
| 30 | |||
| 31 | struct ad9850_state { | ||
| 32 | struct mutex lock; | ||
| 33 | struct spi_device *sdev; | ||
| 34 | }; | ||
| 35 | |||
| 36 | static ssize_t ad9850_set_parameter(struct device *dev, | ||
| 37 | struct device_attribute *attr, | ||
| 38 | const char *buf, | ||
| 39 | size_t len) | ||
| 40 | { | ||
| 41 | struct spi_message msg; | ||
| 42 | struct spi_transfer xfer; | ||
| 43 | int ret; | ||
| 44 | struct ad9850_config *config = (struct ad9850_config *)buf; | ||
| 45 | struct iio_dev *idev = dev_get_drvdata(dev); | ||
| 46 | struct ad9850_state *st = iio_priv(idev); | ||
| 47 | |||
| 48 | xfer.len = len; | ||
| 49 | xfer.tx_buf = config; | ||
| 50 | mutex_lock(&st->lock); | ||
| 51 | |||
| 52 | spi_message_init(&msg); | ||
| 53 | spi_message_add_tail(&xfer, &msg); | ||
| 54 | ret = spi_sync(st->sdev, &msg); | ||
| 55 | if (ret) | ||
| 56 | goto error_ret; | ||
| 57 | error_ret: | ||
| 58 | mutex_unlock(&st->lock); | ||
| 59 | |||
| 60 | return ret ? ret : len; | ||
| 61 | } | ||
| 62 | |||
| 63 | static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9850_set_parameter, 0); | ||
| 64 | |||
| 65 | static struct attribute *ad9850_attributes[] = { | ||
| 66 | &iio_dev_attr_dds.dev_attr.attr, | ||
| 67 | NULL, | ||
| 68 | }; | ||
| 69 | |||
| 70 | static const struct attribute_group ad9850_attribute_group = { | ||
| 71 | .attrs = ad9850_attributes, | ||
| 72 | }; | ||
| 73 | |||
| 74 | static const struct iio_info ad9850_info = { | ||
| 75 | .attrs = &ad9850_attribute_group, | ||
| 76 | .driver_module = THIS_MODULE, | ||
| 77 | }; | ||
| 78 | |||
| 79 | static int __devinit ad9850_probe(struct spi_device *spi) | ||
| 80 | { | ||
| 81 | struct ad9850_state *st; | ||
| 82 | struct iio_dev *idev; | ||
| 83 | int ret = 0; | ||
| 84 | |||
| 85 | idev = iio_allocate_device(sizeof(*st)); | ||
| 86 | if (idev == NULL) { | ||
| 87 | ret = -ENOMEM; | ||
| 88 | goto error_ret; | ||
| 89 | } | ||
| 90 | spi_set_drvdata(spi, idev); | ||
| 91 | st = iio_priv(idev); | ||
| 92 | mutex_init(&st->lock); | ||
| 93 | st->sdev = spi; | ||
| 94 | |||
| 95 | idev->dev.parent = &spi->dev; | ||
| 96 | idev->info = &ad9850_info; | ||
| 97 | idev->modes = INDIO_DIRECT_MODE; | ||
| 98 | |||
| 99 | ret = iio_device_register(idev); | ||
| 100 | if (ret) | ||
| 101 | goto error_free_dev; | ||
| 102 | spi->max_speed_hz = 2000000; | ||
| 103 | spi->mode = SPI_MODE_3; | ||
| 104 | spi->bits_per_word = 16; | ||
| 105 | spi_setup(spi); | ||
| 106 | |||
| 107 | return 0; | ||
| 108 | |||
| 109 | error_free_dev: | ||
| 110 | iio_free_device(idev); | ||
| 111 | error_ret: | ||
| 112 | return ret; | ||
| 113 | } | ||
| 114 | |||
| 115 | static int __devexit ad9850_remove(struct spi_device *spi) | ||
| 116 | { | ||
| 117 | iio_device_unregister(spi_get_drvdata(spi)); | ||
| 118 | |||
| 119 | return 0; | ||
| 120 | } | ||
| 121 | |||
| 122 | static struct spi_driver ad9850_driver = { | ||
| 123 | .driver = { | ||
| 124 | .name = DRV_NAME, | ||
| 125 | .owner = THIS_MODULE, | ||
| 126 | }, | ||
| 127 | .probe = ad9850_probe, | ||
| 128 | .remove = __devexit_p(ad9850_remove), | ||
| 129 | }; | ||
| 130 | |||
| 131 | static __init int ad9850_spi_init(void) | ||
| 132 | { | ||
| 133 | return spi_register_driver(&ad9850_driver); | ||
| 134 | } | ||
| 135 | module_init(ad9850_spi_init); | ||
| 136 | |||
| 137 | static __exit void ad9850_spi_exit(void) | ||
| 138 | { | ||
| 139 | spi_unregister_driver(&ad9850_driver); | ||
| 140 | } | ||
| 141 | module_exit(ad9850_spi_exit); | ||
| 142 | |||
| 143 | MODULE_AUTHOR("Cliff Cai"); | ||
| 144 | MODULE_DESCRIPTION("Analog Devices ad9850 driver"); | ||
| 145 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/dds/ad9852.c b/drivers/staging/iio/dds/ad9852.c new file mode 100644 index 00000000000..0184585425d --- /dev/null +++ b/drivers/staging/iio/dds/ad9852.c | |||
| @@ -0,0 +1,297 @@ | |||
| 1 | /* | ||
| 2 | * Driver for ADI Direct Digital Synthesis ad9852 | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | #include <linux/types.h> | ||
| 12 | #include <linux/mutex.h> | ||
| 13 | #include <linux/device.h> | ||
| 14 | #include <linux/spi/spi.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/sysfs.h> | ||
| 17 | |||
| 18 | #include "../iio.h" | ||
| 19 | #include "../sysfs.h" | ||
| 20 | |||
| 21 | #define DRV_NAME "ad9852" | ||
| 22 | |||
| 23 | #define addr_phaad1 0x0 | ||
| 24 | #define addr_phaad2 0x1 | ||
| 25 | #define addr_fretu1 0x2 | ||
| 26 | #define addr_fretu2 0x3 | ||
| 27 | #define addr_delfre 0x4 | ||
| 28 | #define addr_updclk 0x5 | ||
| 29 | #define addr_ramclk 0x6 | ||
| 30 | #define addr_contrl 0x7 | ||
| 31 | #define addr_optskm 0x8 | ||
| 32 | #define addr_optskr 0xa | ||
| 33 | #define addr_dacctl 0xb | ||
| 34 | |||
| 35 | #define COMPPD (1 << 4) | ||
| 36 | #define REFMULT2 (1 << 2) | ||
| 37 | #define BYPPLL (1 << 5) | ||
| 38 | #define PLLRANG (1 << 6) | ||
| 39 | #define IEUPCLK (1) | ||
| 40 | #define OSKEN (1 << 5) | ||
| 41 | |||
| 42 | #define read_bit (1 << 7) | ||
| 43 | |||
| 44 | /* Register format: 1 byte addr + value */ | ||
| 45 | struct ad9852_config { | ||
| 46 | u8 phajst0[3]; | ||
| 47 | u8 phajst1[3]; | ||
| 48 | u8 fretun1[6]; | ||
| 49 | u8 fretun2[6]; | ||
| 50 | u8 dltafre[6]; | ||
| 51 | u8 updtclk[5]; | ||
| 52 | u8 ramprat[4]; | ||
| 53 | u8 control[5]; | ||
| 54 | u8 outpskm[3]; | ||
| 55 | u8 outpskr[2]; | ||
| 56 | u8 daccntl[3]; | ||
| 57 | }; | ||
| 58 | |||
| 59 | struct ad9852_state { | ||
| 60 | struct mutex lock; | ||
| 61 | struct spi_device *sdev; | ||
| 62 | }; | ||
| 63 | |||
| 64 | static ssize_t ad9852_set_parameter(struct device *dev, | ||
| 65 | struct device_attribute *attr, | ||
| 66 | const char *buf, | ||
| 67 | size_t len) | ||
| 68 | { | ||
| 69 | struct spi_message msg; | ||
| 70 | struct spi_transfer xfer; | ||
| 71 | int ret; | ||
| 72 | struct ad9852_config *config = (struct ad9852_config *)buf; | ||
| 73 | struct iio_dev *idev = dev_get_drvdata(dev); | ||
| 74 | struct ad9852_state *st = iio_priv(idev); | ||
| 75 | |||
| 76 | xfer.len = 3; | ||
| 77 | xfer.tx_buf = &config->phajst0[0]; | ||
| 78 | mutex_lock(&st->lock); | ||
| 79 | |||
| 80 | spi_message_init(&msg); | ||
| 81 | spi_message_add_tail(&xfer, &msg); | ||
| 82 | ret = spi_sync(st->sdev, &msg); | ||
| 83 | if (ret) | ||
| 84 | goto error_ret; | ||
| 85 | |||
| 86 | xfer.len = 3; | ||
| 87 | xfer.tx_buf = &config->phajst1[0]; | ||
| 88 | |||
| 89 | spi_message_init(&msg); | ||
| 90 | spi_message_add_tail(&xfer, &msg); | ||
| 91 | ret = spi_sync(st->sdev, &msg); | ||
| 92 | if (ret) | ||
| 93 | goto error_ret; | ||
| 94 | |||
| 95 | xfer.len = 6; | ||
| 96 | xfer.tx_buf = &config->fretun1[0]; | ||
| 97 | |||
| 98 | spi_message_init(&msg); | ||
| 99 | spi_message_add_tail(&xfer, &msg); | ||
| 100 | ret = spi_sync(st->sdev, &msg); | ||
| 101 | if (ret) | ||
| 102 | goto error_ret; | ||
| 103 | |||
| 104 | xfer.len = 6; | ||
| 105 | xfer.tx_buf = &config->fretun2[0]; | ||
| 106 | |||
| 107 | spi_message_init(&msg); | ||
| 108 | spi_message_add_tail(&xfer, &msg); | ||
| 109 | ret = spi_sync(st->sdev, &msg); | ||
| 110 | if (ret) | ||
| 111 | goto error_ret; | ||
| 112 | |||
| 113 | xfer.len = 6; | ||
| 114 | xfer.tx_buf = &config->dltafre[0]; | ||
| 115 | |||
| 116 | spi_message_init(&msg); | ||
| 117 | spi_message_add_tail(&xfer, &msg); | ||
| 118 | ret = spi_sync(st->sdev, &msg); | ||
| 119 | if (ret) | ||
| 120 | goto error_ret; | ||
| 121 | |||
| 122 | xfer.len = 5; | ||
| 123 | xfer.tx_buf = &config->updtclk[0]; | ||
| 124 | |||
| 125 | spi_message_init(&msg); | ||
| 126 | spi_message_add_tail(&xfer, &msg); | ||
| 127 | ret = spi_sync(st->sdev, &msg); | ||
| 128 | if (ret) | ||
| 129 | goto error_ret; | ||
| 130 | |||
| 131 | xfer.len = 4; | ||
| 132 | xfer.tx_buf = &config->ramprat[0]; | ||
| 133 | |||
| 134 | spi_message_init(&msg); | ||
| 135 | spi_message_add_tail(&xfer, &msg); | ||
| 136 | ret = spi_sync(st->sdev, &msg); | ||
| 137 | if (ret) | ||
| 138 | goto error_ret; | ||
| 139 | |||
| 140 | xfer.len = 5; | ||
| 141 | xfer.tx_buf = &config->control[0]; | ||
| 142 | |||
| 143 | spi_message_init(&msg); | ||
| 144 | spi_message_add_tail(&xfer, &msg); | ||
| 145 | ret = spi_sync(st->sdev, &msg); | ||
| 146 | if (ret) | ||
| 147 | goto error_ret; | ||
| 148 | |||
| 149 | xfer.len = 3; | ||
| 150 | xfer.tx_buf = &config->outpskm[0]; | ||
| 151 | |||
| 152 | spi_message_init(&msg); | ||
| 153 | spi_message_add_tail(&xfer, &msg); | ||
| 154 | ret = spi_sync(st->sdev, &msg); | ||
| 155 | if (ret) | ||
| 156 | goto error_ret; | ||
| 157 | |||
| 158 | xfer.len = 2; | ||
| 159 | xfer.tx_buf = &config->outpskr[0]; | ||
| 160 | |||
| 161 | spi_message_init(&msg); | ||
| 162 | spi_message_add_tail(&xfer, &msg); | ||
| 163 | ret = spi_sync(st->sdev, &msg); | ||
| 164 | if (ret) | ||
| 165 | goto error_ret; | ||
| 166 | |||
| 167 | xfer.len = 3; | ||
| 168 | xfer.tx_buf = &config->daccntl[0]; | ||
| 169 | |||
| 170 | spi_message_init(&msg); | ||
| 171 | spi_message_add_tail(&xfer, &msg); | ||
| 172 | ret = spi_sync(st->sdev, &msg); | ||
| 173 | if (ret) | ||
| 174 | goto error_ret; | ||
| 175 | error_ret: | ||
| 176 | mutex_unlock(&st->lock); | ||
| 177 | |||
| 178 | return ret ? ret : len; | ||
| 179 | } | ||
| 180 | |||
| 181 | static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9852_set_parameter, 0); | ||
| 182 | |||
| 183 | static void ad9852_init(struct ad9852_state *st) | ||
| 184 | { | ||
| 185 | struct spi_message msg; | ||
| 186 | struct spi_transfer xfer; | ||
| 187 | int ret; | ||
| 188 | u8 config[5]; | ||
| 189 | |||
| 190 | config[0] = addr_contrl; | ||
| 191 | config[1] = COMPPD; | ||
| 192 | config[2] = REFMULT2 | BYPPLL | PLLRANG; | ||
| 193 | config[3] = IEUPCLK; | ||
| 194 | config[4] = OSKEN; | ||
| 195 | |||
| 196 | mutex_lock(&st->lock); | ||
| 197 | |||
| 198 | xfer.len = 5; | ||
| 199 | xfer.tx_buf = &config; | ||
| 200 | |||
| 201 | spi_message_init(&msg); | ||
| 202 | spi_message_add_tail(&xfer, &msg); | ||
| 203 | ret = spi_sync(st->sdev, &msg); | ||
| 204 | if (ret) | ||
| 205 | goto error_ret; | ||
| 206 | |||
| 207 | error_ret: | ||
| 208 | mutex_unlock(&st->lock); | ||
| 209 | |||
| 210 | |||
| 211 | |||
| 212 | } | ||
| 213 | |||
| 214 | static struct attribute *ad9852_attributes[] = { | ||
| 215 | &iio_dev_attr_dds.dev_attr.attr, | ||
| 216 | NULL, | ||
| 217 | }; | ||
| 218 | |||
| 219 | static const struct attribute_group ad9852_attribute_group = { | ||
| 220 | .name = DRV_NAME, | ||
| 221 | .attrs = ad9852_attributes, | ||
| 222 | }; | ||
| 223 | |||
| 224 | static const struct iio_info ad9852_info = { | ||
| 225 | .attrs = &ad9852_attribute_group, | ||
| 226 | .driver_module = THIS_MODULE, | ||
| 227 | }; | ||
| 228 | |||
| 229 | static int __devinit ad9852_probe(struct spi_device *spi) | ||
| 230 | { | ||
| 231 | struct ad9852_state *st; | ||
| 232 | struct iio_dev *idev; | ||
| 233 | int ret = 0; | ||
| 234 | |||
| 235 | idev = iio_allocate_device(sizeof(*st)); | ||
| 236 | if (idev == NULL) { | ||
| 237 | ret = -ENOMEM; | ||
| 238 | goto error_ret; | ||
| 239 | } | ||
| 240 | st = iio_priv(idev); | ||
| 241 | spi_set_drvdata(spi, idev); | ||
| 242 | mutex_init(&st->lock); | ||
| 243 | st->sdev = spi; | ||
| 244 | |||
| 245 | idev->dev.parent = &spi->dev; | ||
| 246 | idev->info = &ad9852_info; | ||
| 247 | idev->modes = INDIO_DIRECT_MODE; | ||
| 248 | |||
| 249 | ret = iio_device_register(idev); | ||
| 250 | if (ret) | ||
| 251 | goto error_free_dev; | ||
| 252 | spi->max_speed_hz = 2000000; | ||
| 253 | spi->mode = SPI_MODE_3; | ||
| 254 | spi->bits_per_word = 8; | ||
| 255 | spi_setup(spi); | ||
| 256 | ad9852_init(st); | ||
| 257 | |||
| 258 | return 0; | ||
| 259 | |||
| 260 | error_free_dev: | ||
| 261 | iio_free_device(idev); | ||
| 262 | |||
| 263 | error_ret: | ||
| 264 | return ret; | ||
| 265 | } | ||
| 266 | |||
| 267 | static int __devexit ad9852_remove(struct spi_device *spi) | ||
| 268 | { | ||
| 269 | iio_device_unregister(spi_get_drvdata(spi)); | ||
| 270 | |||
| 271 | return 0; | ||
| 272 | } | ||
| 273 | |||
| 274 | static struct spi_driver ad9852_driver = { | ||
| 275 | .driver = { | ||
| 276 | .name = DRV_NAME, | ||
| 277 | .owner = THIS_MODULE, | ||
| 278 | }, | ||
| 279 | .probe = ad9852_probe, | ||
| 280 | .remove = __devexit_p(ad9852_remove), | ||
| 281 | }; | ||
| 282 | |||
| 283 | static __init int ad9852_spi_init(void) | ||
| 284 | { | ||
| 285 | return spi_register_driver(&ad9852_driver); | ||
| 286 | } | ||
| 287 | module_init(ad9852_spi_init); | ||
| 288 | |||
| 289 | static __exit void ad9852_spi_exit(void) | ||
| 290 | { | ||
| 291 | spi_unregister_driver(&ad9852_driver); | ||
| 292 | } | ||
| 293 | module_exit(ad9852_spi_exit); | ||
| 294 | |||
| 295 | MODULE_AUTHOR("Cliff Cai"); | ||
| 296 | MODULE_DESCRIPTION("Analog Devices ad9852 driver"); | ||
| 297 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/dds/ad9910.c b/drivers/staging/iio/dds/ad9910.c new file mode 100644 index 00000000000..0fa217f7b90 --- /dev/null +++ b/drivers/staging/iio/dds/ad9910.c | |||
| @@ -0,0 +1,430 @@ | |||
| 1 | /* | ||
| 2 | * Driver for ADI Direct Digital Synthesis ad9910 | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | #include <linux/types.h> | ||
| 12 | #include <linux/mutex.h> | ||
| 13 | #include <linux/device.h> | ||
| 14 | #include <linux/spi/spi.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/sysfs.h> | ||
| 17 | |||
| 18 | #include "../iio.h" | ||
| 19 | #include "../sysfs.h" | ||
| 20 | |||
| 21 | #define DRV_NAME "ad9910" | ||
| 22 | |||
| 23 | #define CFR1 0x0 | ||
| 24 | #define CFR2 0x1 | ||
| 25 | #define CFR3 0x2 | ||
| 26 | |||
| 27 | #define AUXDAC 0x3 | ||
| 28 | #define IOUPD 0x4 | ||
| 29 | #define FTW 0x7 | ||
| 30 | #define POW 0x8 | ||
| 31 | #define ASF 0x9 | ||
| 32 | #define MULTC 0x0A | ||
| 33 | #define DIG_RAMPL 0x0B | ||
| 34 | #define DIG_RAMPS 0x0C | ||
| 35 | #define DIG_RAMPR 0x0D | ||
| 36 | #define SIN_TONEP0 0x0E | ||
| 37 | #define SIN_TONEP1 0x0F | ||
| 38 | #define SIN_TONEP2 0x10 | ||
| 39 | #define SIN_TONEP3 0x11 | ||
| 40 | #define SIN_TONEP4 0x12 | ||
| 41 | #define SIN_TONEP5 0x13 | ||
| 42 | #define SIN_TONEP6 0x14 | ||
| 43 | #define SIN_TONEP7 0x15 | ||
| 44 | |||
| 45 | #define RAM_ENABLE (1 << 7) | ||
| 46 | |||
| 47 | #define MANUAL_OSK (1 << 7) | ||
| 48 | #define INVSIC (1 << 6) | ||
| 49 | #define DDS_SINEOP (1) | ||
| 50 | |||
| 51 | #define AUTO_OSK (1) | ||
| 52 | #define OSKEN (1 << 1) | ||
| 53 | #define LOAD_ARR (1 << 2) | ||
| 54 | #define CLR_PHA (1 << 3) | ||
| 55 | #define CLR_DIG (1 << 4) | ||
| 56 | #define ACLR_PHA (1 << 5) | ||
| 57 | #define ACLR_DIG (1 << 6) | ||
| 58 | #define LOAD_LRR (1 << 7) | ||
| 59 | |||
| 60 | #define LSB_FST (1) | ||
| 61 | #define SDIO_IPT (1 << 1) | ||
| 62 | #define EXT_PWD (1 << 3) | ||
| 63 | #define ADAC_PWD (1 << 4) | ||
| 64 | #define REFCLK_PWD (1 << 5) | ||
| 65 | #define DAC_PWD (1 << 6) | ||
| 66 | #define DIG_PWD (1 << 7) | ||
| 67 | |||
| 68 | #define ENA_AMP (1) | ||
| 69 | #define READ_FTW (1) | ||
| 70 | #define DIGR_LOW (1 << 1) | ||
| 71 | #define DIGR_HIGH (1 << 2) | ||
| 72 | #define DIGR_ENA (1 << 3) | ||
| 73 | #define SYNCCLK_ENA (1 << 6) | ||
| 74 | #define ITER_IOUPD (1 << 7) | ||
| 75 | |||
| 76 | #define TX_ENA (1 << 1) | ||
| 77 | #define PDCLK_INV (1 << 2) | ||
| 78 | #define PDCLK_ENB (1 << 3) | ||
| 79 | |||
| 80 | #define PARA_ENA (1 << 4) | ||
| 81 | #define SYNC_DIS (1 << 5) | ||
| 82 | #define DATA_ASS (1 << 6) | ||
| 83 | #define MATCH_ENA (1 << 7) | ||
| 84 | |||
| 85 | #define PLL_ENA (1) | ||
| 86 | #define PFD_RST (1 << 2) | ||
| 87 | #define REFCLK_RST (1 << 6) | ||
| 88 | #define REFCLK_BYP (1 << 7) | ||
| 89 | |||
| 90 | /* Register format: 1 byte addr + value */ | ||
| 91 | struct ad9910_config { | ||
| 92 | u8 auxdac[5]; | ||
| 93 | u8 ioupd[5]; | ||
| 94 | u8 ftw[5]; | ||
| 95 | u8 pow[3]; | ||
| 96 | u8 asf[5]; | ||
| 97 | u8 multc[5]; | ||
| 98 | u8 dig_rampl[9]; | ||
| 99 | u8 dig_ramps[9]; | ||
| 100 | u8 dig_rampr[5]; | ||
| 101 | u8 sin_tonep0[9]; | ||
| 102 | u8 sin_tonep1[9]; | ||
| 103 | u8 sin_tonep2[9]; | ||
| 104 | u8 sin_tonep3[9]; | ||
| 105 | u8 sin_tonep4[9]; | ||
| 106 | u8 sin_tonep5[9]; | ||
| 107 | u8 sin_tonep6[9]; | ||
| 108 | u8 sin_tonep7[9]; | ||
| 109 | }; | ||
| 110 | |||
| 111 | struct ad9910_state { | ||
| 112 | struct mutex lock; | ||
| 113 | struct spi_device *sdev; | ||
| 114 | }; | ||
| 115 | |||
| 116 | static ssize_t ad9910_set_parameter(struct device *dev, | ||
| 117 | struct device_attribute *attr, | ||
| 118 | const char *buf, | ||
| 119 | size_t len) | ||
| 120 | { | ||
| 121 | struct spi_message msg; | ||
| 122 | struct spi_transfer xfer; | ||
| 123 | int ret; | ||
| 124 | struct ad9910_config *config = (struct ad9910_config *)buf; | ||
| 125 | struct iio_dev *idev = dev_get_drvdata(dev); | ||
| 126 | struct ad9910_state *st = iio_priv(idev); | ||
| 127 | |||
| 128 | xfer.len = 5; | ||
| 129 | xfer.tx_buf = &config->auxdac[0]; | ||
| 130 | mutex_lock(&st->lock); | ||
| 131 | |||
| 132 | spi_message_init(&msg); | ||
| 133 | spi_message_add_tail(&xfer, &msg); | ||
| 134 | ret = spi_sync(st->sdev, &msg); | ||
| 135 | if (ret) | ||
| 136 | goto error_ret; | ||
| 137 | |||
| 138 | xfer.len = 5; | ||
| 139 | xfer.tx_buf = &config->ioupd[0]; | ||
| 140 | |||
| 141 | spi_message_init(&msg); | ||
| 142 | spi_message_add_tail(&xfer, &msg); | ||
| 143 | ret = spi_sync(st->sdev, &msg); | ||
| 144 | if (ret) | ||
| 145 | goto error_ret; | ||
| 146 | |||
| 147 | xfer.len = 5; | ||
| 148 | xfer.tx_buf = &config->ftw[0]; | ||
| 149 | |||
| 150 | spi_message_init(&msg); | ||
| 151 | spi_message_add_tail(&xfer, &msg); | ||
| 152 | ret = spi_sync(st->sdev, &msg); | ||
| 153 | if (ret) | ||
| 154 | goto error_ret; | ||
| 155 | |||
| 156 | xfer.len = 3; | ||
| 157 | xfer.tx_buf = &config->pow[0]; | ||
| 158 | |||
| 159 | spi_message_init(&msg); | ||
| 160 | spi_message_add_tail(&xfer, &msg); | ||
| 161 | ret = spi_sync(st->sdev, &msg); | ||
| 162 | if (ret) | ||
| 163 | goto error_ret; | ||
| 164 | |||
| 165 | xfer.len = 5; | ||
| 166 | xfer.tx_buf = &config->asf[0]; | ||
| 167 | |||
| 168 | spi_message_init(&msg); | ||
| 169 | spi_message_add_tail(&xfer, &msg); | ||
| 170 | ret = spi_sync(st->sdev, &msg); | ||
| 171 | if (ret) | ||
| 172 | goto error_ret; | ||
| 173 | |||
| 174 | xfer.len = 5; | ||
| 175 | xfer.tx_buf = &config->multc[0]; | ||
| 176 | |||
| 177 | spi_message_init(&msg); | ||
| 178 | spi_message_add_tail(&xfer, &msg); | ||
| 179 | ret = spi_sync(st->sdev, &msg); | ||
| 180 | if (ret) | ||
| 181 | goto error_ret; | ||
| 182 | |||
| 183 | xfer.len = 9; | ||
| 184 | xfer.tx_buf = &config->dig_rampl[0]; | ||
| 185 | |||
| 186 | spi_message_init(&msg); | ||
| 187 | spi_message_add_tail(&xfer, &msg); | ||
| 188 | ret = spi_sync(st->sdev, &msg); | ||
| 189 | if (ret) | ||
| 190 | goto error_ret; | ||
| 191 | |||
| 192 | xfer.len = 9; | ||
| 193 | xfer.tx_buf = &config->dig_ramps[0]; | ||
| 194 | |||
| 195 | spi_message_init(&msg); | ||
| 196 | spi_message_add_tail(&xfer, &msg); | ||
| 197 | ret = spi_sync(st->sdev, &msg); | ||
| 198 | if (ret) | ||
| 199 | goto error_ret; | ||
| 200 | |||
| 201 | xfer.len = 5; | ||
| 202 | xfer.tx_buf = &config->dig_rampr[0]; | ||
| 203 | |||
| 204 | spi_message_init(&msg); | ||
| 205 | spi_message_add_tail(&xfer, &msg); | ||
| 206 | ret = spi_sync(st->sdev, &msg); | ||
| 207 | if (ret) | ||
| 208 | goto error_ret; | ||
| 209 | |||
| 210 | xfer.len = 9; | ||
| 211 | xfer.tx_buf = &config->sin_tonep0[0]; | ||
| 212 | |||
| 213 | spi_message_init(&msg); | ||
| 214 | spi_message_add_tail(&xfer, &msg); | ||
| 215 | ret = spi_sync(st->sdev, &msg); | ||
| 216 | if (ret) | ||
| 217 | goto error_ret; | ||
| 218 | |||
| 219 | xfer.len = 9; | ||
| 220 | xfer.tx_buf = &config->sin_tonep1[0]; | ||
| 221 | |||
| 222 | spi_message_init(&msg); | ||
| 223 | spi_message_add_tail(&xfer, &msg); | ||
| 224 | ret = spi_sync(st->sdev, &msg); | ||
| 225 | if (ret) | ||
| 226 | goto error_ret; | ||
| 227 | |||
| 228 | xfer.len = 9; | ||
| 229 | xfer.tx_buf = &config->sin_tonep2[0]; | ||
| 230 | |||
| 231 | spi_message_init(&msg); | ||
| 232 | spi_message_add_tail(&xfer, &msg); | ||
| 233 | ret = spi_sync(st->sdev, &msg); | ||
| 234 | if (ret) | ||
| 235 | goto error_ret; | ||
| 236 | xfer.len = 9; | ||
| 237 | xfer.tx_buf = &config->sin_tonep3[0]; | ||
| 238 | |||
| 239 | spi_message_init(&msg); | ||
| 240 | spi_message_add_tail(&xfer, &msg); | ||
| 241 | ret = spi_sync(st->sdev, &msg); | ||
| 242 | if (ret) | ||
| 243 | goto error_ret; | ||
| 244 | |||
| 245 | xfer.len = 9; | ||
| 246 | xfer.tx_buf = &config->sin_tonep4[0]; | ||
| 247 | |||
| 248 | spi_message_init(&msg); | ||
| 249 | spi_message_add_tail(&xfer, &msg); | ||
| 250 | ret = spi_sync(st->sdev, &msg); | ||
| 251 | if (ret) | ||
| 252 | goto error_ret; | ||
| 253 | |||
| 254 | xfer.len = 9; | ||
| 255 | xfer.tx_buf = &config->sin_tonep5[0]; | ||
| 256 | |||
| 257 | spi_message_init(&msg); | ||
| 258 | spi_message_add_tail(&xfer, &msg); | ||
| 259 | ret = spi_sync(st->sdev, &msg); | ||
| 260 | if (ret) | ||
| 261 | goto error_ret; | ||
| 262 | |||
| 263 | xfer.len = 9; | ||
| 264 | xfer.tx_buf = &config->sin_tonep6[0]; | ||
| 265 | |||
| 266 | spi_message_init(&msg); | ||
| 267 | spi_message_add_tail(&xfer, &msg); | ||
| 268 | ret = spi_sync(st->sdev, &msg); | ||
| 269 | if (ret) | ||
| 270 | goto error_ret; | ||
| 271 | |||
| 272 | xfer.len = 9; | ||
| 273 | xfer.tx_buf = &config->sin_tonep7[0]; | ||
| 274 | |||
| 275 | spi_message_init(&msg); | ||
| 276 | spi_message_add_tail(&xfer, &msg); | ||
| 277 | ret = spi_sync(st->sdev, &msg); | ||
| 278 | if (ret) | ||
| 279 | goto error_ret; | ||
| 280 | error_ret: | ||
| 281 | mutex_unlock(&st->lock); | ||
| 282 | |||
| 283 | return ret ? ret : len; | ||
| 284 | } | ||
| 285 | |||
| 286 | static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9910_set_parameter, 0); | ||
| 287 | |||
| 288 | static void ad9910_init(struct ad9910_state *st) | ||
| 289 | { | ||
| 290 | struct spi_message msg; | ||
| 291 | struct spi_transfer xfer; | ||
| 292 | int ret; | ||
| 293 | u8 cfr[5]; | ||
| 294 | |||
| 295 | cfr[0] = CFR1; | ||
| 296 | cfr[1] = 0; | ||
| 297 | cfr[2] = MANUAL_OSK | INVSIC | DDS_SINEOP; | ||
| 298 | cfr[3] = AUTO_OSK | OSKEN | ACLR_PHA | ACLR_DIG | LOAD_LRR; | ||
| 299 | cfr[4] = 0; | ||
| 300 | |||
| 301 | mutex_lock(&st->lock); | ||
| 302 | |||
| 303 | xfer.len = 5; | ||
| 304 | xfer.tx_buf = 𝔠 | ||
| 305 | |||
| 306 | spi_message_init(&msg); | ||
| 307 | spi_message_add_tail(&xfer, &msg); | ||
| 308 | ret = spi_sync(st->sdev, &msg); | ||
| 309 | if (ret) | ||
| 310 | goto error_ret; | ||
| 311 | |||
| 312 | cfr[0] = CFR2; | ||
| 313 | cfr[1] = ENA_AMP; | ||
| 314 | cfr[2] = READ_FTW | DIGR_ENA | ITER_IOUPD; | ||
| 315 | cfr[3] = TX_ENA | PDCLK_INV | PDCLK_ENB; | ||
| 316 | cfr[4] = PARA_ENA; | ||
| 317 | |||
| 318 | xfer.len = 5; | ||
| 319 | xfer.tx_buf = 𝔠 | ||
| 320 | |||
| 321 | spi_message_init(&msg); | ||
| 322 | spi_message_add_tail(&xfer, &msg); | ||
| 323 | ret = spi_sync(st->sdev, &msg); | ||
| 324 | if (ret) | ||
| 325 | goto error_ret; | ||
| 326 | |||
| 327 | cfr[0] = CFR3; | ||
| 328 | cfr[1] = PLL_ENA; | ||
| 329 | cfr[2] = 0; | ||
| 330 | cfr[3] = REFCLK_RST | REFCLK_BYP; | ||
| 331 | cfr[4] = 0; | ||
| 332 | |||
| 333 | xfer.len = 5; | ||
| 334 | xfer.tx_buf = 𝔠 | ||
| 335 | |||
| 336 | spi_message_init(&msg); | ||
| 337 | spi_message_add_tail(&xfer, &msg); | ||
| 338 | ret = spi_sync(st->sdev, &msg); | ||
| 339 | if (ret) | ||
| 340 | goto error_ret; | ||
| 341 | |||
| 342 | error_ret: | ||
| 343 | mutex_unlock(&st->lock); | ||
| 344 | |||
| 345 | |||
| 346 | |||
| 347 | } | ||
| 348 | |||
| 349 | static struct attribute *ad9910_attributes[] = { | ||
| 350 | &iio_dev_attr_dds.dev_attr.attr, | ||
| 351 | NULL, | ||
| 352 | }; | ||
| 353 | |||
| 354 | static const struct attribute_group ad9910_attribute_group = { | ||
| 355 | .name = DRV_NAME, | ||
| 356 | .attrs = ad9910_attributes, | ||
| 357 | }; | ||
| 358 | |||
| 359 | static const struct iio_info ad9910_info = { | ||
| 360 | .attrs = &ad9910_attribute_group, | ||
| 361 | .driver_module = THIS_MODULE, | ||
| 362 | }; | ||
| 363 | |||
| 364 | static int __devinit ad9910_probe(struct spi_device *spi) | ||
| 365 | { | ||
| 366 | struct ad9910_state *st; | ||
| 367 | struct iio_dev *idev; | ||
| 368 | int ret = 0; | ||
| 369 | |||
| 370 | idev = iio_allocate_device(sizeof(*st)); | ||
| 371 | if (idev == NULL) { | ||
| 372 | ret = -ENOMEM; | ||
| 373 | goto error_ret; | ||
| 374 | } | ||
| 375 | spi_set_drvdata(spi, idev); | ||
| 376 | st = iio_priv(idev); | ||
| 377 | mutex_init(&st->lock); | ||
| 378 | st->sdev = spi; | ||
| 379 | |||
| 380 | idev->dev.parent = &spi->dev; | ||
| 381 | idev->info = &ad9910_info; | ||
| 382 | idev->modes = INDIO_DIRECT_MODE; | ||
| 383 | |||
| 384 | ret = iio_device_register(idev); | ||
| 385 | if (ret) | ||
| 386 | goto error_free_dev; | ||
| 387 | spi->max_speed_hz = 2000000; | ||
| 388 | spi->mode = SPI_MODE_3; | ||
| 389 | spi->bits_per_word = 8; | ||
| 390 | spi_setup(spi); | ||
| 391 | ad9910_init(st); | ||
| 392 | return 0; | ||
| 393 | |||
| 394 | error_free_dev: | ||
| 395 | iio_free_device(idev); | ||
| 396 | error_ret: | ||
| 397 | return ret; | ||
| 398 | } | ||
| 399 | |||
| 400 | static int __devexit ad9910_remove(struct spi_device *spi) | ||
| 401 | { | ||
| 402 | iio_device_unregister(spi_get_drvdata(spi)); | ||
| 403 | |||
| 404 | return 0; | ||
| 405 | } | ||
| 406 | |||
| 407 | static struct spi_driver ad9910_driver = { | ||
| 408 | .driver = { | ||
| 409 | .name = DRV_NAME, | ||
| 410 | .owner = THIS_MODULE, | ||
| 411 | }, | ||
| 412 | .probe = ad9910_probe, | ||
| 413 | .remove = __devexit_p(ad9910_remove), | ||
| 414 | }; | ||
| 415 | |||
| 416 | static __init int ad9910_spi_init(void) | ||
| 417 | { | ||
| 418 | return spi_register_driver(&ad9910_driver); | ||
| 419 | } | ||
| 420 | module_init(ad9910_spi_init); | ||
| 421 | |||
| 422 | static __exit void ad9910_spi_exit(void) | ||
| 423 | { | ||
| 424 | spi_unregister_driver(&ad9910_driver); | ||
| 425 | } | ||
| 426 | module_exit(ad9910_spi_exit); | ||
| 427 | |||
| 428 | MODULE_AUTHOR("Cliff Cai"); | ||
| 429 | MODULE_DESCRIPTION("Analog Devices ad9910 driver"); | ||
| 430 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/dds/ad9951.c b/drivers/staging/iio/dds/ad9951.c new file mode 100644 index 00000000000..d361d1f125d --- /dev/null +++ b/drivers/staging/iio/dds/ad9951.c | |||
| @@ -0,0 +1,241 @@ | |||
| 1 | /* | ||
| 2 | * Driver for ADI Direct Digital Synthesis ad9951 | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | #include <linux/types.h> | ||
| 12 | #include <linux/mutex.h> | ||
| 13 | #include <linux/device.h> | ||
| 14 | #include <linux/spi/spi.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/sysfs.h> | ||
| 17 | |||
| 18 | #include "../iio.h" | ||
| 19 | #include "../sysfs.h" | ||
| 20 | |||
| 21 | #define DRV_NAME "ad9951" | ||
| 22 | |||
| 23 | #define CFR1 0x0 | ||
| 24 | #define CFR2 0x1 | ||
| 25 | |||
| 26 | #define AUTO_OSK (1) | ||
| 27 | #define OSKEN (1 << 1) | ||
| 28 | #define LOAD_ARR (1 << 2) | ||
| 29 | |||
| 30 | #define AUTO_SYNC (1 << 7) | ||
| 31 | |||
| 32 | #define LSB_FST (1) | ||
| 33 | #define SDIO_IPT (1 << 1) | ||
| 34 | #define CLR_PHA (1 << 2) | ||
| 35 | #define SINE_OPT (1 << 4) | ||
| 36 | #define ACLR_PHA (1 << 5) | ||
| 37 | |||
| 38 | #define VCO_RANGE (1 << 2) | ||
| 39 | |||
| 40 | #define CRS_OPT (1 << 1) | ||
| 41 | #define HMANU_SYNC (1 << 2) | ||
| 42 | #define HSPD_SYNC (1 << 3) | ||
| 43 | |||
| 44 | /* Register format: 1 byte addr + value */ | ||
| 45 | struct ad9951_config { | ||
| 46 | u8 asf[3]; | ||
| 47 | u8 arr[2]; | ||
| 48 | u8 ftw0[5]; | ||
| 49 | u8 ftw1[3]; | ||
| 50 | }; | ||
| 51 | |||
| 52 | struct ad9951_state { | ||
| 53 | struct mutex lock; | ||
| 54 | struct spi_device *sdev; | ||
| 55 | }; | ||
| 56 | |||
| 57 | static ssize_t ad9951_set_parameter(struct device *dev, | ||
| 58 | struct device_attribute *attr, | ||
| 59 | const char *buf, | ||
| 60 | size_t len) | ||
| 61 | { | ||
| 62 | struct spi_message msg; | ||
| 63 | struct spi_transfer xfer; | ||
| 64 | int ret; | ||
| 65 | struct ad9951_config *config = (struct ad9951_config *)buf; | ||
| 66 | struct iio_dev *idev = dev_get_drvdata(dev); | ||
| 67 | struct ad9951_state *st = iio_priv(idev); | ||
| 68 | |||
| 69 | xfer.len = 3; | ||
| 70 | xfer.tx_buf = &config->asf[0]; | ||
| 71 | mutex_lock(&st->lock); | ||
| 72 | |||
| 73 | spi_message_init(&msg); | ||
| 74 | spi_message_add_tail(&xfer, &msg); | ||
| 75 | ret = spi_sync(st->sdev, &msg); | ||
| 76 | if (ret) | ||
| 77 | goto error_ret; | ||
| 78 | |||
| 79 | xfer.len = 2; | ||
| 80 | xfer.tx_buf = &config->arr[0]; | ||
| 81 | |||
| 82 | spi_message_init(&msg); | ||
| 83 | spi_message_add_tail(&xfer, &msg); | ||
| 84 | ret = spi_sync(st->sdev, &msg); | ||
| 85 | if (ret) | ||
| 86 | goto error_ret; | ||
| 87 | |||
| 88 | xfer.len = 5; | ||
| 89 | xfer.tx_buf = &config->ftw0[0]; | ||
| 90 | |||
| 91 | spi_message_init(&msg); | ||
| 92 | spi_message_add_tail(&xfer, &msg); | ||
| 93 | ret = spi_sync(st->sdev, &msg); | ||
| 94 | if (ret) | ||
| 95 | goto error_ret; | ||
| 96 | |||
| 97 | xfer.len = 3; | ||
| 98 | xfer.tx_buf = &config->ftw1[0]; | ||
| 99 | |||
| 100 | spi_message_init(&msg); | ||
| 101 | spi_message_add_tail(&xfer, &msg); | ||
| 102 | ret = spi_sync(st->sdev, &msg); | ||
| 103 | if (ret) | ||
| 104 | goto error_ret; | ||
| 105 | error_ret: | ||
| 106 | mutex_unlock(&st->lock); | ||
| 107 | |||
| 108 | return ret ? ret : len; | ||
| 109 | } | ||
| 110 | |||
| 111 | static IIO_DEVICE_ATTR(dds, S_IWUSR, NULL, ad9951_set_parameter, 0); | ||
| 112 | |||
| 113 | static void ad9951_init(struct ad9951_state *st) | ||
| 114 | { | ||
| 115 | struct spi_message msg; | ||
| 116 | struct spi_transfer xfer; | ||
| 117 | int ret; | ||
| 118 | u8 cfr[5]; | ||
| 119 | |||
| 120 | cfr[0] = CFR1; | ||
| 121 | cfr[1] = 0; | ||
| 122 | cfr[2] = LSB_FST | CLR_PHA | SINE_OPT | ACLR_PHA; | ||
| 123 | cfr[3] = AUTO_OSK | OSKEN | LOAD_ARR; | ||
| 124 | cfr[4] = 0; | ||
| 125 | |||
| 126 | mutex_lock(&st->lock); | ||
| 127 | |||
| 128 | xfer.len = 5; | ||
| 129 | xfer.tx_buf = 𝔠 | ||
| 130 | |||
| 131 | spi_message_init(&msg); | ||
| 132 | spi_message_add_tail(&xfer, &msg); | ||
| 133 | ret = spi_sync(st->sdev, &msg); | ||
| 134 | if (ret) | ||
| 135 | goto error_ret; | ||
| 136 | |||
| 137 | cfr[0] = CFR2; | ||
| 138 | cfr[1] = VCO_RANGE; | ||
| 139 | cfr[2] = HSPD_SYNC; | ||
| 140 | cfr[3] = 0; | ||
| 141 | |||
| 142 | xfer.len = 4; | ||
| 143 | xfer.tx_buf = 𝔠 | ||
| 144 | |||
| 145 | spi_message_init(&msg); | ||
| 146 | spi_message_add_tail(&xfer, &msg); | ||
| 147 | ret = spi_sync(st->sdev, &msg); | ||
| 148 | if (ret) | ||
| 149 | goto error_ret; | ||
| 150 | |||
| 151 | error_ret: | ||
| 152 | mutex_unlock(&st->lock); | ||
| 153 | |||
| 154 | |||
| 155 | |||
| 156 | } | ||
| 157 | |||
| 158 | static struct attribute *ad9951_attributes[] = { | ||
| 159 | &iio_dev_attr_dds.dev_attr.attr, | ||
| 160 | NULL, | ||
| 161 | }; | ||
| 162 | |||
| 163 | static const struct attribute_group ad9951_attribute_group = { | ||
| 164 | .name = DRV_NAME, | ||
| 165 | .attrs = ad9951_attributes, | ||
| 166 | }; | ||
| 167 | |||
| 168 | static const struct iio_info ad9951_info = { | ||
| 169 | .attrs = &ad9951_attribute_group, | ||
| 170 | .driver_module = THIS_MODULE, | ||
| 171 | }; | ||
| 172 | |||
| 173 | static int __devinit ad9951_probe(struct spi_device *spi) | ||
| 174 | { | ||
| 175 | struct ad9951_state *st; | ||
| 176 | struct iio_dev *idev; | ||
| 177 | int ret = 0; | ||
| 178 | |||
| 179 | idev = iio_allocate_device(sizeof(*st)); | ||
| 180 | if (idev == NULL) { | ||
| 181 | ret = -ENOMEM; | ||
| 182 | goto error_ret; | ||
| 183 | } | ||
| 184 | spi_set_drvdata(spi, idev); | ||
| 185 | st = iio_priv(idev); | ||
| 186 | mutex_init(&st->lock); | ||
| 187 | st->sdev = spi; | ||
| 188 | |||
| 189 | idev->dev.parent = &spi->dev; | ||
| 190 | |||
| 191 | idev->info = &ad9951_info; | ||
| 192 | idev->modes = INDIO_DIRECT_MODE; | ||
| 193 | |||
| 194 | ret = iio_device_register(idev); | ||
| 195 | if (ret) | ||
| 196 | goto error_free_dev; | ||
| 197 | spi->max_speed_hz = 2000000; | ||
| 198 | spi->mode = SPI_MODE_3; | ||
| 199 | spi->bits_per_word = 8; | ||
| 200 | spi_setup(spi); | ||
| 201 | ad9951_init(st); | ||
| 202 | return 0; | ||
| 203 | |||
| 204 | error_free_dev: | ||
| 205 | iio_free_device(idev); | ||
| 206 | |||
| 207 | error_ret: | ||
| 208 | return ret; | ||
| 209 | } | ||
| 210 | |||
| 211 | static int __devexit ad9951_remove(struct spi_device *spi) | ||
| 212 | { | ||
| 213 | iio_device_unregister(spi_get_drvdata(spi)); | ||
| 214 | |||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | |||
| 218 | static struct spi_driver ad9951_driver = { | ||
| 219 | .driver = { | ||
| 220 | .name = DRV_NAME, | ||
| 221 | .owner = THIS_MODULE, | ||
| 222 | }, | ||
| 223 | .probe = ad9951_probe, | ||
| 224 | .remove = __devexit_p(ad9951_remove), | ||
| 225 | }; | ||
| 226 | |||
| 227 | static __init int ad9951_spi_init(void) | ||
| 228 | { | ||
| 229 | return spi_register_driver(&ad9951_driver); | ||
| 230 | } | ||
| 231 | module_init(ad9951_spi_init); | ||
| 232 | |||
| 233 | static __exit void ad9951_spi_exit(void) | ||
| 234 | { | ||
| 235 | spi_unregister_driver(&ad9951_driver); | ||
| 236 | } | ||
| 237 | module_exit(ad9951_spi_exit); | ||
| 238 | |||
| 239 | MODULE_AUTHOR("Cliff Cai"); | ||
| 240 | MODULE_DESCRIPTION("Analog Devices ad9951 driver"); | ||
| 241 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/dds/dds.h b/drivers/staging/iio/dds/dds.h new file mode 100644 index 00000000000..d8ac3a93baf --- /dev/null +++ b/drivers/staging/iio/dds/dds.h | |||
| @@ -0,0 +1,110 @@ | |||
| 1 | /* | ||
| 2 | * dds.h - sysfs attributes associated with DDS devices | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | /** | ||
| 10 | * /sys/bus/iio/devices/.../ddsX_freqY | ||
| 11 | */ | ||
| 12 | |||
| 13 | #define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr) \ | ||
| 14 | IIO_DEVICE_ATTR(dds##_channel##_freq##_num, \ | ||
| 15 | _mode, _show, _store, _addr) | ||
| 16 | |||
| 17 | /** | ||
| 18 | * /sys/bus/iio/devices/.../ddsX_freqY_scale | ||
| 19 | */ | ||
| 20 | |||
| 21 | #define IIO_CONST_ATTR_FREQ_SCALE(_channel, _string) \ | ||
| 22 | IIO_CONST_ATTR(dds##_channel##_freq_scale, _string) | ||
| 23 | |||
| 24 | /** | ||
| 25 | * /sys/bus/iio/devices/.../ddsX_freqsymbol | ||
| 26 | */ | ||
| 27 | |||
| 28 | #define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr) \ | ||
| 29 | IIO_DEVICE_ATTR(dds##_channel##_freqsymbol, \ | ||
| 30 | _mode, _show, _store, _addr); | ||
| 31 | |||
| 32 | /** | ||
| 33 | * /sys/bus/iio/devices/.../ddsX_phaseY | ||
| 34 | */ | ||
| 35 | |||
| 36 | #define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr) \ | ||
| 37 | IIO_DEVICE_ATTR(dds##_channel##_phase##_num, \ | ||
| 38 | _mode, _show, _store, _addr) | ||
| 39 | |||
| 40 | /** | ||
| 41 | * /sys/bus/iio/devices/.../ddsX_phaseY_scale | ||
| 42 | */ | ||
| 43 | |||
| 44 | #define IIO_CONST_ATTR_PHASE_SCALE(_channel, _string) \ | ||
| 45 | IIO_CONST_ATTR(dds##_channel##_phase_scale, _string) | ||
| 46 | |||
| 47 | /** | ||
| 48 | * /sys/bus/iio/devices/.../ddsX_phasesymbol | ||
| 49 | */ | ||
| 50 | |||
| 51 | #define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr) \ | ||
| 52 | IIO_DEVICE_ATTR(dds##_channel##_phasesymbol, \ | ||
| 53 | _mode, _show, _store, _addr); | ||
| 54 | |||
| 55 | /** | ||
| 56 | * /sys/bus/iio/devices/.../ddsX_pincontrol_en | ||
| 57 | */ | ||
| 58 | |||
| 59 | #define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\ | ||
| 60 | IIO_DEVICE_ATTR(dds##_channel##_pincontrol_en, \ | ||
| 61 | _mode, _show, _store, _addr); | ||
| 62 | |||
| 63 | /** | ||
| 64 | * /sys/bus/iio/devices/.../ddsX_pincontrol_freq_en | ||
| 65 | */ | ||
| 66 | |||
| 67 | #define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\ | ||
| 68 | IIO_DEVICE_ATTR(dds##_channel##_pincontrol_freq_en, \ | ||
| 69 | _mode, _show, _store, _addr); | ||
| 70 | |||
| 71 | /** | ||
| 72 | * /sys/bus/iio/devices/.../ddsX_pincontrol_phase_en | ||
| 73 | */ | ||
| 74 | |||
| 75 | #define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\ | ||
| 76 | IIO_DEVICE_ATTR(dds##_channel##_pincontrol_phase_en, \ | ||
| 77 | _mode, _show, _store, _addr); | ||
| 78 | |||
| 79 | /** | ||
| 80 | * /sys/bus/iio/devices/.../ddsX_out_enable | ||
| 81 | */ | ||
| 82 | |||
| 83 | #define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr) \ | ||
| 84 | IIO_DEVICE_ATTR(dds##_channel##_out_enable, \ | ||
| 85 | _mode, _show, _store, _addr); | ||
| 86 | |||
| 87 | /** | ||
| 88 | * /sys/bus/iio/devices/.../ddsX_outY_enable | ||
| 89 | */ | ||
| 90 | |||
| 91 | #define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output, \ | ||
| 92 | _mode, _show, _store, _addr) \ | ||
| 93 | IIO_DEVICE_ATTR(dds##_channel##_out##_output##_enable, \ | ||
| 94 | _mode, _show, _store, _addr); | ||
| 95 | |||
| 96 | /** | ||
| 97 | * /sys/bus/iio/devices/.../ddsX_outY_wavetype | ||
| 98 | */ | ||
| 99 | |||
| 100 | #define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr) \ | ||
| 101 | IIO_DEVICE_ATTR(dds##_channel##_out##_output##_wavetype, \ | ||
| 102 | S_IWUSR, NULL, _store, _addr); | ||
| 103 | |||
| 104 | /** | ||
| 105 | * /sys/bus/iio/devices/.../ddsX_outY_wavetype_available | ||
| 106 | */ | ||
| 107 | |||
| 108 | #define IIO_CONST_ATTR_OUT_WAVETYPES_AVAILABLE(_channel, _output, _modes)\ | ||
| 109 | IIO_CONST_ATTR(dds##_channel##_out##_output##_wavetype_available,\ | ||
| 110 | _modes); | ||
diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c new file mode 100644 index 00000000000..a4df8b32251 --- /dev/null +++ b/drivers/staging/iio/gyro/adis16260_ring.c | |||
| @@ -0,0 +1,155 @@ | |||
| 1 | #include <linux/interrupt.h> | ||
| 2 | #include <linux/irq.h> | ||
| 3 | #include <linux/gpio.h> | ||
| 4 | #include <linux/workqueue.h> | ||
| 5 | #include <linux/mutex.h> | ||
| 6 | #include <linux/device.h> | ||
| 7 | #include <linux/kernel.h> | ||
| 8 | #include <linux/spi/spi.h> | ||
| 9 | #include <linux/slab.h> | ||
| 10 | #include <linux/sysfs.h> | ||
| 11 | #include <linux/list.h> | ||
| 12 | |||
| 13 | #include "../iio.h" | ||
| 14 | #include "../sysfs.h" | ||
| 15 | #include "../ring_sw.h" | ||
| 16 | #include "../accel/accel.h" | ||
| 17 | #include "../trigger.h" | ||
| 18 | #include "adis16260.h" | ||
| 19 | |||
| 20 | /** | ||
| 21 | * adis16260_read_ring_data() read data registers which will be placed into ring | ||
| 22 | * @dev: device associated with child of actual device (iio_dev or iio_trig) | ||
| 23 | * @rx: somewhere to pass back the value read | ||
| 24 | **/ | ||
| 25 | static int adis16260_read_ring_data(struct device *dev, u8 *rx) | ||
| 26 | { | ||
| 27 | struct spi_message msg; | ||
| 28 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 29 | struct adis16260_state *st = iio_priv(indio_dev); | ||
| 30 | struct spi_transfer xfers[ADIS16260_OUTPUTS + 1]; | ||
| 31 | int ret; | ||
| 32 | int i; | ||
| 33 | |||
| 34 | mutex_lock(&st->buf_lock); | ||
| 35 | |||
| 36 | spi_message_init(&msg); | ||
| 37 | |||
| 38 | memset(xfers, 0, sizeof(xfers)); | ||
| 39 | for (i = 0; i <= ADIS16260_OUTPUTS; i++) { | ||
| 40 | xfers[i].bits_per_word = 8; | ||
| 41 | xfers[i].cs_change = 1; | ||
| 42 | xfers[i].len = 2; | ||
| 43 | xfers[i].delay_usecs = 30; | ||
| 44 | xfers[i].tx_buf = st->tx + 2 * i; | ||
| 45 | if (i < 2) /* SUPPLY_OUT:0x02 GYRO_OUT:0x04 */ | ||
| 46 | st->tx[2 * i] | ||
| 47 | = ADIS16260_READ_REG(ADIS16260_SUPPLY_OUT | ||
| 48 | + 2 * i); | ||
| 49 | else /* 0x06 to 0x09 is reserved */ | ||
| 50 | st->tx[2 * i] | ||
| 51 | = ADIS16260_READ_REG(ADIS16260_SUPPLY_OUT | ||
| 52 | + 2 * i + 4); | ||
| 53 | st->tx[2 * i + 1] = 0; | ||
| 54 | if (i >= 1) | ||
| 55 | xfers[i].rx_buf = rx + 2 * (i - 1); | ||
| 56 | spi_message_add_tail(&xfers[i], &msg); | ||
| 57 | } | ||
| 58 | |||
| 59 | ret = spi_sync(st->us, &msg); | ||
| 60 | if (ret) | ||
| 61 | dev_err(&st->us->dev, "problem when burst reading"); | ||
| 62 | |||
| 63 | mutex_unlock(&st->buf_lock); | ||
| 64 | |||
| 65 | return ret; | ||
| 66 | } | ||
| 67 | |||
| 68 | static irqreturn_t adis16260_trigger_handler(int irq, void *p) | ||
| 69 | { | ||
| 70 | struct iio_poll_func *pf = p; | ||
| 71 | struct iio_dev *indio_dev = pf->private_data; | ||
| 72 | struct adis16260_state *st = iio_priv(indio_dev); | ||
| 73 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 74 | int i = 0; | ||
| 75 | s16 *data; | ||
| 76 | size_t datasize = ring->access->get_bytes_per_datum(ring); | ||
| 77 | |||
| 78 | data = kmalloc(datasize , GFP_KERNEL); | ||
| 79 | if (data == NULL) { | ||
| 80 | dev_err(&st->us->dev, "memory alloc failed in ring bh"); | ||
| 81 | return -ENOMEM; | ||
| 82 | } | ||
| 83 | |||
| 84 | if (ring->scan_count && | ||
| 85 | adis16260_read_ring_data(&indio_dev->dev, st->rx) >= 0) | ||
| 86 | for (; i < ring->scan_count; i++) | ||
| 87 | data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2])); | ||
| 88 | |||
| 89 | /* Guaranteed to be aligned with 8 byte boundary */ | ||
| 90 | if (ring->scan_timestamp) | ||
| 91 | *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; | ||
| 92 | |||
| 93 | ring->access->store_to(ring, (u8 *)data, pf->timestamp); | ||
| 94 | |||
| 95 | iio_trigger_notify_done(indio_dev->trig); | ||
| 96 | kfree(data); | ||
| 97 | |||
| 98 | return IRQ_HANDLED; | ||
| 99 | } | ||
| 100 | |||
| 101 | void adis16260_unconfigure_ring(struct iio_dev *indio_dev) | ||
| 102 | { | ||
| 103 | iio_dealloc_pollfunc(indio_dev->pollfunc); | ||
| 104 | iio_sw_rb_free(indio_dev->ring); | ||
| 105 | } | ||
| 106 | |||
| 107 | static const struct iio_ring_setup_ops adis16260_ring_setup_ops = { | ||
| 108 | .preenable = &iio_sw_ring_preenable, | ||
| 109 | .postenable = &iio_triggered_ring_postenable, | ||
| 110 | .predisable = &iio_triggered_ring_predisable, | ||
| 111 | }; | ||
| 112 | |||
| 113 | int adis16260_configure_ring(struct iio_dev *indio_dev) | ||
| 114 | { | ||
| 115 | int ret = 0; | ||
| 116 | struct iio_ring_buffer *ring; | ||
| 117 | |||
| 118 | ring = iio_sw_rb_allocate(indio_dev); | ||
| 119 | if (!ring) { | ||
| 120 | ret = -ENOMEM; | ||
| 121 | return ret; | ||
| 122 | } | ||
| 123 | indio_dev->ring = ring; | ||
| 124 | /* Effectively select the ring buffer implementation */ | ||
| 125 | ring->access = &ring_sw_access_funcs; | ||
| 126 | ring->bpe = 2; | ||
| 127 | ring->scan_timestamp = true; | ||
| 128 | ring->setup_ops = &adis16260_ring_setup_ops; | ||
| 129 | ring->owner = THIS_MODULE; | ||
| 130 | |||
| 131 | /* Set default scan mode */ | ||
| 132 | iio_scan_mask_set(ring, ADIS16260_SCAN_SUPPLY); | ||
| 133 | iio_scan_mask_set(ring, ADIS16260_SCAN_GYRO); | ||
| 134 | iio_scan_mask_set(ring, ADIS16260_SCAN_AUX_ADC); | ||
| 135 | iio_scan_mask_set(ring, ADIS16260_SCAN_TEMP); | ||
| 136 | iio_scan_mask_set(ring, ADIS16260_SCAN_ANGL); | ||
| 137 | |||
| 138 | indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, | ||
| 139 | &adis16260_trigger_handler, | ||
| 140 | IRQF_ONESHOT, | ||
| 141 | indio_dev, | ||
| 142 | "adis16260_consumer%d", | ||
| 143 | indio_dev->id); | ||
| 144 | if (indio_dev->pollfunc == NULL) { | ||
| 145 | ret = -ENOMEM; | ||
| 146 | goto error_iio_sw_rb_free; | ||
| 147 | } | ||
| 148 | |||
| 149 | indio_dev->modes |= INDIO_RING_TRIGGERED; | ||
| 150 | return 0; | ||
| 151 | |||
| 152 | error_iio_sw_rb_free: | ||
| 153 | iio_sw_rb_free(indio_dev->ring); | ||
| 154 | return ret; | ||
| 155 | } | ||
diff --git a/drivers/staging/iio/gyro/adis16260_trigger.c b/drivers/staging/iio/gyro/adis16260_trigger.c new file mode 100644 index 00000000000..01094d0e714 --- /dev/null +++ b/drivers/staging/iio/gyro/adis16260_trigger.c | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | #include <linux/interrupt.h> | ||
| 2 | #include <linux/irq.h> | ||
| 3 | #include <linux/mutex.h> | ||
| 4 | #include <linux/device.h> | ||
| 5 | #include <linux/kernel.h> | ||
| 6 | #include <linux/sysfs.h> | ||
| 7 | #include <linux/list.h> | ||
| 8 | #include <linux/spi/spi.h> | ||
| 9 | |||
| 10 | #include "../iio.h" | ||
| 11 | #include "../sysfs.h" | ||
| 12 | #include "../trigger.h" | ||
| 13 | #include "adis16260.h" | ||
| 14 | |||
| 15 | /** | ||
| 16 | * adis16260_data_rdy_trigger_set_state() set datardy interrupt state | ||
| 17 | **/ | ||
| 18 | static int adis16260_data_rdy_trigger_set_state(struct iio_trigger *trig, | ||
| 19 | bool state) | ||
| 20 | { | ||
| 21 | struct iio_dev *indio_dev = trig->private_data; | ||
| 22 | |||
| 23 | dev_dbg(&indio_dev->dev, "%s (%d)\n", __func__, state); | ||
| 24 | return adis16260_set_irq(indio_dev, state); | ||
| 25 | } | ||
| 26 | |||
| 27 | int adis16260_probe_trigger(struct iio_dev *indio_dev) | ||
| 28 | { | ||
| 29 | int ret; | ||
| 30 | struct adis16260_state *st = iio_priv(indio_dev); | ||
| 31 | |||
| 32 | st->trig = iio_allocate_trigger("%s-dev%d", | ||
| 33 | spi_get_device_id(st->us)->name, | ||
| 34 | indio_dev->id); | ||
| 35 | if (st->trig == NULL) { | ||
| 36 | ret = -ENOMEM; | ||
| 37 | goto error_ret; | ||
| 38 | } | ||
| 39 | |||
| 40 | ret = request_irq(st->us->irq, | ||
| 41 | &iio_trigger_generic_data_rdy_poll, | ||
| 42 | IRQF_TRIGGER_RISING, | ||
| 43 | "adis16260", | ||
| 44 | st->trig); | ||
| 45 | if (ret) | ||
| 46 | goto error_free_trig; | ||
| 47 | |||
| 48 | st->trig->dev.parent = &st->us->dev; | ||
| 49 | st->trig->owner = THIS_MODULE; | ||
| 50 | st->trig->private_data = indio_dev; | ||
| 51 | st->trig->set_trigger_state = &adis16260_data_rdy_trigger_set_state; | ||
| 52 | ret = iio_trigger_register(st->trig); | ||
| 53 | |||
| 54 | /* select default trigger */ | ||
| 55 | indio_dev->trig = st->trig; | ||
| 56 | if (ret) | ||
| 57 | goto error_free_irq; | ||
| 58 | |||
| 59 | return 0; | ||
| 60 | |||
| 61 | error_free_irq: | ||
| 62 | free_irq(st->us->irq, st->trig); | ||
| 63 | error_free_trig: | ||
| 64 | iio_free_trigger(st->trig); | ||
| 65 | error_ret: | ||
| 66 | return ret; | ||
| 67 | } | ||
| 68 | |||
| 69 | void adis16260_remove_trigger(struct iio_dev *indio_dev) | ||
| 70 | { | ||
| 71 | struct adis16260_state *st = iio_priv(indio_dev); | ||
| 72 | |||
| 73 | iio_trigger_unregister(st->trig); | ||
| 74 | free_irq(st->us->irq, st->trig); | ||
| 75 | iio_free_trigger(st->trig); | ||
| 76 | } | ||
diff --git a/drivers/staging/iio/gyro/gyro.h b/drivers/staging/iio/gyro/gyro.h new file mode 100644 index 00000000000..b5495613407 --- /dev/null +++ b/drivers/staging/iio/gyro/gyro.h | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | |||
| 2 | #include "../sysfs.h" | ||
| 3 | |||
| 4 | /* Gyroscope types of attribute */ | ||
| 5 | |||
| 6 | #define IIO_CONST_ATTR_GYRO_OFFSET(_string) \ | ||
| 7 | IIO_CONST_ATTR(gyro_offset, _string) | ||
| 8 | |||
| 9 | #define IIO_DEV_ATTR_GYRO_OFFSET(_mode, _show, _store, _addr) \ | ||
| 10 | IIO_DEVICE_ATTR(gyro_offset, _mode, _show, _store, _addr) | ||
| 11 | |||
| 12 | #define IIO_DEV_ATTR_GYRO_X_OFFSET(_mode, _show, _store, _addr) \ | ||
| 13 | IIO_DEVICE_ATTR(gyro_x_offset, _mode, _show, _store, _addr) | ||
| 14 | |||
| 15 | #define IIO_DEV_ATTR_GYRO_Y_OFFSET(_mode, _show, _store, _addr) \ | ||
| 16 | IIO_DEVICE_ATTR(gyro_y_offset, _mode, _show, _store, _addr) | ||
| 17 | |||
| 18 | #define IIO_DEV_ATTR_GYRO_Z_OFFSET(_mode, _show, _store, _addr) \ | ||
| 19 | IIO_DEVICE_ATTR(gyro_z_offset, _mode, _show, _store, _addr) | ||
| 20 | |||
| 21 | #define IIO_CONST_ATTR_GYRO_SCALE(_string) \ | ||
| 22 | IIO_CONST_ATTR(gyro_scale, _string) | ||
| 23 | |||
| 24 | #define IIO_DEV_ATTR_GYRO_SCALE(_mode, _show, _store, _addr) \ | ||
| 25 | IIO_DEVICE_ATTR(gyro_scale, S_IRUGO, _show, _store, _addr) | ||
| 26 | |||
| 27 | #define IIO_DEV_ATTR_GYRO_X_SCALE(_mode, _show, _store, _addr) \ | ||
| 28 | IIO_DEVICE_ATTR(gyro_x_scale, _mode, _show, _store, _addr) | ||
| 29 | |||
| 30 | #define IIO_DEV_ATTR_GYRO_Y_SCALE(_mode, _show, _store, _addr) \ | ||
| 31 | IIO_DEVICE_ATTR(gyro_y_scale, _mode, _show, _store, _addr) | ||
| 32 | |||
| 33 | #define IIO_DEV_ATTR_GYRO_Z_SCALE(_mode, _show, _store, _addr) \ | ||
| 34 | IIO_DEVICE_ATTR(gyro_z_scale, _mode, _show, _store, _addr) | ||
| 35 | |||
| 36 | #define IIO_DEV_ATTR_GYRO_CALIBBIAS(_mode, _show, _store, _addr) \ | ||
| 37 | IIO_DEVICE_ATTR(gyro_calibbias, S_IRUGO, _show, _store, _addr) | ||
| 38 | |||
| 39 | #define IIO_DEV_ATTR_GYRO_X_CALIBBIAS(_mode, _show, _store, _addr) \ | ||
| 40 | IIO_DEVICE_ATTR(gyro_x_calibbias, _mode, _show, _store, _addr) | ||
| 41 | |||
| 42 | #define IIO_DEV_ATTR_GYRO_Y_CALIBBIAS(_mode, _show, _store, _addr) \ | ||
| 43 | IIO_DEVICE_ATTR(gyro_y_calibbias, _mode, _show, _store, _addr) | ||
| 44 | |||
| 45 | #define IIO_DEV_ATTR_GYRO_Z_CALIBBIAS(_mode, _show, _store, _addr) \ | ||
| 46 | IIO_DEVICE_ATTR(gyro_z_calibbias, _mode, _show, _store, _addr) | ||
| 47 | |||
| 48 | #define IIO_DEV_ATTR_GYRO_CALIBSCALE(_mode, _show, _store, _addr) \ | ||
| 49 | IIO_DEVICE_ATTR(gyro_calibscale, S_IRUGO, _show, _store, _addr) | ||
| 50 | |||
| 51 | #define IIO_DEV_ATTR_GYRO_X_CALIBSCALE(_mode, _show, _store, _addr) \ | ||
| 52 | IIO_DEVICE_ATTR(gyro_x_calibscale, _mode, _show, _store, _addr) | ||
| 53 | |||
| 54 | #define IIO_DEV_ATTR_GYRO_Y_CALIBSCALE(_mode, _show, _store, _addr) \ | ||
| 55 | IIO_DEVICE_ATTR(gyro_y_calibscale, _mode, _show, _store, _addr) | ||
| 56 | |||
| 57 | #define IIO_DEV_ATTR_GYRO_Z_CALIBSCALE(_mode, _show, _store, _addr) \ | ||
| 58 | IIO_DEVICE_ATTR(gyro_z_calibscale, _mode, _show, _store, _addr) | ||
| 59 | |||
| 60 | #define IIO_DEV_ATTR_GYRO_Z_QUADRATURE_CORRECTION(_show, _addr) \ | ||
| 61 | IIO_DEVICE_ATTR(gyro_z_quadrature_correction_raw, S_IRUGO, _show, NULL, _addr) | ||
| 62 | |||
| 63 | #define IIO_DEV_ATTR_GYRO(_show, _addr) \ | ||
| 64 | IIO_DEVICE_ATTR(gyro_raw, S_IRUGO, _show, NULL, _addr) | ||
| 65 | |||
| 66 | #define IIO_DEV_ATTR_GYRO_X(_show, _addr) \ | ||
| 67 | IIO_DEVICE_ATTR(gyro_x_raw, S_IRUGO, _show, NULL, _addr) | ||
| 68 | |||
| 69 | #define IIO_DEV_ATTR_GYRO_Y(_show, _addr) \ | ||
| 70 | IIO_DEVICE_ATTR(gyro_y_raw, S_IRUGO, _show, NULL, _addr) | ||
| 71 | |||
| 72 | #define IIO_DEV_ATTR_GYRO_Z(_show, _addr) \ | ||
| 73 | IIO_DEVICE_ATTR(gyro_z_raw, S_IRUGO, _show, NULL, _addr) | ||
| 74 | |||
| 75 | #define IIO_DEV_ATTR_ANGL(_show, _addr) \ | ||
| 76 | IIO_DEVICE_ATTR(angl_raw, S_IRUGO, _show, NULL, _addr) | ||
| 77 | |||
| 78 | #define IIO_DEV_ATTR_ANGL_X(_show, _addr) \ | ||
| 79 | IIO_DEVICE_ATTR(angl_x_raw, S_IRUGO, _show, NULL, _addr) | ||
| 80 | |||
| 81 | #define IIO_DEV_ATTR_ANGL_Y(_show, _addr) \ | ||
| 82 | IIO_DEVICE_ATTR(angl_y_raw, S_IRUGO, _show, NULL, _addr) | ||
| 83 | |||
| 84 | #define IIO_DEV_ATTR_ANGL_Z(_show, _addr) \ | ||
| 85 | IIO_DEVICE_ATTR(angl_z_raw, S_IRUGO, _show, NULL, _addr) | ||
diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h new file mode 100644 index 00000000000..7a6ce4d0fb7 --- /dev/null +++ b/drivers/staging/iio/iio.h | |||
| @@ -0,0 +1,439 @@ | |||
| 1 | /* The industrial I/O core | ||
| 2 | * | ||
| 3 | * Copyright (c) 2008 Jonathan Cameron | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 as published by | ||
| 7 | * the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef _INDUSTRIAL_IO_H_ | ||
| 11 | #define _INDUSTRIAL_IO_H_ | ||
| 12 | |||
| 13 | #include <linux/device.h> | ||
| 14 | #include <linux/cdev.h> | ||
| 15 | #include <linux/irq.h> | ||
| 16 | #include "sysfs.h" | ||
| 17 | #include "chrdev.h" | ||
| 18 | |||
| 19 | /* IIO TODO LIST */ | ||
| 20 | /* | ||
| 21 | * Provide means of adjusting timer accuracy. | ||
| 22 | * Currently assumes nano seconds. | ||
| 23 | */ | ||
| 24 | |||
| 25 | /* Event interface flags */ | ||
| 26 | #define IIO_BUSY_BIT_POS 1 | ||
| 27 | |||
| 28 | /* naughty temporary hack to match these against the event version | ||
| 29 | - need to flattern these together */ | ||
| 30 | enum iio_chan_type { | ||
| 31 | /* real channel types */ | ||
| 32 | IIO_IN, | ||
| 33 | IIO_OUT, | ||
| 34 | IIO_CURRENT, | ||
| 35 | IIO_POWER, | ||
| 36 | IIO_ACCEL, | ||
| 37 | IIO_IN_DIFF, | ||
| 38 | IIO_GYRO, | ||
| 39 | IIO_MAGN, | ||
| 40 | IIO_LIGHT, | ||
| 41 | IIO_INTENSITY, | ||
| 42 | IIO_PROXIMITY, | ||
| 43 | IIO_TEMP, | ||
| 44 | IIO_INCLI, | ||
| 45 | IIO_ROT, | ||
| 46 | IIO_ANGL, | ||
| 47 | IIO_TIMESTAMP, | ||
| 48 | }; | ||
| 49 | |||
| 50 | #define IIO_MOD_X 0 | ||
| 51 | #define IIO_MOD_LIGHT_BOTH 0 | ||
| 52 | #define IIO_MOD_Y 1 | ||
| 53 | #define IIO_MOD_LIGHT_IR 1 | ||
| 54 | #define IIO_MOD_Z 2 | ||
| 55 | #define IIO_MOD_X_AND_Y 3 | ||
| 56 | #define IIO_MOD_X_ANX_Z 4 | ||
| 57 | #define IIO_MOD_Y_AND_Z 5 | ||
| 58 | #define IIO_MOD_X_AND_Y_AND_Z 6 | ||
| 59 | #define IIO_MOD_X_OR_Y 7 | ||
| 60 | #define IIO_MOD_X_OR_Z 8 | ||
| 61 | #define IIO_MOD_Y_OR_Z 9 | ||
| 62 | #define IIO_MOD_X_OR_Y_OR_Z 10 | ||
| 63 | |||
| 64 | /* Could add the raw attributes as well - allowing buffer only devices */ | ||
| 65 | enum iio_chan_info_enum { | ||
| 66 | IIO_CHAN_INFO_SCALE_SHARED, | ||
| 67 | IIO_CHAN_INFO_SCALE_SEPARATE, | ||
| 68 | IIO_CHAN_INFO_OFFSET_SHARED, | ||
| 69 | IIO_CHAN_INFO_OFFSET_SEPARATE, | ||
| 70 | IIO_CHAN_INFO_CALIBSCALE_SHARED, | ||
| 71 | IIO_CHAN_INFO_CALIBSCALE_SEPARATE, | ||
| 72 | IIO_CHAN_INFO_CALIBBIAS_SHARED, | ||
| 73 | IIO_CHAN_INFO_CALIBBIAS_SEPARATE, | ||
| 74 | IIO_CHAN_INFO_PEAK_SHARED, | ||
| 75 | IIO_CHAN_INFO_PEAK_SEPARATE, | ||
| 76 | IIO_CHAN_INFO_PEAK_SCALE_SHARED, | ||
| 77 | IIO_CHAN_INFO_PEAK_SCALE_SEPARATE, | ||
| 78 | }; | ||
| 79 | |||
| 80 | /** | ||
| 81 | * struct iio_chan_spec - specification of a single channel | ||
| 82 | * @type: What type of measurement is the channel making. | ||
| 83 | * @channel: What number or name do we wish to asign the channel. | ||
| 84 | * @channel2: If there is a second number for a differential | ||
| 85 | * channel then this is it. If modified is set then the | ||
| 86 | * value here specifies the modifier. | ||
| 87 | * @address: Driver specific identifier. | ||
| 88 | * @scan_index: Monotonic index to give ordering in scans when read | ||
| 89 | * from a buffer. | ||
| 90 | * @scan_type: Sign: 's' or 'u' to specify signed or unsigned | ||
| 91 | * realbits: Number of valid bits of data | ||
| 92 | * storage_bits: Realbits + padding | ||
| 93 | * shift: Shift right by this before masking out | ||
| 94 | * realbits. | ||
| 95 | * @info_mask: What information is to be exported about this channel. | ||
| 96 | * This includes calibbias, scale etc. | ||
| 97 | * @event_mask: What events can this channel produce. | ||
| 98 | * @extend_name: Allows labeling of channel attributes with an | ||
| 99 | * informative name. Note this has no effect codes etc, | ||
| 100 | * unlike modifiers. | ||
| 101 | * @processed_val: Flag to specify the data access attribute should be | ||
| 102 | * *_input rather than *_raw. | ||
| 103 | * @modified: Does a modifier apply to this channel. What these are | ||
| 104 | * depends on the channel type. Modifier is set in | ||
| 105 | * channel2. Examples are IIO_MOD_X for axial sensors about | ||
| 106 | * the 'x' axis. | ||
| 107 | * @indexed: Specify the channel has a numerical index. If not, | ||
| 108 | * the value in channel will be suppressed for attribute | ||
| 109 | * but not for event codes. Typically set it to 0 when | ||
| 110 | * the index is false. | ||
| 111 | */ | ||
| 112 | struct iio_chan_spec { | ||
| 113 | enum iio_chan_type type; | ||
| 114 | int channel; | ||
| 115 | int channel2; | ||
| 116 | unsigned long address; | ||
| 117 | int scan_index; | ||
| 118 | struct { | ||
| 119 | char sign; | ||
| 120 | u8 realbits; | ||
| 121 | u8 storagebits; | ||
| 122 | u8 shift; | ||
| 123 | } scan_type; | ||
| 124 | const long info_mask; | ||
| 125 | const long event_mask; | ||
| 126 | const char *extend_name; | ||
| 127 | unsigned processed_val:1; | ||
| 128 | unsigned modified:1; | ||
| 129 | unsigned indexed:1; | ||
| 130 | }; | ||
| 131 | /* Meant for internal use only */ | ||
| 132 | void __iio_device_attr_deinit(struct device_attribute *dev_attr); | ||
| 133 | int __iio_device_attr_init(struct device_attribute *dev_attr, | ||
| 134 | const char *postfix, | ||
| 135 | struct iio_chan_spec const *chan, | ||
| 136 | ssize_t (*readfunc)(struct device *dev, | ||
| 137 | struct device_attribute *attr, | ||
| 138 | char *buf), | ||
| 139 | ssize_t (*writefunc)(struct device *dev, | ||
| 140 | struct device_attribute *attr, | ||
| 141 | const char *buf, | ||
| 142 | size_t len), | ||
| 143 | bool generic); | ||
| 144 | #define IIO_ST(si, rb, sb, sh) \ | ||
| 145 | { .sign = si, .realbits = rb, .storagebits = sb, .shift = sh } | ||
| 146 | |||
| 147 | #define IIO_CHAN(_type, _mod, _indexed, _proc, _name, _chan, _chan2, \ | ||
| 148 | _inf_mask, _address, _si, _stype, _event_mask) \ | ||
| 149 | { .type = _type, \ | ||
| 150 | .modified = _mod, \ | ||
| 151 | .indexed = _indexed, \ | ||
| 152 | .processed_val = _proc, \ | ||
| 153 | .extend_name = _name, \ | ||
| 154 | .channel = _chan, \ | ||
| 155 | .channel2 = _chan2, \ | ||
| 156 | .info_mask = _inf_mask, \ | ||
| 157 | .address = _address, \ | ||
| 158 | .scan_index = _si, \ | ||
| 159 | .scan_type = _stype, \ | ||
| 160 | .event_mask = _event_mask } | ||
| 161 | |||
| 162 | #define IIO_CHAN_SOFT_TIMESTAMP(_si) \ | ||
| 163 | { .type = IIO_TIMESTAMP, .channel = -1, \ | ||
| 164 | .scan_index = _si, .scan_type = IIO_ST('s', 64, 64, 0) } | ||
| 165 | |||
| 166 | int __iio_add_chan_devattr(const char *postfix, | ||
| 167 | const char *group, | ||
| 168 | struct iio_chan_spec const *chan, | ||
| 169 | ssize_t (*func)(struct device *dev, | ||
| 170 | struct device_attribute *attr, | ||
| 171 | char *buf), | ||
| 172 | ssize_t (*writefunc)(struct device *dev, | ||
| 173 | struct device_attribute *attr, | ||
| 174 | const char *buf, | ||
| 175 | size_t len), | ||
| 176 | int mask, | ||
| 177 | bool generic, | ||
| 178 | struct device *dev, | ||
| 179 | struct list_head *attr_list); | ||
| 180 | /** | ||
| 181 | * iio_get_time_ns() - utility function to get a time stamp for events etc | ||
| 182 | **/ | ||
| 183 | static inline s64 iio_get_time_ns(void) | ||
| 184 | { | ||
| 185 | struct timespec ts; | ||
| 186 | /* | ||
| 187 | * calls getnstimeofday. | ||
| 188 | * If hrtimers then up to ns accurate, if not microsecond. | ||
| 189 | */ | ||
| 190 | ktime_get_real_ts(&ts); | ||
| 191 | |||
| 192 | return timespec_to_ns(&ts); | ||
| 193 | } | ||
| 194 | |||
| 195 | /* Device operating modes */ | ||
| 196 | #define INDIO_DIRECT_MODE 0x01 | ||
| 197 | #define INDIO_RING_TRIGGERED 0x02 | ||
| 198 | #define INDIO_RING_HARDWARE_BUFFER 0x08 | ||
| 199 | |||
| 200 | #define INDIO_ALL_RING_MODES (INDIO_RING_TRIGGERED | INDIO_RING_HARDWARE_BUFFER) | ||
| 201 | |||
| 202 | /* Vast majority of this is set by the industrialio subsystem on a | ||
| 203 | * call to iio_device_register. */ | ||
| 204 | #define IIO_VAL_INT 1 | ||
| 205 | #define IIO_VAL_INT_PLUS_MICRO 2 | ||
| 206 | #define IIO_VAL_INT_PLUS_NANO 3 | ||
| 207 | |||
| 208 | struct iio_trigger; /* forward declaration */ | ||
| 209 | |||
| 210 | /** | ||
| 211 | * struct iio_info - constant information about device | ||
| 212 | * @driver_module: module structure used to ensure correct | ||
| 213 | * ownership of chrdevs etc | ||
| 214 | * @num_interrupt_lines:number of physical interrupt lines from device | ||
| 215 | * @event_attrs: event control attributes | ||
| 216 | * @attrs: general purpose device attributes | ||
| 217 | * @read_raw: function to request a value from the device. | ||
| 218 | * mask specifies which value. Note 0 means a reading of | ||
| 219 | * the channel in question. Return value will specify the | ||
| 220 | * type of value returned by the device. val and val2 will | ||
| 221 | * contain the elements making up the returned value. | ||
| 222 | * @write_raw: function to write a value to the device. | ||
| 223 | * Parameters are the same as for read_raw. | ||
| 224 | * @write_raw_get_fmt: callback function to query the expected | ||
| 225 | * format/precision. If not set by the driver, write_raw | ||
| 226 | * returns IIO_VAL_INT_PLUS_MICRO. | ||
| 227 | * @read_event_config: find out if the event is enabled. | ||
| 228 | * @write_event_config: set if the event is enabled. | ||
| 229 | * @read_event_value: read a value associated with the event. Meaning | ||
| 230 | * is event dependant. event_code specifies which event. | ||
| 231 | * @write_event_value: write the value associate with the event. | ||
| 232 | * Meaning is event dependent. | ||
| 233 | * @validate_trigger: function to validate the trigger when the | ||
| 234 | * current trigger gets changed. | ||
| 235 | **/ | ||
| 236 | struct iio_info { | ||
| 237 | struct module *driver_module; | ||
| 238 | int num_interrupt_lines; | ||
| 239 | struct attribute_group *event_attrs; | ||
| 240 | const struct attribute_group *attrs; | ||
| 241 | |||
| 242 | int (*read_raw)(struct iio_dev *indio_dev, | ||
| 243 | struct iio_chan_spec const *chan, | ||
| 244 | int *val, | ||
| 245 | int *val2, | ||
| 246 | long mask); | ||
| 247 | |||
| 248 | int (*write_raw)(struct iio_dev *indio_dev, | ||
| 249 | struct iio_chan_spec const *chan, | ||
| 250 | int val, | ||
| 251 | int val2, | ||
| 252 | long mask); | ||
| 253 | |||
| 254 | int (*write_raw_get_fmt)(struct iio_dev *indio_dev, | ||
| 255 | struct iio_chan_spec const *chan, | ||
| 256 | long mask); | ||
| 257 | |||
| 258 | int (*read_event_config)(struct iio_dev *indio_dev, | ||
| 259 | int event_code); | ||
| 260 | |||
| 261 | int (*write_event_config)(struct iio_dev *indio_dev, | ||
| 262 | int event_code, | ||
| 263 | int state); | ||
| 264 | |||
| 265 | int (*read_event_value)(struct iio_dev *indio_dev, | ||
| 266 | int event_code, | ||
| 267 | int *val); | ||
| 268 | int (*write_event_value)(struct iio_dev *indio_dev, | ||
| 269 | int event_code, | ||
| 270 | int val); | ||
| 271 | int (*validate_trigger)(struct iio_dev *indio_dev, | ||
| 272 | struct iio_trigger *trig); | ||
| 273 | |||
| 274 | }; | ||
| 275 | |||
| 276 | /** | ||
| 277 | * struct iio_dev - industrial I/O device | ||
| 278 | * @id: [INTERN] used to identify device internally | ||
| 279 | * @dev_data: [DRIVER] device specific data | ||
| 280 | * @modes: [DRIVER] operating modes supported by device | ||
| 281 | * @currentmode: [DRIVER] current operating mode | ||
| 282 | * @dev: [DRIVER] device structure, should be assigned a parent | ||
| 283 | * and owner | ||
| 284 | * @event_interfaces: [INTERN] event chrdevs associated with interrupt lines | ||
| 285 | * @ring: [DRIVER] any ring buffer present | ||
| 286 | * @mlock: [INTERN] lock used to prevent simultaneous device state | ||
| 287 | * changes | ||
| 288 | * @available_scan_masks: [DRIVER] optional array of allowed bitmasks | ||
| 289 | * @trig: [INTERN] current device trigger (ring buffer modes) | ||
| 290 | * @pollfunc: [DRIVER] function run on trigger being received | ||
| 291 | * @channels: [DRIVER] channel specification structure table | ||
| 292 | * @num_channels: [DRIVER] number of chanels specified in @channels. | ||
| 293 | * @channel_attr_list: [INTERN] keep track of automatically created channel | ||
| 294 | * attributes. | ||
| 295 | * @name: [DRIVER] name of the device. | ||
| 296 | **/ | ||
| 297 | struct iio_dev { | ||
| 298 | int id; | ||
| 299 | void *dev_data; | ||
| 300 | int modes; | ||
| 301 | int currentmode; | ||
| 302 | struct device dev; | ||
| 303 | |||
| 304 | struct iio_event_interface *event_interfaces; | ||
| 305 | |||
| 306 | struct iio_ring_buffer *ring; | ||
| 307 | struct mutex mlock; | ||
| 308 | |||
| 309 | u32 *available_scan_masks; | ||
| 310 | struct iio_trigger *trig; | ||
| 311 | struct iio_poll_func *pollfunc; | ||
| 312 | |||
| 313 | struct iio_chan_spec const *channels; | ||
| 314 | int num_channels; | ||
| 315 | |||
| 316 | struct list_head channel_attr_list; | ||
| 317 | const char *name; | ||
| 318 | const struct iio_info *info; | ||
| 319 | }; | ||
| 320 | |||
| 321 | /** | ||
| 322 | * iio_device_register() - register a device with the IIO subsystem | ||
| 323 | * @dev_info: Device structure filled by the device driver | ||
| 324 | **/ | ||
| 325 | int iio_device_register(struct iio_dev *dev_info); | ||
| 326 | |||
| 327 | /** | ||
| 328 | * iio_device_unregister() - unregister a device from the IIO subsystem | ||
| 329 | * @dev_info: Device structure representing the device. | ||
| 330 | **/ | ||
| 331 | void iio_device_unregister(struct iio_dev *dev_info); | ||
| 332 | |||
| 333 | /** | ||
| 334 | * iio_push_event() - try to add event to the list for userspace reading | ||
| 335 | * @dev_info: IIO device structure | ||
| 336 | * @ev_line: Which event line (hardware interrupt) | ||
| 337 | * @ev_code: What event | ||
| 338 | * @timestamp: When the event occurred | ||
| 339 | **/ | ||
| 340 | int iio_push_event(struct iio_dev *dev_info, | ||
| 341 | int ev_line, | ||
| 342 | int ev_code, | ||
| 343 | s64 timestamp); | ||
| 344 | |||
| 345 | /* Used to distinguish between bipolar and unipolar scan elemenents. | ||
| 346 | * Whilst this may seem obvious, we may well want to change the representation | ||
| 347 | * in the future!*/ | ||
| 348 | #define IIO_SIGNED(a) -(a) | ||
| 349 | #define IIO_UNSIGNED(a) (a) | ||
| 350 | |||
| 351 | extern dev_t iio_devt; | ||
| 352 | extern struct bus_type iio_bus_type; | ||
| 353 | |||
| 354 | /** | ||
| 355 | * iio_put_device() - reference counted deallocation of struct device | ||
| 356 | * @dev: the iio_device containing the device | ||
| 357 | **/ | ||
| 358 | static inline void iio_put_device(struct iio_dev *dev) | ||
| 359 | { | ||
| 360 | if (dev) | ||
| 361 | put_device(&dev->dev); | ||
| 362 | }; | ||
| 363 | |||
| 364 | /** | ||
| 365 | * to_iio_dev() - get iio_dev for which we have the struct device | ||
| 366 | * @d: the struct device | ||
| 367 | **/ | ||
| 368 | static inline struct iio_dev *to_iio_dev(struct device *d) | ||
| 369 | { | ||
| 370 | return container_of(d, struct iio_dev, dev); | ||
| 371 | }; | ||
| 372 | |||
| 373 | /** | ||
| 374 | * iio_dev_get_devdata() - helper function gets device specific data | ||
| 375 | * @d: the iio_dev associated with the device | ||
| 376 | **/ | ||
| 377 | static inline void *iio_dev_get_devdata(struct iio_dev *d) | ||
| 378 | { | ||
| 379 | return d->dev_data; | ||
| 380 | } | ||
| 381 | |||
| 382 | |||
| 383 | /* Can we make this smaller? */ | ||
| 384 | #define IIO_ALIGN L1_CACHE_BYTES | ||
| 385 | /** | ||
| 386 | * iio_allocate_device() - allocate an iio_dev from a driver | ||
| 387 | * @sizeof_priv: Space to allocate for private structure. | ||
| 388 | **/ | ||
| 389 | struct iio_dev *iio_allocate_device(int sizeof_priv); | ||
| 390 | |||
| 391 | static inline void *iio_priv(const struct iio_dev *dev) | ||
| 392 | { | ||
| 393 | return (char *)dev + ALIGN(sizeof(struct iio_dev), IIO_ALIGN); | ||
| 394 | } | ||
| 395 | |||
| 396 | static inline struct iio_dev *iio_priv_to_dev(void *priv) | ||
| 397 | { | ||
| 398 | return (struct iio_dev *)((char *)priv - | ||
| 399 | ALIGN(sizeof(struct iio_dev), IIO_ALIGN)); | ||
| 400 | } | ||
| 401 | |||
| 402 | /** | ||
| 403 | * iio_free_device() - free an iio_dev from a driver | ||
| 404 | * @dev: the iio_dev associated with the device | ||
| 405 | **/ | ||
| 406 | void iio_free_device(struct iio_dev *dev); | ||
| 407 | |||
| 408 | /** | ||
| 409 | * iio_put() - internal module reference count reduce | ||
| 410 | **/ | ||
| 411 | void iio_put(void); | ||
| 412 | |||
| 413 | /** | ||
| 414 | * iio_get() - internal module reference count increase | ||
| 415 | **/ | ||
| 416 | void iio_get(void); | ||
| 417 | |||
| 418 | /** | ||
| 419 | * iio_device_get_chrdev_minor() - get an unused minor number | ||
| 420 | **/ | ||
| 421 | int iio_device_get_chrdev_minor(void); | ||
| 422 | void iio_device_free_chrdev_minor(int val); | ||
| 423 | |||
| 424 | /** | ||
| 425 | * iio_ring_enabled() - helper function to test if any form of ring is enabled | ||
| 426 | * @dev_info: IIO device info structure for device | ||
| 427 | **/ | ||
| 428 | static inline bool iio_ring_enabled(struct iio_dev *dev_info) | ||
| 429 | { | ||
| 430 | return dev_info->currentmode | ||
| 431 | & (INDIO_RING_TRIGGERED | ||
| 432 | | INDIO_RING_HARDWARE_BUFFER); | ||
| 433 | }; | ||
| 434 | |||
| 435 | struct ida; | ||
| 436 | |||
| 437 | int iio_get_new_ida_val(struct ida *this_ida); | ||
| 438 | void iio_free_ida_val(struct ida *this_ida, int id); | ||
| 439 | #endif /* _INDUSTRIAL_IO_H_ */ | ||
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c new file mode 100644 index 00000000000..19819e7578c --- /dev/null +++ b/drivers/staging/iio/industrialio-core.c | |||
| @@ -0,0 +1,1245 @@ | |||
| 1 | /* The industrial I/O core | ||
| 2 | * | ||
| 3 | * Copyright (c) 2008 Jonathan Cameron | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 as published by | ||
| 7 | * the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * Based on elements of hwmon and input subsystems. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/idr.h> | ||
| 15 | #include <linux/kdev_t.h> | ||
| 16 | #include <linux/err.h> | ||
| 17 | #include <linux/device.h> | ||
| 18 | #include <linux/fs.h> | ||
| 19 | #include <linux/poll.h> | ||
| 20 | #include <linux/sched.h> | ||
| 21 | #include <linux/wait.h> | ||
| 22 | #include <linux/cdev.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include "iio.h" | ||
| 25 | #include "trigger_consumer.h" | ||
| 26 | |||
| 27 | #define IIO_ID_PREFIX "device" | ||
| 28 | #define IIO_ID_FORMAT IIO_ID_PREFIX "%d" | ||
| 29 | |||
| 30 | /* IDR to assign each registered device a unique id*/ | ||
| 31 | static DEFINE_IDA(iio_ida); | ||
| 32 | /* IDR to allocate character device minor numbers */ | ||
| 33 | static DEFINE_IDA(iio_chrdev_ida); | ||
| 34 | /* Lock used to protect both of the above */ | ||
| 35 | static DEFINE_SPINLOCK(iio_ida_lock); | ||
| 36 | |||
| 37 | dev_t iio_devt; | ||
| 38 | EXPORT_SYMBOL(iio_devt); | ||
| 39 | |||
| 40 | #define IIO_DEV_MAX 256 | ||
| 41 | struct bus_type iio_bus_type = { | ||
| 42 | .name = "iio", | ||
| 43 | }; | ||
| 44 | EXPORT_SYMBOL(iio_bus_type); | ||
| 45 | |||
| 46 | static const char * const iio_chan_type_name_spec_shared[] = { | ||
| 47 | [IIO_IN] = "in", | ||
| 48 | [IIO_OUT] = "out", | ||
| 49 | [IIO_CURRENT] = "current", | ||
| 50 | [IIO_POWER] = "power", | ||
| 51 | [IIO_ACCEL] = "accel", | ||
| 52 | [IIO_IN_DIFF] = "in-in", | ||
| 53 | [IIO_GYRO] = "gyro", | ||
| 54 | [IIO_MAGN] = "magn", | ||
| 55 | [IIO_LIGHT] = "illuminance", | ||
| 56 | [IIO_INTENSITY] = "intensity", | ||
| 57 | [IIO_PROXIMITY] = "proximity", | ||
| 58 | [IIO_TEMP] = "temp", | ||
| 59 | [IIO_INCLI] = "incli", | ||
| 60 | [IIO_ROT] = "rot", | ||
| 61 | [IIO_ANGL] = "angl", | ||
| 62 | [IIO_TIMESTAMP] = "timestamp", | ||
| 63 | }; | ||
| 64 | |||
| 65 | static const char * const iio_chan_type_name_spec_complex[] = { | ||
| 66 | [IIO_IN_DIFF] = "in%d-in%d", | ||
| 67 | }; | ||
| 68 | |||
| 69 | static const char * const iio_modifier_names_light[] = { | ||
| 70 | [IIO_MOD_LIGHT_BOTH] = "both", | ||
| 71 | [IIO_MOD_LIGHT_IR] = "ir", | ||
| 72 | }; | ||
| 73 | |||
| 74 | static const char * const iio_modifier_names_axial[] = { | ||
| 75 | [IIO_MOD_X] = "x", | ||
| 76 | [IIO_MOD_Y] = "y", | ||
| 77 | [IIO_MOD_Z] = "z", | ||
| 78 | }; | ||
| 79 | |||
| 80 | /* relies on pairs of these shared then separate */ | ||
| 81 | static const char * const iio_chan_info_postfix[] = { | ||
| 82 | [IIO_CHAN_INFO_SCALE_SHARED/2] = "scale", | ||
| 83 | [IIO_CHAN_INFO_OFFSET_SHARED/2] = "offset", | ||
| 84 | [IIO_CHAN_INFO_CALIBSCALE_SHARED/2] = "calibscale", | ||
| 85 | [IIO_CHAN_INFO_CALIBBIAS_SHARED/2] = "calibbias", | ||
| 86 | [IIO_CHAN_INFO_PEAK_SHARED/2] = "peak_raw", | ||
| 87 | [IIO_CHAN_INFO_PEAK_SCALE_SHARED/2] = "peak_scale", | ||
| 88 | }; | ||
| 89 | |||
| 90 | int iio_push_event(struct iio_dev *dev_info, | ||
| 91 | int ev_line, | ||
| 92 | int ev_code, | ||
| 93 | s64 timestamp) | ||
| 94 | { | ||
| 95 | struct iio_event_interface *ev_int | ||
| 96 | = &dev_info->event_interfaces[ev_line]; | ||
| 97 | struct iio_detected_event_list *ev; | ||
| 98 | int ret = 0; | ||
| 99 | |||
| 100 | /* Does anyone care? */ | ||
| 101 | mutex_lock(&ev_int->event_list_lock); | ||
| 102 | if (test_bit(IIO_BUSY_BIT_POS, &ev_int->handler.flags)) { | ||
| 103 | if (ev_int->current_events == ev_int->max_events) { | ||
| 104 | mutex_unlock(&ev_int->event_list_lock); | ||
| 105 | return 0; | ||
| 106 | } | ||
| 107 | ev = kmalloc(sizeof(*ev), GFP_KERNEL); | ||
| 108 | if (ev == NULL) { | ||
| 109 | ret = -ENOMEM; | ||
| 110 | mutex_unlock(&ev_int->event_list_lock); | ||
| 111 | goto error_ret; | ||
| 112 | } | ||
| 113 | ev->ev.id = ev_code; | ||
| 114 | ev->ev.timestamp = timestamp; | ||
| 115 | |||
| 116 | list_add_tail(&ev->list, &ev_int->det_events); | ||
| 117 | ev_int->current_events++; | ||
| 118 | mutex_unlock(&ev_int->event_list_lock); | ||
| 119 | wake_up_interruptible(&ev_int->wait); | ||
| 120 | } else | ||
| 121 | mutex_unlock(&ev_int->event_list_lock); | ||
| 122 | |||
| 123 | error_ret: | ||
| 124 | return ret; | ||
| 125 | } | ||
| 126 | EXPORT_SYMBOL(iio_push_event); | ||
| 127 | |||
| 128 | |||
| 129 | /* This turns up an awful lot */ | ||
| 130 | ssize_t iio_read_const_attr(struct device *dev, | ||
| 131 | struct device_attribute *attr, | ||
| 132 | char *buf) | ||
| 133 | { | ||
| 134 | return sprintf(buf, "%s\n", to_iio_const_attr(attr)->string); | ||
| 135 | } | ||
| 136 | EXPORT_SYMBOL(iio_read_const_attr); | ||
| 137 | |||
| 138 | |||
| 139 | static ssize_t iio_event_chrdev_read(struct file *filep, | ||
| 140 | char __user *buf, | ||
| 141 | size_t count, | ||
| 142 | loff_t *f_ps) | ||
| 143 | { | ||
| 144 | struct iio_event_interface *ev_int = filep->private_data; | ||
| 145 | struct iio_detected_event_list *el; | ||
| 146 | int ret; | ||
| 147 | size_t len; | ||
| 148 | |||
| 149 | mutex_lock(&ev_int->event_list_lock); | ||
| 150 | if (list_empty(&ev_int->det_events)) { | ||
| 151 | if (filep->f_flags & O_NONBLOCK) { | ||
| 152 | ret = -EAGAIN; | ||
| 153 | goto error_mutex_unlock; | ||
| 154 | } | ||
| 155 | mutex_unlock(&ev_int->event_list_lock); | ||
| 156 | /* Blocking on device; waiting for something to be there */ | ||
| 157 | ret = wait_event_interruptible(ev_int->wait, | ||
| 158 | !list_empty(&ev_int | ||
| 159 | ->det_events)); | ||
| 160 | if (ret) | ||
| 161 | goto error_ret; | ||
| 162 | /* Single access device so no one else can get the data */ | ||
| 163 | mutex_lock(&ev_int->event_list_lock); | ||
| 164 | } | ||
| 165 | |||
| 166 | el = list_first_entry(&ev_int->det_events, | ||
| 167 | struct iio_detected_event_list, | ||
| 168 | list); | ||
| 169 | len = sizeof el->ev; | ||
| 170 | if (copy_to_user(buf, &(el->ev), len)) { | ||
| 171 | ret = -EFAULT; | ||
| 172 | goto error_mutex_unlock; | ||
| 173 | } | ||
| 174 | list_del(&el->list); | ||
| 175 | ev_int->current_events--; | ||
| 176 | mutex_unlock(&ev_int->event_list_lock); | ||
| 177 | kfree(el); | ||
| 178 | |||
| 179 | return len; | ||
| 180 | |||
| 181 | error_mutex_unlock: | ||
| 182 | mutex_unlock(&ev_int->event_list_lock); | ||
| 183 | error_ret: | ||
| 184 | |||
| 185 | return ret; | ||
| 186 | } | ||
| 187 | |||
| 188 | static int iio_event_chrdev_release(struct inode *inode, struct file *filep) | ||
| 189 | { | ||
| 190 | struct iio_handler *hand = iio_cdev_to_handler(inode->i_cdev); | ||
| 191 | struct iio_event_interface *ev_int = hand->private; | ||
| 192 | struct iio_detected_event_list *el, *t; | ||
| 193 | |||
| 194 | mutex_lock(&ev_int->event_list_lock); | ||
| 195 | clear_bit(IIO_BUSY_BIT_POS, &ev_int->handler.flags); | ||
| 196 | /* | ||
| 197 | * In order to maintain a clean state for reopening, | ||
| 198 | * clear out any awaiting events. The mask will prevent | ||
| 199 | * any new __iio_push_event calls running. | ||
| 200 | */ | ||
| 201 | list_for_each_entry_safe(el, t, &ev_int->det_events, list) { | ||
| 202 | list_del(&el->list); | ||
| 203 | kfree(el); | ||
| 204 | } | ||
| 205 | mutex_unlock(&ev_int->event_list_lock); | ||
| 206 | |||
| 207 | return 0; | ||
| 208 | } | ||
| 209 | |||
| 210 | static int iio_event_chrdev_open(struct inode *inode, struct file *filep) | ||
| 211 | { | ||
| 212 | struct iio_handler *hand = iio_cdev_to_handler(inode->i_cdev); | ||
| 213 | struct iio_event_interface *ev_int = hand->private; | ||
| 214 | |||
| 215 | mutex_lock(&ev_int->event_list_lock); | ||
| 216 | if (test_and_set_bit(IIO_BUSY_BIT_POS, &hand->flags)) { | ||
| 217 | fops_put(filep->f_op); | ||
| 218 | mutex_unlock(&ev_int->event_list_lock); | ||
| 219 | return -EBUSY; | ||
| 220 | } | ||
| 221 | filep->private_data = hand->private; | ||
| 222 | mutex_unlock(&ev_int->event_list_lock); | ||
| 223 | |||
| 224 | return 0; | ||
| 225 | } | ||
| 226 | |||
| 227 | static const struct file_operations iio_event_chrdev_fileops = { | ||
| 228 | .read = iio_event_chrdev_read, | ||
| 229 | .release = iio_event_chrdev_release, | ||
| 230 | .open = iio_event_chrdev_open, | ||
| 231 | .owner = THIS_MODULE, | ||
| 232 | .llseek = noop_llseek, | ||
| 233 | }; | ||
| 234 | |||
| 235 | static void iio_event_dev_release(struct device *dev) | ||
| 236 | { | ||
| 237 | struct iio_event_interface *ev_int | ||
| 238 | = container_of(dev, struct iio_event_interface, dev); | ||
| 239 | cdev_del(&ev_int->handler.chrdev); | ||
| 240 | iio_device_free_chrdev_minor(MINOR(dev->devt)); | ||
| 241 | }; | ||
| 242 | |||
| 243 | static struct device_type iio_event_type = { | ||
| 244 | .release = iio_event_dev_release, | ||
| 245 | }; | ||
| 246 | |||
| 247 | int iio_device_get_chrdev_minor(void) | ||
| 248 | { | ||
| 249 | int ret, val; | ||
| 250 | |||
| 251 | ida_again: | ||
| 252 | if (unlikely(ida_pre_get(&iio_chrdev_ida, GFP_KERNEL) == 0)) | ||
| 253 | return -ENOMEM; | ||
| 254 | spin_lock(&iio_ida_lock); | ||
| 255 | ret = ida_get_new(&iio_chrdev_ida, &val); | ||
| 256 | spin_unlock(&iio_ida_lock); | ||
| 257 | if (unlikely(ret == -EAGAIN)) | ||
| 258 | goto ida_again; | ||
| 259 | else if (unlikely(ret)) | ||
| 260 | return ret; | ||
| 261 | if (val > IIO_DEV_MAX) | ||
| 262 | return -ENOMEM; | ||
| 263 | return val; | ||
| 264 | } | ||
| 265 | |||
| 266 | void iio_device_free_chrdev_minor(int val) | ||
| 267 | { | ||
| 268 | spin_lock(&iio_ida_lock); | ||
| 269 | ida_remove(&iio_chrdev_ida, val); | ||
| 270 | spin_unlock(&iio_ida_lock); | ||
| 271 | } | ||
| 272 | |||
| 273 | static int iio_setup_ev_int(struct iio_event_interface *ev_int, | ||
| 274 | const char *dev_name, | ||
| 275 | int index, | ||
| 276 | struct module *owner, | ||
| 277 | struct device *dev) | ||
| 278 | { | ||
| 279 | int ret, minor; | ||
| 280 | |||
| 281 | ev_int->dev.bus = &iio_bus_type; | ||
| 282 | ev_int->dev.parent = dev; | ||
| 283 | ev_int->dev.type = &iio_event_type; | ||
| 284 | device_initialize(&ev_int->dev); | ||
| 285 | |||
| 286 | minor = iio_device_get_chrdev_minor(); | ||
| 287 | if (minor < 0) { | ||
| 288 | ret = minor; | ||
| 289 | goto error_device_put; | ||
| 290 | } | ||
| 291 | ev_int->dev.devt = MKDEV(MAJOR(iio_devt), minor); | ||
| 292 | dev_set_name(&ev_int->dev, "%s:event%d", dev_name, index); | ||
| 293 | |||
| 294 | ret = device_add(&ev_int->dev); | ||
| 295 | if (ret) | ||
| 296 | goto error_free_minor; | ||
| 297 | |||
| 298 | cdev_init(&ev_int->handler.chrdev, &iio_event_chrdev_fileops); | ||
| 299 | ev_int->handler.chrdev.owner = owner; | ||
| 300 | |||
| 301 | mutex_init(&ev_int->event_list_lock); | ||
| 302 | /* discussion point - make this variable? */ | ||
| 303 | ev_int->max_events = 10; | ||
| 304 | ev_int->current_events = 0; | ||
| 305 | INIT_LIST_HEAD(&ev_int->det_events); | ||
| 306 | init_waitqueue_head(&ev_int->wait); | ||
| 307 | ev_int->handler.private = ev_int; | ||
| 308 | ev_int->handler.flags = 0; | ||
| 309 | |||
| 310 | ret = cdev_add(&ev_int->handler.chrdev, ev_int->dev.devt, 1); | ||
| 311 | if (ret) | ||
| 312 | goto error_unreg_device; | ||
| 313 | |||
| 314 | return 0; | ||
| 315 | |||
| 316 | error_unreg_device: | ||
| 317 | device_unregister(&ev_int->dev); | ||
| 318 | error_free_minor: | ||
| 319 | iio_device_free_chrdev_minor(minor); | ||
| 320 | error_device_put: | ||
| 321 | put_device(&ev_int->dev); | ||
| 322 | |||
| 323 | return ret; | ||
| 324 | } | ||
| 325 | |||
| 326 | static void iio_free_ev_int(struct iio_event_interface *ev_int) | ||
| 327 | { | ||
| 328 | device_unregister(&ev_int->dev); | ||
| 329 | put_device(&ev_int->dev); | ||
| 330 | } | ||
| 331 | |||
| 332 | static int __init iio_dev_init(void) | ||
| 333 | { | ||
| 334 | int err; | ||
| 335 | |||
| 336 | err = alloc_chrdev_region(&iio_devt, 0, IIO_DEV_MAX, "iio"); | ||
| 337 | if (err < 0) | ||
| 338 | printk(KERN_ERR "%s: failed to allocate char dev region\n", | ||
| 339 | __FILE__); | ||
| 340 | |||
| 341 | return err; | ||
| 342 | } | ||
| 343 | |||
| 344 | static void __exit iio_dev_exit(void) | ||
| 345 | { | ||
| 346 | if (iio_devt) | ||
| 347 | unregister_chrdev_region(iio_devt, IIO_DEV_MAX); | ||
| 348 | } | ||
| 349 | |||
| 350 | static int __init iio_init(void) | ||
| 351 | { | ||
| 352 | int ret; | ||
| 353 | |||
| 354 | /* Register sysfs bus */ | ||
| 355 | ret = bus_register(&iio_bus_type); | ||
| 356 | if (ret < 0) { | ||
| 357 | printk(KERN_ERR | ||
| 358 | "%s could not register bus type\n", | ||
| 359 | __FILE__); | ||
| 360 | goto error_nothing; | ||
| 361 | } | ||
| 362 | |||
| 363 | ret = iio_dev_init(); | ||
| 364 | if (ret < 0) | ||
| 365 | goto error_unregister_bus_type; | ||
| 366 | |||
| 367 | return 0; | ||
| 368 | |||
| 369 | error_unregister_bus_type: | ||
| 370 | bus_unregister(&iio_bus_type); | ||
| 371 | error_nothing: | ||
| 372 | return ret; | ||
| 373 | } | ||
| 374 | |||
| 375 | static void __exit iio_exit(void) | ||
| 376 | { | ||
| 377 | iio_dev_exit(); | ||
| 378 | bus_unregister(&iio_bus_type); | ||
| 379 | } | ||
| 380 | |||
| 381 | static ssize_t iio_read_channel_info(struct device *dev, | ||
| 382 | struct device_attribute *attr, | ||
| 383 | char *buf) | ||
| 384 | { | ||
| 385 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 386 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 387 | int val, val2; | ||
| 388 | int ret = indio_dev->info->read_raw(indio_dev, this_attr->c, | ||
| 389 | &val, &val2, this_attr->address); | ||
| 390 | |||
| 391 | if (ret < 0) | ||
| 392 | return ret; | ||
| 393 | |||
| 394 | if (ret == IIO_VAL_INT) | ||
| 395 | return sprintf(buf, "%d\n", val); | ||
| 396 | else if (ret == IIO_VAL_INT_PLUS_MICRO) { | ||
| 397 | if (val2 < 0) | ||
| 398 | return sprintf(buf, "-%d.%06u\n", val, -val2); | ||
| 399 | else | ||
| 400 | return sprintf(buf, "%d.%06u\n", val, val2); | ||
| 401 | } else if (ret == IIO_VAL_INT_PLUS_NANO) { | ||
| 402 | if (val2 < 0) | ||
| 403 | return sprintf(buf, "-%d.%09u\n", val, -val2); | ||
| 404 | else | ||
| 405 | return sprintf(buf, "%d.%09u\n", val, val2); | ||
| 406 | } else | ||
| 407 | return 0; | ||
| 408 | } | ||
| 409 | |||
| 410 | static ssize_t iio_write_channel_info(struct device *dev, | ||
| 411 | struct device_attribute *attr, | ||
| 412 | const char *buf, | ||
| 413 | size_t len) | ||
| 414 | { | ||
| 415 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 416 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 417 | int ret, integer = 0, fract = 0, fract_mult = 100000; | ||
| 418 | bool integer_part = true, negative = false; | ||
| 419 | |||
| 420 | /* Assumes decimal - precision based on number of digits */ | ||
| 421 | if (!indio_dev->info->write_raw) | ||
| 422 | return -EINVAL; | ||
| 423 | |||
| 424 | if (indio_dev->info->write_raw_get_fmt) | ||
| 425 | switch (indio_dev->info->write_raw_get_fmt(indio_dev, | ||
| 426 | this_attr->c, this_attr->address)) { | ||
| 427 | case IIO_VAL_INT_PLUS_MICRO: | ||
| 428 | fract_mult = 100000; | ||
| 429 | break; | ||
| 430 | case IIO_VAL_INT_PLUS_NANO: | ||
| 431 | fract_mult = 100000000; | ||
| 432 | break; | ||
| 433 | default: | ||
| 434 | return -EINVAL; | ||
| 435 | } | ||
| 436 | |||
| 437 | if (buf[0] == '-') { | ||
| 438 | negative = true; | ||
| 439 | buf++; | ||
| 440 | } | ||
| 441 | |||
| 442 | while (*buf) { | ||
| 443 | if ('0' <= *buf && *buf <= '9') { | ||
| 444 | if (integer_part) | ||
| 445 | integer = integer*10 + *buf - '0'; | ||
| 446 | else { | ||
| 447 | fract += fract_mult*(*buf - '0'); | ||
| 448 | if (fract_mult == 1) | ||
| 449 | break; | ||
| 450 | fract_mult /= 10; | ||
| 451 | } | ||
| 452 | } else if (*buf == '\n') { | ||
| 453 | if (*(buf + 1) == '\0') | ||
| 454 | break; | ||
| 455 | else | ||
| 456 | return -EINVAL; | ||
| 457 | } else if (*buf == '.') { | ||
| 458 | integer_part = false; | ||
| 459 | } else { | ||
| 460 | return -EINVAL; | ||
| 461 | } | ||
| 462 | buf++; | ||
| 463 | } | ||
| 464 | if (negative) { | ||
| 465 | if (integer) | ||
| 466 | integer = -integer; | ||
| 467 | else | ||
| 468 | fract = -fract; | ||
| 469 | } | ||
| 470 | |||
| 471 | ret = indio_dev->info->write_raw(indio_dev, this_attr->c, | ||
| 472 | integer, fract, this_attr->address); | ||
| 473 | if (ret) | ||
| 474 | return ret; | ||
| 475 | |||
| 476 | return len; | ||
| 477 | } | ||
| 478 | |||
| 479 | static int __iio_build_postfix(struct iio_chan_spec const *chan, | ||
| 480 | bool generic, | ||
| 481 | const char *postfix, | ||
| 482 | char **result) | ||
| 483 | { | ||
| 484 | char *all_post; | ||
| 485 | /* 3 options - generic, extend_name, modified - if generic, extend_name | ||
| 486 | * and modified cannot apply.*/ | ||
| 487 | |||
| 488 | if (generic || (!chan->modified && !chan->extend_name)) { | ||
| 489 | all_post = kasprintf(GFP_KERNEL, "%s", postfix); | ||
| 490 | } else if (chan->modified) { | ||
| 491 | const char *intermediate; | ||
| 492 | switch (chan->type) { | ||
| 493 | case IIO_INTENSITY: | ||
| 494 | intermediate | ||
| 495 | = iio_modifier_names_light[chan->channel2]; | ||
| 496 | break; | ||
| 497 | case IIO_ACCEL: | ||
| 498 | case IIO_GYRO: | ||
| 499 | case IIO_MAGN: | ||
| 500 | case IIO_INCLI: | ||
| 501 | case IIO_ROT: | ||
| 502 | case IIO_ANGL: | ||
| 503 | intermediate | ||
| 504 | = iio_modifier_names_axial[chan->channel2]; | ||
| 505 | break; | ||
| 506 | default: | ||
| 507 | return -EINVAL; | ||
| 508 | } | ||
| 509 | if (chan->extend_name) | ||
| 510 | all_post = kasprintf(GFP_KERNEL, "%s_%s_%s", | ||
| 511 | intermediate, | ||
| 512 | chan->extend_name, | ||
| 513 | postfix); | ||
| 514 | else | ||
| 515 | all_post = kasprintf(GFP_KERNEL, "%s_%s", | ||
| 516 | intermediate, | ||
| 517 | postfix); | ||
| 518 | } else | ||
| 519 | all_post = kasprintf(GFP_KERNEL, "%s_%s", chan->extend_name, | ||
| 520 | postfix); | ||
| 521 | if (all_post == NULL) | ||
| 522 | return -ENOMEM; | ||
| 523 | *result = all_post; | ||
| 524 | return 0; | ||
| 525 | } | ||
| 526 | |||
| 527 | int __iio_device_attr_init(struct device_attribute *dev_attr, | ||
| 528 | const char *postfix, | ||
| 529 | struct iio_chan_spec const *chan, | ||
| 530 | ssize_t (*readfunc)(struct device *dev, | ||
| 531 | struct device_attribute *attr, | ||
| 532 | char *buf), | ||
| 533 | ssize_t (*writefunc)(struct device *dev, | ||
| 534 | struct device_attribute *attr, | ||
| 535 | const char *buf, | ||
| 536 | size_t len), | ||
| 537 | bool generic) | ||
| 538 | { | ||
| 539 | int ret; | ||
| 540 | char *name_format, *full_postfix; | ||
| 541 | sysfs_attr_init(&dev_attr->attr); | ||
| 542 | ret = __iio_build_postfix(chan, generic, postfix, &full_postfix); | ||
| 543 | if (ret) | ||
| 544 | goto error_ret; | ||
| 545 | |||
| 546 | /* Special case for types that uses both channel numbers in naming */ | ||
| 547 | if (chan->type == IIO_IN_DIFF && !generic) | ||
| 548 | name_format | ||
| 549 | = kasprintf(GFP_KERNEL, "%s_%s", | ||
| 550 | iio_chan_type_name_spec_complex[chan->type], | ||
| 551 | full_postfix); | ||
| 552 | else if (generic || !chan->indexed) | ||
| 553 | name_format | ||
| 554 | = kasprintf(GFP_KERNEL, "%s_%s", | ||
| 555 | iio_chan_type_name_spec_shared[chan->type], | ||
| 556 | full_postfix); | ||
| 557 | else | ||
| 558 | name_format | ||
| 559 | = kasprintf(GFP_KERNEL, "%s%d_%s", | ||
| 560 | iio_chan_type_name_spec_shared[chan->type], | ||
| 561 | chan->channel, | ||
| 562 | full_postfix); | ||
| 563 | |||
| 564 | if (name_format == NULL) { | ||
| 565 | ret = -ENOMEM; | ||
| 566 | goto error_free_full_postfix; | ||
| 567 | } | ||
| 568 | dev_attr->attr.name = kasprintf(GFP_KERNEL, | ||
| 569 | name_format, | ||
| 570 | chan->channel, | ||
| 571 | chan->channel2); | ||
| 572 | if (dev_attr->attr.name == NULL) { | ||
| 573 | ret = -ENOMEM; | ||
| 574 | goto error_free_name_format; | ||
| 575 | } | ||
| 576 | |||
| 577 | if (readfunc) { | ||
| 578 | dev_attr->attr.mode |= S_IRUGO; | ||
| 579 | dev_attr->show = readfunc; | ||
| 580 | } | ||
| 581 | |||
| 582 | if (writefunc) { | ||
| 583 | dev_attr->attr.mode |= S_IWUSR; | ||
| 584 | dev_attr->store = writefunc; | ||
| 585 | } | ||
| 586 | kfree(name_format); | ||
| 587 | kfree(full_postfix); | ||
| 588 | |||
| 589 | return 0; | ||
| 590 | |||
| 591 | error_free_name_format: | ||
| 592 | kfree(name_format); | ||
| 593 | error_free_full_postfix: | ||
| 594 | kfree(full_postfix); | ||
| 595 | error_ret: | ||
| 596 | return ret; | ||
| 597 | } | ||
| 598 | |||
| 599 | void __iio_device_attr_deinit(struct device_attribute *dev_attr) | ||
| 600 | { | ||
| 601 | kfree(dev_attr->attr.name); | ||
| 602 | } | ||
| 603 | |||
| 604 | int __iio_add_chan_devattr(const char *postfix, | ||
| 605 | const char *group, | ||
| 606 | struct iio_chan_spec const *chan, | ||
| 607 | ssize_t (*readfunc)(struct device *dev, | ||
| 608 | struct device_attribute *attr, | ||
| 609 | char *buf), | ||
| 610 | ssize_t (*writefunc)(struct device *dev, | ||
| 611 | struct device_attribute *attr, | ||
| 612 | const char *buf, | ||
| 613 | size_t len), | ||
| 614 | int mask, | ||
| 615 | bool generic, | ||
| 616 | struct device *dev, | ||
| 617 | struct list_head *attr_list) | ||
| 618 | { | ||
| 619 | int ret; | ||
| 620 | struct iio_dev_attr *iio_attr, *t; | ||
| 621 | |||
| 622 | iio_attr = kzalloc(sizeof *iio_attr, GFP_KERNEL); | ||
| 623 | if (iio_attr == NULL) { | ||
| 624 | ret = -ENOMEM; | ||
| 625 | goto error_ret; | ||
| 626 | } | ||
| 627 | ret = __iio_device_attr_init(&iio_attr->dev_attr, | ||
| 628 | postfix, chan, | ||
| 629 | readfunc, writefunc, generic); | ||
| 630 | if (ret) | ||
| 631 | goto error_iio_dev_attr_free; | ||
| 632 | iio_attr->c = chan; | ||
| 633 | iio_attr->address = mask; | ||
| 634 | list_for_each_entry(t, attr_list, l) | ||
| 635 | if (strcmp(t->dev_attr.attr.name, | ||
| 636 | iio_attr->dev_attr.attr.name) == 0) { | ||
| 637 | if (!generic) | ||
| 638 | dev_err(dev, "tried to double register : %s\n", | ||
| 639 | t->dev_attr.attr.name); | ||
| 640 | ret = -EBUSY; | ||
| 641 | goto error_device_attr_deinit; | ||
| 642 | } | ||
| 643 | |||
| 644 | ret = sysfs_add_file_to_group(&dev->kobj, | ||
| 645 | &iio_attr->dev_attr.attr, group); | ||
| 646 | if (ret < 0) | ||
| 647 | goto error_device_attr_deinit; | ||
| 648 | |||
| 649 | list_add(&iio_attr->l, attr_list); | ||
| 650 | |||
| 651 | return 0; | ||
| 652 | |||
| 653 | error_device_attr_deinit: | ||
| 654 | __iio_device_attr_deinit(&iio_attr->dev_attr); | ||
| 655 | error_iio_dev_attr_free: | ||
| 656 | kfree(iio_attr); | ||
| 657 | error_ret: | ||
| 658 | return ret; | ||
| 659 | } | ||
| 660 | |||
| 661 | static int iio_device_add_channel_sysfs(struct iio_dev *dev_info, | ||
| 662 | struct iio_chan_spec const *chan) | ||
| 663 | { | ||
| 664 | int ret, i; | ||
| 665 | |||
| 666 | |||
| 667 | if (chan->channel < 0) | ||
| 668 | return 0; | ||
| 669 | if (chan->processed_val) | ||
| 670 | ret = __iio_add_chan_devattr("input", NULL, chan, | ||
| 671 | &iio_read_channel_info, | ||
| 672 | NULL, | ||
| 673 | 0, | ||
| 674 | 0, | ||
| 675 | &dev_info->dev, | ||
| 676 | &dev_info->channel_attr_list); | ||
| 677 | else | ||
| 678 | ret = __iio_add_chan_devattr("raw", NULL, chan, | ||
| 679 | &iio_read_channel_info, | ||
| 680 | (chan->type == IIO_OUT ? | ||
| 681 | &iio_write_channel_info : NULL), | ||
| 682 | 0, | ||
| 683 | 0, | ||
| 684 | &dev_info->dev, | ||
| 685 | &dev_info->channel_attr_list); | ||
| 686 | if (ret) | ||
| 687 | goto error_ret; | ||
| 688 | |||
| 689 | for_each_set_bit(i, &chan->info_mask, sizeof(long)*8) { | ||
| 690 | ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2], | ||
| 691 | NULL, chan, | ||
| 692 | &iio_read_channel_info, | ||
| 693 | &iio_write_channel_info, | ||
| 694 | (1 << i), | ||
| 695 | !(i%2), | ||
| 696 | &dev_info->dev, | ||
| 697 | &dev_info->channel_attr_list); | ||
| 698 | if (ret == -EBUSY && (i%2 == 0)) { | ||
| 699 | ret = 0; | ||
| 700 | continue; | ||
| 701 | } | ||
| 702 | if (ret < 0) | ||
| 703 | goto error_ret; | ||
| 704 | } | ||
| 705 | error_ret: | ||
| 706 | return ret; | ||
| 707 | } | ||
| 708 | |||
| 709 | static void iio_device_remove_and_free_read_attr(struct iio_dev *dev_info, | ||
| 710 | struct iio_dev_attr *p) | ||
| 711 | { | ||
| 712 | sysfs_remove_file_from_group(&dev_info->dev.kobj, | ||
| 713 | &p->dev_attr.attr, NULL); | ||
| 714 | kfree(p->dev_attr.attr.name); | ||
| 715 | kfree(p); | ||
| 716 | } | ||
| 717 | |||
| 718 | static ssize_t iio_show_dev_name(struct device *dev, | ||
| 719 | struct device_attribute *attr, | ||
| 720 | char *buf) | ||
| 721 | { | ||
| 722 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 723 | return sprintf(buf, "%s\n", indio_dev->name); | ||
| 724 | } | ||
| 725 | |||
| 726 | static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL); | ||
| 727 | |||
| 728 | static int iio_device_register_sysfs(struct iio_dev *dev_info) | ||
| 729 | { | ||
| 730 | int i, ret = 0; | ||
| 731 | struct iio_dev_attr *p, *n; | ||
| 732 | |||
| 733 | if (dev_info->info->attrs) { | ||
| 734 | ret = sysfs_create_group(&dev_info->dev.kobj, | ||
| 735 | dev_info->info->attrs); | ||
| 736 | if (ret) { | ||
| 737 | dev_err(dev_info->dev.parent, | ||
| 738 | "Failed to register sysfs hooks\n"); | ||
| 739 | goto error_ret; | ||
| 740 | } | ||
| 741 | } | ||
| 742 | |||
| 743 | /* | ||
| 744 | * New channel registration method - relies on the fact a group does | ||
| 745 | * not need to be initialized if it is name is NULL. | ||
| 746 | */ | ||
| 747 | INIT_LIST_HEAD(&dev_info->channel_attr_list); | ||
| 748 | if (dev_info->channels) | ||
| 749 | for (i = 0; i < dev_info->num_channels; i++) { | ||
| 750 | ret = iio_device_add_channel_sysfs(dev_info, | ||
| 751 | &dev_info | ||
| 752 | ->channels[i]); | ||
| 753 | if (ret < 0) | ||
| 754 | goto error_clear_attrs; | ||
| 755 | } | ||
| 756 | if (dev_info->name) { | ||
| 757 | ret = sysfs_add_file_to_group(&dev_info->dev.kobj, | ||
| 758 | &dev_attr_name.attr, | ||
| 759 | NULL); | ||
| 760 | if (ret) | ||
| 761 | goto error_clear_attrs; | ||
| 762 | } | ||
| 763 | return 0; | ||
| 764 | |||
| 765 | error_clear_attrs: | ||
| 766 | list_for_each_entry_safe(p, n, | ||
| 767 | &dev_info->channel_attr_list, l) { | ||
| 768 | list_del(&p->l); | ||
| 769 | iio_device_remove_and_free_read_attr(dev_info, p); | ||
| 770 | } | ||
| 771 | if (dev_info->info->attrs) | ||
| 772 | sysfs_remove_group(&dev_info->dev.kobj, dev_info->info->attrs); | ||
| 773 | error_ret: | ||
| 774 | return ret; | ||
| 775 | |||
| 776 | } | ||
| 777 | |||
| 778 | static void iio_device_unregister_sysfs(struct iio_dev *dev_info) | ||
| 779 | { | ||
| 780 | |||
| 781 | struct iio_dev_attr *p, *n; | ||
| 782 | if (dev_info->name) | ||
| 783 | sysfs_remove_file_from_group(&dev_info->dev.kobj, | ||
| 784 | &dev_attr_name.attr, | ||
| 785 | NULL); | ||
| 786 | list_for_each_entry_safe(p, n, &dev_info->channel_attr_list, l) { | ||
| 787 | list_del(&p->l); | ||
| 788 | iio_device_remove_and_free_read_attr(dev_info, p); | ||
| 789 | } | ||
| 790 | |||
| 791 | if (dev_info->info->attrs) | ||
| 792 | sysfs_remove_group(&dev_info->dev.kobj, dev_info->info->attrs); | ||
| 793 | } | ||
| 794 | |||
| 795 | /* Return a negative errno on failure */ | ||
| 796 | int iio_get_new_ida_val(struct ida *this_ida) | ||
| 797 | { | ||
| 798 | int ret; | ||
| 799 | int val; | ||
| 800 | |||
| 801 | ida_again: | ||
| 802 | if (unlikely(ida_pre_get(this_ida, GFP_KERNEL) == 0)) | ||
| 803 | return -ENOMEM; | ||
| 804 | |||
| 805 | spin_lock(&iio_ida_lock); | ||
| 806 | ret = ida_get_new(this_ida, &val); | ||
| 807 | spin_unlock(&iio_ida_lock); | ||
| 808 | if (unlikely(ret == -EAGAIN)) | ||
| 809 | goto ida_again; | ||
| 810 | else if (unlikely(ret)) | ||
| 811 | return ret; | ||
| 812 | |||
| 813 | return val; | ||
| 814 | } | ||
| 815 | EXPORT_SYMBOL(iio_get_new_ida_val); | ||
| 816 | |||
| 817 | void iio_free_ida_val(struct ida *this_ida, int id) | ||
| 818 | { | ||
| 819 | spin_lock(&iio_ida_lock); | ||
| 820 | ida_remove(this_ida, id); | ||
| 821 | spin_unlock(&iio_ida_lock); | ||
| 822 | } | ||
| 823 | EXPORT_SYMBOL(iio_free_ida_val); | ||
| 824 | |||
| 825 | static const char * const iio_ev_type_text[] = { | ||
| 826 | [IIO_EV_TYPE_THRESH] = "thresh", | ||
| 827 | [IIO_EV_TYPE_MAG] = "mag", | ||
| 828 | [IIO_EV_TYPE_ROC] = "roc" | ||
| 829 | }; | ||
| 830 | |||
| 831 | static const char * const iio_ev_dir_text[] = { | ||
| 832 | [IIO_EV_DIR_EITHER] = "either", | ||
| 833 | [IIO_EV_DIR_RISING] = "rising", | ||
| 834 | [IIO_EV_DIR_FALLING] = "falling" | ||
| 835 | }; | ||
| 836 | |||
| 837 | static ssize_t iio_ev_state_store(struct device *dev, | ||
| 838 | struct device_attribute *attr, | ||
| 839 | const char *buf, | ||
| 840 | size_t len) | ||
| 841 | { | ||
| 842 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 843 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 844 | int ret; | ||
| 845 | bool val; | ||
| 846 | |||
| 847 | ret = strtobool(buf, &val); | ||
| 848 | if (ret < 0) | ||
| 849 | return ret; | ||
| 850 | |||
| 851 | ret = indio_dev->info->write_event_config(indio_dev, | ||
| 852 | this_attr->address, | ||
| 853 | val); | ||
| 854 | return (ret < 0) ? ret : len; | ||
| 855 | } | ||
| 856 | |||
| 857 | static ssize_t iio_ev_state_show(struct device *dev, | ||
| 858 | struct device_attribute *attr, | ||
| 859 | char *buf) | ||
| 860 | { | ||
| 861 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 862 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 863 | int val = indio_dev->info->read_event_config(indio_dev, | ||
| 864 | this_attr->address); | ||
| 865 | |||
| 866 | if (val < 0) | ||
| 867 | return val; | ||
| 868 | else | ||
| 869 | return sprintf(buf, "%d\n", val); | ||
| 870 | } | ||
| 871 | |||
| 872 | static ssize_t iio_ev_value_show(struct device *dev, | ||
| 873 | struct device_attribute *attr, | ||
| 874 | char *buf) | ||
| 875 | { | ||
| 876 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 877 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 878 | int val, ret; | ||
| 879 | |||
| 880 | ret = indio_dev->info->read_event_value(indio_dev, | ||
| 881 | this_attr->address, &val); | ||
| 882 | if (ret < 0) | ||
| 883 | return ret; | ||
| 884 | |||
| 885 | return sprintf(buf, "%d\n", val); | ||
| 886 | } | ||
| 887 | |||
| 888 | static ssize_t iio_ev_value_store(struct device *dev, | ||
| 889 | struct device_attribute *attr, | ||
| 890 | const char *buf, | ||
| 891 | size_t len) | ||
| 892 | { | ||
| 893 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 894 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 895 | unsigned long val; | ||
| 896 | int ret; | ||
| 897 | |||
| 898 | ret = strict_strtoul(buf, 10, &val); | ||
| 899 | if (ret) | ||
| 900 | return ret; | ||
| 901 | |||
| 902 | ret = indio_dev->info->write_event_value(indio_dev, this_attr->address, | ||
| 903 | val); | ||
| 904 | if (ret < 0) | ||
| 905 | return ret; | ||
| 906 | |||
| 907 | return len; | ||
| 908 | } | ||
| 909 | |||
| 910 | static int iio_device_add_event_sysfs(struct iio_dev *dev_info, | ||
| 911 | struct iio_chan_spec const *chan) | ||
| 912 | { | ||
| 913 | |||
| 914 | int ret = 0, i, mask; | ||
| 915 | char *postfix; | ||
| 916 | if (!chan->event_mask) | ||
| 917 | return 0; | ||
| 918 | |||
| 919 | for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) { | ||
| 920 | postfix = kasprintf(GFP_KERNEL, "%s_%s_en", | ||
| 921 | iio_ev_type_text[i/IIO_EV_TYPE_MAX], | ||
| 922 | iio_ev_dir_text[i%IIO_EV_TYPE_MAX]); | ||
| 923 | if (postfix == NULL) { | ||
| 924 | ret = -ENOMEM; | ||
| 925 | goto error_ret; | ||
| 926 | } | ||
| 927 | switch (chan->type) { | ||
| 928 | /* Switch this to a table at some point */ | ||
| 929 | case IIO_IN: | ||
| 930 | mask = IIO_UNMOD_EVENT_CODE(chan->type, chan->channel, | ||
| 931 | i/IIO_EV_TYPE_MAX, | ||
| 932 | i%IIO_EV_TYPE_MAX); | ||
| 933 | break; | ||
| 934 | case IIO_ACCEL: | ||
| 935 | mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel, | ||
| 936 | i/IIO_EV_TYPE_MAX, | ||
| 937 | i%IIO_EV_TYPE_MAX); | ||
| 938 | break; | ||
| 939 | case IIO_IN_DIFF: | ||
| 940 | mask = IIO_MOD_EVENT_CODE(chan->type, chan->channel, | ||
| 941 | chan->channel2, | ||
| 942 | i/IIO_EV_TYPE_MAX, | ||
| 943 | i%IIO_EV_TYPE_MAX); | ||
| 944 | break; | ||
| 945 | default: | ||
| 946 | printk(KERN_INFO "currently unhandled type of event\n"); | ||
| 947 | } | ||
| 948 | ret = __iio_add_chan_devattr(postfix, | ||
| 949 | NULL, | ||
| 950 | chan, | ||
| 951 | &iio_ev_state_show, | ||
| 952 | iio_ev_state_store, | ||
| 953 | mask, | ||
| 954 | /*HACK. - limits us to one | ||
| 955 | event interface - fix by | ||
| 956 | extending the bitmask - but | ||
| 957 | how far*/ | ||
| 958 | 0, | ||
| 959 | &dev_info->event_interfaces[0].dev, | ||
| 960 | &dev_info->event_interfaces[0]. | ||
| 961 | dev_attr_list); | ||
| 962 | kfree(postfix); | ||
| 963 | if (ret) | ||
| 964 | goto error_ret; | ||
| 965 | |||
| 966 | postfix = kasprintf(GFP_KERNEL, "%s_%s_value", | ||
| 967 | iio_ev_type_text[i/IIO_EV_TYPE_MAX], | ||
| 968 | iio_ev_dir_text[i%IIO_EV_TYPE_MAX]); | ||
| 969 | if (postfix == NULL) { | ||
| 970 | ret = -ENOMEM; | ||
| 971 | goto error_ret; | ||
| 972 | } | ||
| 973 | ret = __iio_add_chan_devattr(postfix, NULL, chan, | ||
| 974 | iio_ev_value_show, | ||
| 975 | iio_ev_value_store, | ||
| 976 | mask, | ||
| 977 | 0, | ||
| 978 | &dev_info->event_interfaces[0] | ||
| 979 | .dev, | ||
| 980 | &dev_info->event_interfaces[0] | ||
| 981 | .dev_attr_list); | ||
| 982 | kfree(postfix); | ||
| 983 | if (ret) | ||
| 984 | goto error_ret; | ||
| 985 | |||
| 986 | } | ||
| 987 | |||
| 988 | error_ret: | ||
| 989 | return ret; | ||
| 990 | } | ||
| 991 | |||
| 992 | static inline void __iio_remove_all_event_sysfs(struct iio_dev *dev_info, | ||
| 993 | const char *groupname, | ||
| 994 | int num) | ||
| 995 | { | ||
| 996 | struct iio_dev_attr *p, *n; | ||
| 997 | list_for_each_entry_safe(p, n, | ||
| 998 | &dev_info->event_interfaces[num]. | ||
| 999 | dev_attr_list, l) { | ||
| 1000 | sysfs_remove_file_from_group(&dev_info | ||
| 1001 | ->event_interfaces[num].dev.kobj, | ||
| 1002 | &p->dev_attr.attr, | ||
| 1003 | groupname); | ||
| 1004 | kfree(p->dev_attr.attr.name); | ||
| 1005 | kfree(p); | ||
| 1006 | } | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | static inline int __iio_add_event_config_attrs(struct iio_dev *dev_info, int i) | ||
| 1010 | { | ||
| 1011 | int j; | ||
| 1012 | int ret; | ||
| 1013 | INIT_LIST_HEAD(&dev_info->event_interfaces[0].dev_attr_list); | ||
| 1014 | /* Dynically created from the channels array */ | ||
| 1015 | if (dev_info->channels) { | ||
| 1016 | for (j = 0; j < dev_info->num_channels; j++) { | ||
| 1017 | ret = iio_device_add_event_sysfs(dev_info, | ||
| 1018 | &dev_info | ||
| 1019 | ->channels[j]); | ||
| 1020 | if (ret) | ||
| 1021 | goto error_clear_attrs; | ||
| 1022 | } | ||
| 1023 | } | ||
| 1024 | return 0; | ||
| 1025 | |||
| 1026 | error_clear_attrs: | ||
| 1027 | __iio_remove_all_event_sysfs(dev_info, NULL, i); | ||
| 1028 | |||
| 1029 | return ret; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | static inline int __iio_remove_event_config_attrs(struct iio_dev *dev_info, | ||
| 1033 | int i) | ||
| 1034 | { | ||
| 1035 | __iio_remove_all_event_sysfs(dev_info, NULL, i); | ||
| 1036 | return 0; | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | static int iio_device_register_eventset(struct iio_dev *dev_info) | ||
| 1040 | { | ||
| 1041 | int ret = 0, i, j; | ||
| 1042 | |||
| 1043 | if (dev_info->info->num_interrupt_lines == 0) | ||
| 1044 | return 0; | ||
| 1045 | |||
| 1046 | dev_info->event_interfaces = | ||
| 1047 | kzalloc(sizeof(struct iio_event_interface) | ||
| 1048 | *dev_info->info->num_interrupt_lines, | ||
| 1049 | GFP_KERNEL); | ||
| 1050 | if (dev_info->event_interfaces == NULL) { | ||
| 1051 | ret = -ENOMEM; | ||
| 1052 | goto error_ret; | ||
| 1053 | } | ||
| 1054 | |||
| 1055 | for (i = 0; i < dev_info->info->num_interrupt_lines; i++) { | ||
| 1056 | ret = iio_setup_ev_int(&dev_info->event_interfaces[i], | ||
| 1057 | dev_name(&dev_info->dev), | ||
| 1058 | i, | ||
| 1059 | dev_info->info->driver_module, | ||
| 1060 | &dev_info->dev); | ||
| 1061 | if (ret) { | ||
| 1062 | dev_err(&dev_info->dev, | ||
| 1063 | "Could not get chrdev interface\n"); | ||
| 1064 | goto error_free_setup_ev_ints; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | dev_set_drvdata(&dev_info->event_interfaces[i].dev, | ||
| 1068 | (void *)dev_info); | ||
| 1069 | |||
| 1070 | if (dev_info->info->event_attrs != NULL) | ||
| 1071 | ret = sysfs_create_group(&dev_info | ||
| 1072 | ->event_interfaces[i] | ||
| 1073 | .dev.kobj, | ||
| 1074 | &dev_info->info | ||
| 1075 | ->event_attrs[i]); | ||
| 1076 | |||
| 1077 | if (ret) { | ||
| 1078 | dev_err(&dev_info->dev, | ||
| 1079 | "Failed to register sysfs for event attrs"); | ||
| 1080 | goto error_remove_sysfs_interfaces; | ||
| 1081 | } | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | for (i = 0; i < dev_info->info->num_interrupt_lines; i++) { | ||
| 1085 | ret = __iio_add_event_config_attrs(dev_info, i); | ||
| 1086 | if (ret) | ||
| 1087 | goto error_unregister_config_attrs; | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | return 0; | ||
| 1091 | |||
| 1092 | error_unregister_config_attrs: | ||
| 1093 | for (j = 0; j < i; j++) | ||
| 1094 | __iio_remove_event_config_attrs(dev_info, i); | ||
| 1095 | i = dev_info->info->num_interrupt_lines - 1; | ||
| 1096 | error_remove_sysfs_interfaces: | ||
| 1097 | for (j = 0; j < i; j++) | ||
| 1098 | if (dev_info->info->event_attrs != NULL) | ||
| 1099 | sysfs_remove_group(&dev_info | ||
| 1100 | ->event_interfaces[j].dev.kobj, | ||
| 1101 | &dev_info->info->event_attrs[j]); | ||
| 1102 | error_free_setup_ev_ints: | ||
| 1103 | for (j = 0; j < i; j++) | ||
| 1104 | iio_free_ev_int(&dev_info->event_interfaces[j]); | ||
| 1105 | kfree(dev_info->event_interfaces); | ||
| 1106 | error_ret: | ||
| 1107 | |||
| 1108 | return ret; | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | static void iio_device_unregister_eventset(struct iio_dev *dev_info) | ||
| 1112 | { | ||
| 1113 | int i; | ||
| 1114 | |||
| 1115 | if (dev_info->info->num_interrupt_lines == 0) | ||
| 1116 | return; | ||
| 1117 | for (i = 0; i < dev_info->info->num_interrupt_lines; i++) { | ||
| 1118 | __iio_remove_event_config_attrs(dev_info, i); | ||
| 1119 | if (dev_info->info->event_attrs != NULL) | ||
| 1120 | sysfs_remove_group(&dev_info | ||
| 1121 | ->event_interfaces[i].dev.kobj, | ||
| 1122 | &dev_info->info->event_attrs[i]); | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | for (i = 0; i < dev_info->info->num_interrupt_lines; i++) | ||
| 1126 | iio_free_ev_int(&dev_info->event_interfaces[i]); | ||
| 1127 | kfree(dev_info->event_interfaces); | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | static void iio_dev_release(struct device *device) | ||
| 1131 | { | ||
| 1132 | iio_put(); | ||
| 1133 | kfree(to_iio_dev(device)); | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | static struct device_type iio_dev_type = { | ||
| 1137 | .name = "iio_device", | ||
| 1138 | .release = iio_dev_release, | ||
| 1139 | }; | ||
| 1140 | |||
| 1141 | struct iio_dev *iio_allocate_device(int sizeof_priv) | ||
| 1142 | { | ||
| 1143 | struct iio_dev *dev; | ||
| 1144 | size_t alloc_size; | ||
| 1145 | |||
| 1146 | alloc_size = sizeof(struct iio_dev); | ||
| 1147 | if (sizeof_priv) { | ||
| 1148 | alloc_size = ALIGN(alloc_size, IIO_ALIGN); | ||
| 1149 | alloc_size += sizeof_priv; | ||
| 1150 | } | ||
| 1151 | /* ensure 32-byte alignment of whole construct ? */ | ||
| 1152 | alloc_size += IIO_ALIGN - 1; | ||
| 1153 | |||
| 1154 | dev = kzalloc(alloc_size, GFP_KERNEL); | ||
| 1155 | |||
| 1156 | if (dev) { | ||
| 1157 | dev->dev.type = &iio_dev_type; | ||
| 1158 | dev->dev.bus = &iio_bus_type; | ||
| 1159 | device_initialize(&dev->dev); | ||
| 1160 | dev_set_drvdata(&dev->dev, (void *)dev); | ||
| 1161 | mutex_init(&dev->mlock); | ||
| 1162 | iio_get(); | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | return dev; | ||
| 1166 | } | ||
| 1167 | EXPORT_SYMBOL(iio_allocate_device); | ||
| 1168 | |||
| 1169 | void iio_free_device(struct iio_dev *dev) | ||
| 1170 | { | ||
| 1171 | if (dev) | ||
| 1172 | iio_put_device(dev); | ||
| 1173 | } | ||
| 1174 | EXPORT_SYMBOL(iio_free_device); | ||
| 1175 | |||
| 1176 | int iio_device_register(struct iio_dev *dev_info) | ||
| 1177 | { | ||
| 1178 | int ret; | ||
| 1179 | |||
| 1180 | dev_info->id = iio_get_new_ida_val(&iio_ida); | ||
| 1181 | if (dev_info->id < 0) { | ||
| 1182 | ret = dev_info->id; | ||
| 1183 | dev_err(&dev_info->dev, "Failed to get id\n"); | ||
| 1184 | goto error_ret; | ||
| 1185 | } | ||
| 1186 | dev_set_name(&dev_info->dev, "device%d", dev_info->id); | ||
| 1187 | |||
| 1188 | ret = device_add(&dev_info->dev); | ||
| 1189 | if (ret) | ||
| 1190 | goto error_free_ida; | ||
| 1191 | ret = iio_device_register_sysfs(dev_info); | ||
| 1192 | if (ret) { | ||
| 1193 | dev_err(dev_info->dev.parent, | ||
| 1194 | "Failed to register sysfs interfaces\n"); | ||
| 1195 | goto error_del_device; | ||
| 1196 | } | ||
| 1197 | ret = iio_device_register_eventset(dev_info); | ||
| 1198 | if (ret) { | ||
| 1199 | dev_err(dev_info->dev.parent, | ||
| 1200 | "Failed to register event set\n"); | ||
| 1201 | goto error_free_sysfs; | ||
| 1202 | } | ||
| 1203 | if (dev_info->modes & INDIO_RING_TRIGGERED) | ||
| 1204 | iio_device_register_trigger_consumer(dev_info); | ||
| 1205 | |||
| 1206 | return 0; | ||
| 1207 | |||
| 1208 | error_free_sysfs: | ||
| 1209 | iio_device_unregister_sysfs(dev_info); | ||
| 1210 | error_del_device: | ||
| 1211 | device_del(&dev_info->dev); | ||
| 1212 | error_free_ida: | ||
| 1213 | iio_free_ida_val(&iio_ida, dev_info->id); | ||
| 1214 | error_ret: | ||
| 1215 | return ret; | ||
| 1216 | } | ||
| 1217 | EXPORT_SYMBOL(iio_device_register); | ||
| 1218 | |||
| 1219 | void iio_device_unregister(struct iio_dev *dev_info) | ||
| 1220 | { | ||
| 1221 | if (dev_info->modes & INDIO_RING_TRIGGERED) | ||
| 1222 | iio_device_unregister_trigger_consumer(dev_info); | ||
| 1223 | iio_device_unregister_eventset(dev_info); | ||
| 1224 | iio_device_unregister_sysfs(dev_info); | ||
| 1225 | iio_free_ida_val(&iio_ida, dev_info->id); | ||
| 1226 | device_unregister(&dev_info->dev); | ||
| 1227 | } | ||
| 1228 | EXPORT_SYMBOL(iio_device_unregister); | ||
| 1229 | |||
| 1230 | void iio_put(void) | ||
| 1231 | { | ||
| 1232 | module_put(THIS_MODULE); | ||
| 1233 | } | ||
| 1234 | |||
| 1235 | void iio_get(void) | ||
| 1236 | { | ||
| 1237 | __module_get(THIS_MODULE); | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | subsys_initcall(iio_init); | ||
| 1241 | module_exit(iio_exit); | ||
| 1242 | |||
| 1243 | MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); | ||
| 1244 | MODULE_DESCRIPTION("Industrial I/O core"); | ||
| 1245 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/staging/iio/industrialio-ring.c b/drivers/staging/iio/industrialio-ring.c new file mode 100644 index 00000000000..843eb82a69b --- /dev/null +++ b/drivers/staging/iio/industrialio-ring.c | |||
| @@ -0,0 +1,596 @@ | |||
| 1 | /* The industrial I/O core | ||
| 2 | * | ||
| 3 | * Copyright (c) 2008 Jonathan Cameron | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 as published by | ||
| 7 | * the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * Handling of ring allocation / resizing. | ||
| 10 | * | ||
| 11 | * | ||
| 12 | * Things to look at here. | ||
| 13 | * - Better memory allocation techniques? | ||
| 14 | * - Alternative access techniques? | ||
| 15 | */ | ||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/device.h> | ||
| 18 | #include <linux/fs.h> | ||
| 19 | #include <linux/cdev.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <linux/poll.h> | ||
| 22 | |||
| 23 | #include "iio.h" | ||
| 24 | #include "ring_generic.h" | ||
| 25 | |||
| 26 | /** | ||
| 27 | * iio_ring_open() - chrdev file open for ring buffer access | ||
| 28 | * | ||
| 29 | * This function relies on all ring buffer implementations having an | ||
| 30 | * iio_ring_buffer as their first element. | ||
| 31 | **/ | ||
| 32 | static int iio_ring_open(struct inode *inode, struct file *filp) | ||
| 33 | { | ||
| 34 | struct iio_handler *hand | ||
| 35 | = container_of(inode->i_cdev, struct iio_handler, chrdev); | ||
| 36 | struct iio_ring_buffer *rb = hand->private; | ||
| 37 | |||
| 38 | filp->private_data = hand->private; | ||
| 39 | if (rb->access->mark_in_use) | ||
| 40 | rb->access->mark_in_use(rb); | ||
| 41 | |||
| 42 | return 0; | ||
| 43 | } | ||
| 44 | |||
| 45 | /** | ||
| 46 | * iio_ring_release() - chrdev file close ring buffer access | ||
| 47 | * | ||
| 48 | * This function relies on all ring buffer implementations having an | ||
| 49 | * iio_ring_buffer as their first element. | ||
| 50 | **/ | ||
| 51 | static int iio_ring_release(struct inode *inode, struct file *filp) | ||
| 52 | { | ||
| 53 | struct cdev *cd = inode->i_cdev; | ||
| 54 | struct iio_handler *hand = iio_cdev_to_handler(cd); | ||
| 55 | struct iio_ring_buffer *rb = hand->private; | ||
| 56 | |||
| 57 | clear_bit(IIO_BUSY_BIT_POS, &rb->access_handler.flags); | ||
| 58 | if (rb->access->unmark_in_use) | ||
| 59 | rb->access->unmark_in_use(rb); | ||
| 60 | |||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | /** | ||
| 65 | * iio_ring_read_first_n_outer() - chrdev read for ring buffer access | ||
| 66 | * | ||
| 67 | * This function relies on all ring buffer implementations having an | ||
| 68 | * iio_ring _bufer as their first element. | ||
| 69 | **/ | ||
| 70 | static ssize_t iio_ring_read_first_n_outer(struct file *filp, char __user *buf, | ||
| 71 | size_t n, loff_t *f_ps) | ||
| 72 | { | ||
| 73 | struct iio_ring_buffer *rb = filp->private_data; | ||
| 74 | |||
| 75 | if (!rb->access->read_first_n) | ||
| 76 | return -EINVAL; | ||
| 77 | return rb->access->read_first_n(rb, n, buf); | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * iio_ring_poll() - poll the ring to find out if it has data | ||
| 82 | */ | ||
| 83 | static unsigned int iio_ring_poll(struct file *filp, | ||
| 84 | struct poll_table_struct *wait) | ||
| 85 | { | ||
| 86 | struct iio_ring_buffer *rb = filp->private_data; | ||
| 87 | |||
| 88 | poll_wait(filp, &rb->pollq, wait); | ||
| 89 | if (rb->stufftoread) | ||
| 90 | return POLLIN | POLLRDNORM; | ||
| 91 | /* need a way of knowing if there may be enough data... */ | ||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | static const struct file_operations iio_ring_fileops = { | ||
| 96 | .read = iio_ring_read_first_n_outer, | ||
| 97 | .release = iio_ring_release, | ||
| 98 | .open = iio_ring_open, | ||
| 99 | .poll = iio_ring_poll, | ||
| 100 | .owner = THIS_MODULE, | ||
| 101 | .llseek = noop_llseek, | ||
| 102 | }; | ||
| 103 | |||
| 104 | void iio_ring_access_release(struct device *dev) | ||
| 105 | { | ||
| 106 | struct iio_ring_buffer *buf | ||
| 107 | = container_of(dev, struct iio_ring_buffer, dev); | ||
| 108 | cdev_del(&buf->access_handler.chrdev); | ||
| 109 | iio_device_free_chrdev_minor(MINOR(dev->devt)); | ||
| 110 | } | ||
| 111 | EXPORT_SYMBOL(iio_ring_access_release); | ||
| 112 | |||
| 113 | static inline int | ||
| 114 | __iio_request_ring_buffer_chrdev(struct iio_ring_buffer *buf, | ||
| 115 | struct module *owner, | ||
| 116 | int id) | ||
| 117 | { | ||
| 118 | int ret; | ||
| 119 | |||
| 120 | buf->access_handler.flags = 0; | ||
| 121 | buf->dev.bus = &iio_bus_type; | ||
| 122 | device_initialize(&buf->dev); | ||
| 123 | |||
| 124 | ret = iio_device_get_chrdev_minor(); | ||
| 125 | if (ret < 0) | ||
| 126 | goto error_device_put; | ||
| 127 | |||
| 128 | buf->dev.devt = MKDEV(MAJOR(iio_devt), ret); | ||
| 129 | dev_set_name(&buf->dev, "%s:buffer%d", | ||
| 130 | dev_name(buf->dev.parent), | ||
| 131 | id); | ||
| 132 | ret = device_add(&buf->dev); | ||
| 133 | if (ret < 0) { | ||
| 134 | printk(KERN_ERR "failed to add the ring dev\n"); | ||
| 135 | goto error_device_put; | ||
| 136 | } | ||
| 137 | cdev_init(&buf->access_handler.chrdev, &iio_ring_fileops); | ||
| 138 | buf->access_handler.chrdev.owner = owner; | ||
| 139 | ret = cdev_add(&buf->access_handler.chrdev, buf->dev.devt, 1); | ||
| 140 | if (ret) { | ||
| 141 | printk(KERN_ERR "failed to allocate ring chrdev\n"); | ||
| 142 | goto error_device_unregister; | ||
| 143 | } | ||
| 144 | return 0; | ||
| 145 | |||
| 146 | error_device_unregister: | ||
| 147 | device_unregister(&buf->dev); | ||
| 148 | error_device_put: | ||
| 149 | put_device(&buf->dev); | ||
| 150 | |||
| 151 | return ret; | ||
| 152 | } | ||
| 153 | |||
| 154 | static void __iio_free_ring_buffer_chrdev(struct iio_ring_buffer *buf) | ||
| 155 | { | ||
| 156 | device_unregister(&buf->dev); | ||
| 157 | } | ||
| 158 | |||
| 159 | void iio_ring_buffer_init(struct iio_ring_buffer *ring, | ||
| 160 | struct iio_dev *dev_info) | ||
| 161 | { | ||
| 162 | ring->indio_dev = dev_info; | ||
| 163 | ring->access_handler.private = ring; | ||
| 164 | init_waitqueue_head(&ring->pollq); | ||
| 165 | } | ||
| 166 | EXPORT_SYMBOL(iio_ring_buffer_init); | ||
| 167 | |||
| 168 | static ssize_t iio_show_scan_index(struct device *dev, | ||
| 169 | struct device_attribute *attr, | ||
| 170 | char *buf) | ||
| 171 | { | ||
| 172 | return sprintf(buf, "%u\n", to_iio_dev_attr(attr)->c->scan_index); | ||
| 173 | } | ||
| 174 | |||
| 175 | static ssize_t iio_show_fixed_type(struct device *dev, | ||
| 176 | struct device_attribute *attr, | ||
| 177 | char *buf) | ||
| 178 | { | ||
| 179 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 180 | return sprintf(buf, "%c%d/%d>>%u\n", | ||
| 181 | this_attr->c->scan_type.sign, | ||
| 182 | this_attr->c->scan_type.realbits, | ||
| 183 | this_attr->c->scan_type.storagebits, | ||
| 184 | this_attr->c->scan_type.shift); | ||
| 185 | } | ||
| 186 | |||
| 187 | static ssize_t iio_scan_el_show(struct device *dev, | ||
| 188 | struct device_attribute *attr, | ||
| 189 | char *buf) | ||
| 190 | { | ||
| 191 | int ret; | ||
| 192 | struct iio_ring_buffer *ring = dev_get_drvdata(dev); | ||
| 193 | |||
| 194 | ret = iio_scan_mask_query(ring, to_iio_dev_attr(attr)->address); | ||
| 195 | if (ret < 0) | ||
| 196 | return ret; | ||
| 197 | return sprintf(buf, "%d\n", ret); | ||
| 198 | } | ||
| 199 | |||
| 200 | static int iio_scan_mask_clear(struct iio_ring_buffer *ring, int bit) | ||
| 201 | { | ||
| 202 | if (bit > IIO_MAX_SCAN_LENGTH) | ||
| 203 | return -EINVAL; | ||
| 204 | ring->scan_mask &= ~(1 << bit); | ||
| 205 | ring->scan_count--; | ||
| 206 | return 0; | ||
| 207 | } | ||
| 208 | |||
| 209 | static ssize_t iio_scan_el_store(struct device *dev, | ||
| 210 | struct device_attribute *attr, | ||
| 211 | const char *buf, | ||
| 212 | size_t len) | ||
| 213 | { | ||
| 214 | int ret = 0; | ||
| 215 | bool state; | ||
| 216 | struct iio_ring_buffer *ring = dev_get_drvdata(dev); | ||
| 217 | struct iio_dev *indio_dev = ring->indio_dev; | ||
| 218 | struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); | ||
| 219 | |||
| 220 | state = !(buf[0] == '0'); | ||
| 221 | mutex_lock(&indio_dev->mlock); | ||
| 222 | if (indio_dev->currentmode == INDIO_RING_TRIGGERED) { | ||
| 223 | ret = -EBUSY; | ||
| 224 | goto error_ret; | ||
| 225 | } | ||
| 226 | ret = iio_scan_mask_query(ring, this_attr->address); | ||
| 227 | if (ret < 0) | ||
| 228 | goto error_ret; | ||
| 229 | if (!state && ret) { | ||
| 230 | ret = iio_scan_mask_clear(ring, this_attr->address); | ||
| 231 | if (ret) | ||
| 232 | goto error_ret; | ||
| 233 | } else if (state && !ret) { | ||
| 234 | ret = iio_scan_mask_set(ring, this_attr->address); | ||
| 235 | if (ret) | ||
| 236 | goto error_ret; | ||
| 237 | } | ||
| 238 | |||
| 239 | error_ret: | ||
| 240 | mutex_unlock(&indio_dev->mlock); | ||
| 241 | |||
| 242 | return ret ? ret : len; | ||
| 243 | |||
| 244 | } | ||
| 245 | |||
| 246 | static ssize_t iio_scan_el_ts_show(struct device *dev, | ||
| 247 | struct device_attribute *attr, | ||
| 248 | char *buf) | ||
| 249 | { | ||
| 250 | struct iio_ring_buffer *ring = dev_get_drvdata(dev); | ||
| 251 | return sprintf(buf, "%d\n", ring->scan_timestamp); | ||
| 252 | } | ||
| 253 | |||
| 254 | static ssize_t iio_scan_el_ts_store(struct device *dev, | ||
| 255 | struct device_attribute *attr, | ||
| 256 | const char *buf, | ||
| 257 | size_t len) | ||
| 258 | { | ||
| 259 | int ret = 0; | ||
| 260 | struct iio_ring_buffer *ring = dev_get_drvdata(dev); | ||
| 261 | struct iio_dev *indio_dev = ring->indio_dev; | ||
| 262 | bool state; | ||
| 263 | state = !(buf[0] == '0'); | ||
| 264 | mutex_lock(&indio_dev->mlock); | ||
| 265 | if (indio_dev->currentmode == INDIO_RING_TRIGGERED) { | ||
| 266 | ret = -EBUSY; | ||
| 267 | goto error_ret; | ||
| 268 | } | ||
| 269 | ring->scan_timestamp = state; | ||
| 270 | error_ret: | ||
| 271 | mutex_unlock(&indio_dev->mlock); | ||
| 272 | |||
| 273 | return ret ? ret : len; | ||
| 274 | } | ||
| 275 | |||
| 276 | static int iio_ring_add_channel_sysfs(struct iio_ring_buffer *ring, | ||
| 277 | const struct iio_chan_spec *chan) | ||
| 278 | { | ||
| 279 | int ret; | ||
| 280 | |||
| 281 | ret = __iio_add_chan_devattr("index", "scan_elements", | ||
| 282 | chan, | ||
| 283 | &iio_show_scan_index, | ||
| 284 | NULL, | ||
| 285 | 0, | ||
| 286 | 0, | ||
| 287 | &ring->dev, | ||
| 288 | &ring->scan_el_dev_attr_list); | ||
| 289 | if (ret) | ||
| 290 | goto error_ret; | ||
| 291 | |||
| 292 | ret = __iio_add_chan_devattr("type", "scan_elements", | ||
| 293 | chan, | ||
| 294 | &iio_show_fixed_type, | ||
| 295 | NULL, | ||
| 296 | 0, | ||
| 297 | 0, | ||
| 298 | &ring->dev, | ||
| 299 | &ring->scan_el_dev_attr_list); | ||
| 300 | if (ret) | ||
| 301 | goto error_ret; | ||
| 302 | |||
| 303 | if (chan->type != IIO_TIMESTAMP) | ||
| 304 | ret = __iio_add_chan_devattr("en", "scan_elements", | ||
| 305 | chan, | ||
| 306 | &iio_scan_el_show, | ||
| 307 | &iio_scan_el_store, | ||
| 308 | chan->scan_index, | ||
| 309 | 0, | ||
| 310 | &ring->dev, | ||
| 311 | &ring->scan_el_dev_attr_list); | ||
| 312 | else | ||
| 313 | ret = __iio_add_chan_devattr("en", "scan_elements", | ||
| 314 | chan, | ||
| 315 | &iio_scan_el_ts_show, | ||
| 316 | &iio_scan_el_ts_store, | ||
| 317 | chan->scan_index, | ||
| 318 | 0, | ||
| 319 | &ring->dev, | ||
| 320 | &ring->scan_el_dev_attr_list); | ||
| 321 | error_ret: | ||
| 322 | return ret; | ||
| 323 | } | ||
| 324 | |||
| 325 | static void iio_ring_remove_and_free_scan_dev_attr(struct iio_ring_buffer *ring, | ||
| 326 | struct iio_dev_attr *p) | ||
| 327 | { | ||
| 328 | sysfs_remove_file_from_group(&ring->dev.kobj, | ||
| 329 | &p->dev_attr.attr, "scan_elements"); | ||
| 330 | kfree(p->dev_attr.attr.name); | ||
| 331 | kfree(p); | ||
| 332 | } | ||
| 333 | |||
| 334 | static struct attribute *iio_scan_el_dummy_attrs[] = { | ||
| 335 | NULL | ||
| 336 | }; | ||
| 337 | |||
| 338 | static struct attribute_group iio_scan_el_dummy_group = { | ||
| 339 | .name = "scan_elements", | ||
| 340 | .attrs = iio_scan_el_dummy_attrs | ||
| 341 | }; | ||
| 342 | |||
| 343 | static void __iio_ring_attr_cleanup(struct iio_ring_buffer *ring) | ||
| 344 | { | ||
| 345 | struct iio_dev_attr *p, *n; | ||
| 346 | int anydynamic = !list_empty(&ring->scan_el_dev_attr_list); | ||
| 347 | list_for_each_entry_safe(p, n, | ||
| 348 | &ring->scan_el_dev_attr_list, l) | ||
| 349 | iio_ring_remove_and_free_scan_dev_attr(ring, p); | ||
| 350 | |||
| 351 | if (ring->scan_el_attrs) | ||
| 352 | sysfs_remove_group(&ring->dev.kobj, | ||
| 353 | ring->scan_el_attrs); | ||
| 354 | else if (anydynamic) | ||
| 355 | sysfs_remove_group(&ring->dev.kobj, | ||
| 356 | &iio_scan_el_dummy_group); | ||
| 357 | } | ||
| 358 | |||
| 359 | int iio_ring_buffer_register_ex(struct iio_ring_buffer *ring, int id, | ||
| 360 | const struct iio_chan_spec *channels, | ||
| 361 | int num_channels) | ||
| 362 | { | ||
| 363 | int ret, i; | ||
| 364 | |||
| 365 | ret = __iio_request_ring_buffer_chrdev(ring, ring->owner, id); | ||
| 366 | if (ret) | ||
| 367 | goto error_ret; | ||
| 368 | |||
| 369 | if (ring->scan_el_attrs) { | ||
| 370 | ret = sysfs_create_group(&ring->dev.kobj, | ||
| 371 | ring->scan_el_attrs); | ||
| 372 | if (ret) { | ||
| 373 | dev_err(&ring->dev, | ||
| 374 | "Failed to add sysfs scan elements\n"); | ||
| 375 | goto error_free_ring_buffer_chrdev; | ||
| 376 | } | ||
| 377 | } else if (channels) { | ||
| 378 | ret = sysfs_create_group(&ring->dev.kobj, | ||
| 379 | &iio_scan_el_dummy_group); | ||
| 380 | if (ret) | ||
| 381 | goto error_free_ring_buffer_chrdev; | ||
| 382 | } | ||
| 383 | |||
| 384 | INIT_LIST_HEAD(&ring->scan_el_dev_attr_list); | ||
| 385 | if (channels) { | ||
| 386 | /* new magic */ | ||
| 387 | for (i = 0; i < num_channels; i++) { | ||
| 388 | ret = iio_ring_add_channel_sysfs(ring, &channels[i]); | ||
| 389 | if (ret < 0) | ||
| 390 | goto error_cleanup_dynamic; | ||
| 391 | } | ||
| 392 | } | ||
| 393 | |||
| 394 | return 0; | ||
| 395 | error_cleanup_dynamic: | ||
| 396 | __iio_ring_attr_cleanup(ring); | ||
| 397 | error_free_ring_buffer_chrdev: | ||
| 398 | __iio_free_ring_buffer_chrdev(ring); | ||
| 399 | error_ret: | ||
| 400 | return ret; | ||
| 401 | } | ||
| 402 | EXPORT_SYMBOL(iio_ring_buffer_register_ex); | ||
| 403 | |||
| 404 | void iio_ring_buffer_unregister(struct iio_ring_buffer *ring) | ||
| 405 | { | ||
| 406 | __iio_ring_attr_cleanup(ring); | ||
| 407 | __iio_free_ring_buffer_chrdev(ring); | ||
| 408 | } | ||
| 409 | EXPORT_SYMBOL(iio_ring_buffer_unregister); | ||
| 410 | |||
| 411 | ssize_t iio_read_ring_length(struct device *dev, | ||
| 412 | struct device_attribute *attr, | ||
| 413 | char *buf) | ||
| 414 | { | ||
| 415 | struct iio_ring_buffer *ring = dev_get_drvdata(dev); | ||
| 416 | |||
| 417 | if (ring->access->get_length) | ||
| 418 | return sprintf(buf, "%d\n", | ||
| 419 | ring->access->get_length(ring)); | ||
| 420 | |||
| 421 | return 0; | ||
| 422 | } | ||
| 423 | EXPORT_SYMBOL(iio_read_ring_length); | ||
| 424 | |||
| 425 | ssize_t iio_write_ring_length(struct device *dev, | ||
| 426 | struct device_attribute *attr, | ||
| 427 | const char *buf, | ||
| 428 | size_t len) | ||
| 429 | { | ||
| 430 | int ret; | ||
| 431 | ulong val; | ||
| 432 | struct iio_ring_buffer *ring = dev_get_drvdata(dev); | ||
| 433 | |||
| 434 | ret = strict_strtoul(buf, 10, &val); | ||
| 435 | if (ret) | ||
| 436 | return ret; | ||
| 437 | |||
| 438 | if (ring->access->get_length) | ||
| 439 | if (val == ring->access->get_length(ring)) | ||
| 440 | return len; | ||
| 441 | |||
| 442 | if (ring->access->set_length) { | ||
| 443 | ring->access->set_length(ring, val); | ||
| 444 | if (ring->access->mark_param_change) | ||
| 445 | ring->access->mark_param_change(ring); | ||
| 446 | } | ||
| 447 | |||
| 448 | return len; | ||
| 449 | } | ||
| 450 | EXPORT_SYMBOL(iio_write_ring_length); | ||
| 451 | |||
| 452 | ssize_t iio_read_ring_bytes_per_datum(struct device *dev, | ||
| 453 | struct device_attribute *attr, | ||
| 454 | char *buf) | ||
| 455 | { | ||
| 456 | struct iio_ring_buffer *ring = dev_get_drvdata(dev); | ||
| 457 | |||
| 458 | if (ring->access->get_bytes_per_datum) | ||
| 459 | return sprintf(buf, "%d\n", | ||
| 460 | ring->access->get_bytes_per_datum(ring)); | ||
| 461 | |||
| 462 | return 0; | ||
| 463 | } | ||
| 464 | EXPORT_SYMBOL(iio_read_ring_bytes_per_datum); | ||
| 465 | |||
| 466 | ssize_t iio_store_ring_enable(struct device *dev, | ||
| 467 | struct device_attribute *attr, | ||
| 468 | const char *buf, | ||
| 469 | size_t len) | ||
| 470 | { | ||
| 471 | int ret; | ||
| 472 | bool requested_state, current_state; | ||
| 473 | int previous_mode; | ||
| 474 | struct iio_ring_buffer *ring = dev_get_drvdata(dev); | ||
| 475 | struct iio_dev *dev_info = ring->indio_dev; | ||
| 476 | |||
| 477 | mutex_lock(&dev_info->mlock); | ||
| 478 | previous_mode = dev_info->currentmode; | ||
| 479 | requested_state = !(buf[0] == '0'); | ||
| 480 | current_state = !!(previous_mode & INDIO_ALL_RING_MODES); | ||
| 481 | if (current_state == requested_state) { | ||
| 482 | printk(KERN_INFO "iio-ring, current state requested again\n"); | ||
| 483 | goto done; | ||
| 484 | } | ||
| 485 | if (requested_state) { | ||
| 486 | if (ring->setup_ops->preenable) { | ||
| 487 | ret = ring->setup_ops->preenable(dev_info); | ||
| 488 | if (ret) { | ||
| 489 | printk(KERN_ERR | ||
| 490 | "Buffer not started:" | ||
| 491 | "ring preenable failed\n"); | ||
| 492 | goto error_ret; | ||
| 493 | } | ||
| 494 | } | ||
| 495 | if (ring->access->request_update) { | ||
| 496 | ret = ring->access->request_update(ring); | ||
| 497 | if (ret) { | ||
| 498 | printk(KERN_INFO | ||
| 499 | "Buffer not started:" | ||
| 500 | "ring parameter update failed\n"); | ||
| 501 | goto error_ret; | ||
| 502 | } | ||
| 503 | } | ||
| 504 | if (ring->access->mark_in_use) | ||
| 505 | ring->access->mark_in_use(ring); | ||
| 506 | /* Definitely possible for devices to support both of these.*/ | ||
| 507 | if (dev_info->modes & INDIO_RING_TRIGGERED) { | ||
| 508 | if (!dev_info->trig) { | ||
| 509 | printk(KERN_INFO | ||
| 510 | "Buffer not started: no trigger\n"); | ||
| 511 | ret = -EINVAL; | ||
| 512 | if (ring->access->unmark_in_use) | ||
| 513 | ring->access->unmark_in_use(ring); | ||
| 514 | goto error_ret; | ||
| 515 | } | ||
| 516 | dev_info->currentmode = INDIO_RING_TRIGGERED; | ||
| 517 | } else if (dev_info->modes & INDIO_RING_HARDWARE_BUFFER) | ||
| 518 | dev_info->currentmode = INDIO_RING_HARDWARE_BUFFER; | ||
| 519 | else { /* should never be reached */ | ||
| 520 | ret = -EINVAL; | ||
| 521 | goto error_ret; | ||
| 522 | } | ||
| 523 | |||
| 524 | if (ring->setup_ops->postenable) { | ||
| 525 | ret = ring->setup_ops->postenable(dev_info); | ||
| 526 | if (ret) { | ||
| 527 | printk(KERN_INFO | ||
| 528 | "Buffer not started:" | ||
| 529 | "postenable failed\n"); | ||
| 530 | if (ring->access->unmark_in_use) | ||
| 531 | ring->access->unmark_in_use(ring); | ||
| 532 | dev_info->currentmode = previous_mode; | ||
| 533 | if (ring->setup_ops->postdisable) | ||
| 534 | ring->setup_ops->postdisable(dev_info); | ||
| 535 | goto error_ret; | ||
| 536 | } | ||
| 537 | } | ||
| 538 | } else { | ||
| 539 | if (ring->setup_ops->predisable) { | ||
| 540 | ret = ring->setup_ops->predisable(dev_info); | ||
| 541 | if (ret) | ||
| 542 | goto error_ret; | ||
| 543 | } | ||
| 544 | if (ring->access->unmark_in_use) | ||
| 545 | ring->access->unmark_in_use(ring); | ||
| 546 | dev_info->currentmode = INDIO_DIRECT_MODE; | ||
| 547 | if (ring->setup_ops->postdisable) { | ||
| 548 | ret = ring->setup_ops->postdisable(dev_info); | ||
| 549 | if (ret) | ||
| 550 | goto error_ret; | ||
| 551 | } | ||
| 552 | } | ||
| 553 | done: | ||
| 554 | mutex_unlock(&dev_info->mlock); | ||
| 555 | return len; | ||
| 556 | |||
| 557 | error_ret: | ||
| 558 | mutex_unlock(&dev_info->mlock); | ||
| 559 | return ret; | ||
| 560 | } | ||
| 561 | EXPORT_SYMBOL(iio_store_ring_enable); | ||
| 562 | |||
| 563 | ssize_t iio_show_ring_enable(struct device *dev, | ||
| 564 | struct device_attribute *attr, | ||
| 565 | char *buf) | ||
| 566 | { | ||
| 567 | struct iio_ring_buffer *ring = dev_get_drvdata(dev); | ||
| 568 | return sprintf(buf, "%d\n", !!(ring->indio_dev->currentmode | ||
| 569 | & INDIO_ALL_RING_MODES)); | ||
| 570 | } | ||
| 571 | EXPORT_SYMBOL(iio_show_ring_enable); | ||
| 572 | |||
| 573 | int iio_sw_ring_preenable(struct iio_dev *indio_dev) | ||
| 574 | { | ||
| 575 | struct iio_ring_buffer *ring = indio_dev->ring; | ||
| 576 | size_t size; | ||
| 577 | dev_dbg(&indio_dev->dev, "%s\n", __func__); | ||
| 578 | /* Check if there are any scan elements enabled, if not fail*/ | ||
| 579 | if (!(ring->scan_count || ring->scan_timestamp)) | ||
| 580 | return -EINVAL; | ||
| 581 | if (ring->scan_timestamp) | ||
| 582 | if (ring->scan_count) | ||
| 583 | /* Timestamp (aligned to s64) and data */ | ||
| 584 | size = (((ring->scan_count * ring->bpe) | ||
| 585 | + sizeof(s64) - 1) | ||
| 586 | & ~(sizeof(s64) - 1)) | ||
| 587 | + sizeof(s64); | ||
| 588 | else /* Timestamp only */ | ||
| 589 | size = sizeof(s64); | ||
| 590 | else /* Data only */ | ||
| 591 | size = ring->scan_count * ring->bpe; | ||
| 592 | ring->access->set_bytes_per_datum(ring, size); | ||
| 593 | |||
| 594 | return 0; | ||
| 595 | } | ||
| 596 | EXPORT_SYMBOL(iio_sw_ring_preenable); | ||
diff --git a/drivers/staging/iio/industrialio-trigger.c b/drivers/staging/iio/industrialio-trigger.c new file mode 100644 index 00000000000..90ca2df23ea --- /dev/null +++ b/drivers/staging/iio/industrialio-trigger.c | |||
| @@ -0,0 +1,525 @@ | |||
| 1 | /* The industrial I/O core, trigger handling functions | ||
| 2 | * | ||
| 3 | * Copyright (c) 2008 Jonathan Cameron | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 as published by | ||
| 7 | * the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/idr.h> | ||
| 13 | #include <linux/err.h> | ||
| 14 | #include <linux/device.h> | ||
| 15 | #include <linux/interrupt.h> | ||
| 16 | #include <linux/list.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | |||
| 19 | #include "iio.h" | ||
| 20 | #include "trigger.h" | ||
| 21 | #include "trigger_consumer.h" | ||
| 22 | |||
| 23 | /* RFC - Question of approach | ||
| 24 | * Make the common case (single sensor single trigger) | ||
| 25 | * simple by starting trigger capture from when first sensors | ||
| 26 | * is added. | ||
| 27 | * | ||
| 28 | * Complex simultaneous start requires use of 'hold' functionality | ||
| 29 | * of the trigger. (not implemented) | ||
| 30 | * | ||
| 31 | * Any other suggestions? | ||
| 32 | */ | ||
| 33 | |||
| 34 | static DEFINE_IDR(iio_trigger_idr); | ||
| 35 | static DEFINE_SPINLOCK(iio_trigger_idr_lock); | ||
| 36 | |||
| 37 | /* Single list of all available triggers */ | ||
| 38 | static LIST_HEAD(iio_trigger_list); | ||
| 39 | static DEFINE_MUTEX(iio_trigger_list_lock); | ||
| 40 | |||
| 41 | /** | ||
| 42 | * iio_trigger_read_name() - retrieve useful identifying name | ||
| 43 | **/ | ||
| 44 | static ssize_t iio_trigger_read_name(struct device *dev, | ||
| 45 | struct device_attribute *attr, | ||
| 46 | char *buf) | ||
| 47 | { | ||
| 48 | struct iio_trigger *trig = dev_get_drvdata(dev); | ||
| 49 | return sprintf(buf, "%s\n", trig->name); | ||
| 50 | } | ||
| 51 | |||
| 52 | static DEVICE_ATTR(name, S_IRUGO, iio_trigger_read_name, NULL); | ||
| 53 | |||
| 54 | /** | ||
| 55 | * iio_trigger_register_sysfs() - create a device for this trigger | ||
| 56 | * @trig_info: the trigger | ||
| 57 | * | ||
| 58 | * Also adds any control attribute registered by the trigger driver | ||
| 59 | **/ | ||
| 60 | static int iio_trigger_register_sysfs(struct iio_trigger *trig_info) | ||
| 61 | { | ||
| 62 | return sysfs_add_file_to_group(&trig_info->dev.kobj, | ||
| 63 | &dev_attr_name.attr, | ||
| 64 | NULL); | ||
| 65 | } | ||
| 66 | |||
| 67 | static void iio_trigger_unregister_sysfs(struct iio_trigger *trig_info) | ||
| 68 | { | ||
| 69 | sysfs_remove_file_from_group(&trig_info->dev.kobj, | ||
| 70 | &dev_attr_name.attr, | ||
| 71 | NULL); | ||
| 72 | } | ||
| 73 | |||
| 74 | |||
| 75 | /** | ||
| 76 | * iio_trigger_register_id() - get a unique id for this trigger | ||
| 77 | * @trig_info: the trigger | ||
| 78 | **/ | ||
| 79 | static int iio_trigger_register_id(struct iio_trigger *trig_info) | ||
| 80 | { | ||
| 81 | int ret = 0; | ||
| 82 | |||
| 83 | idr_again: | ||
| 84 | if (unlikely(idr_pre_get(&iio_trigger_idr, GFP_KERNEL) == 0)) | ||
| 85 | return -ENOMEM; | ||
| 86 | |||
| 87 | spin_lock(&iio_trigger_idr_lock); | ||
| 88 | ret = idr_get_new(&iio_trigger_idr, NULL, &trig_info->id); | ||
| 89 | spin_unlock(&iio_trigger_idr_lock); | ||
| 90 | if (unlikely(ret == -EAGAIN)) | ||
| 91 | goto idr_again; | ||
| 92 | else if (likely(!ret)) | ||
| 93 | trig_info->id = trig_info->id & MAX_ID_MASK; | ||
| 94 | |||
| 95 | return ret; | ||
| 96 | } | ||
| 97 | |||
| 98 | /** | ||
| 99 | * iio_trigger_unregister_id() - free up unique id for use by another trigger | ||
| 100 | * @trig_info: the trigger | ||
| 101 | **/ | ||
| 102 | static void iio_trigger_unregister_id(struct iio_trigger *trig_info) | ||
| 103 | { | ||
| 104 | spin_lock(&iio_trigger_idr_lock); | ||
| 105 | idr_remove(&iio_trigger_idr, trig_info->id); | ||
| 106 | spin_unlock(&iio_trigger_idr_lock); | ||
| 107 | } | ||
| 108 | |||
| 109 | int iio_trigger_register(struct iio_trigger *trig_info) | ||
| 110 | { | ||
| 111 | int ret; | ||
| 112 | |||
| 113 | ret = iio_trigger_register_id(trig_info); | ||
| 114 | if (ret) | ||
| 115 | goto error_ret; | ||
| 116 | /* Set the name used for the sysfs directory etc */ | ||
| 117 | dev_set_name(&trig_info->dev, "trigger%ld", | ||
| 118 | (unsigned long) trig_info->id); | ||
| 119 | |||
| 120 | ret = device_add(&trig_info->dev); | ||
| 121 | if (ret) | ||
| 122 | goto error_unregister_id; | ||
| 123 | |||
| 124 | ret = iio_trigger_register_sysfs(trig_info); | ||
| 125 | if (ret) | ||
| 126 | goto error_device_del; | ||
| 127 | |||
| 128 | /* Add to list of available triggers held by the IIO core */ | ||
| 129 | mutex_lock(&iio_trigger_list_lock); | ||
| 130 | list_add_tail(&trig_info->list, &iio_trigger_list); | ||
| 131 | mutex_unlock(&iio_trigger_list_lock); | ||
| 132 | |||
| 133 | return 0; | ||
| 134 | |||
| 135 | error_device_del: | ||
| 136 | device_del(&trig_info->dev); | ||
| 137 | error_unregister_id: | ||
| 138 | iio_trigger_unregister_id(trig_info); | ||
| 139 | error_ret: | ||
| 140 | return ret; | ||
| 141 | } | ||
| 142 | EXPORT_SYMBOL(iio_trigger_register); | ||
| 143 | |||
| 144 | void iio_trigger_unregister(struct iio_trigger *trig_info) | ||
| 145 | { | ||
| 146 | mutex_lock(&iio_trigger_list_lock); | ||
| 147 | list_del(&trig_info->list); | ||
| 148 | mutex_unlock(&iio_trigger_list_lock); | ||
| 149 | |||
| 150 | iio_trigger_unregister_sysfs(trig_info); | ||
| 151 | iio_trigger_unregister_id(trig_info); | ||
| 152 | /* Possible issue in here */ | ||
| 153 | device_unregister(&trig_info->dev); | ||
| 154 | } | ||
| 155 | EXPORT_SYMBOL(iio_trigger_unregister); | ||
| 156 | |||
| 157 | static struct iio_trigger *iio_trigger_find_by_name(const char *name, | ||
| 158 | size_t len) | ||
| 159 | { | ||
| 160 | struct iio_trigger *trig = NULL, *iter; | ||
| 161 | |||
| 162 | mutex_lock(&iio_trigger_list_lock); | ||
| 163 | list_for_each_entry(iter, &iio_trigger_list, list) | ||
| 164 | if (sysfs_streq(iter->name, name)) { | ||
| 165 | trig = iter; | ||
| 166 | break; | ||
| 167 | } | ||
| 168 | mutex_unlock(&iio_trigger_list_lock); | ||
| 169 | |||
| 170 | return trig; | ||
| 171 | } | ||
| 172 | |||
| 173 | void iio_trigger_poll(struct iio_trigger *trig, s64 time) | ||
| 174 | { | ||
| 175 | int i; | ||
| 176 | if (!trig->use_count) { | ||
| 177 | for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) | ||
| 178 | if (trig->subirqs[i].enabled) { | ||
| 179 | trig->use_count++; | ||
| 180 | generic_handle_irq(trig->subirq_base + i); | ||
| 181 | } | ||
| 182 | } | ||
| 183 | } | ||
| 184 | EXPORT_SYMBOL(iio_trigger_poll); | ||
| 185 | |||
| 186 | irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private) | ||
| 187 | { | ||
| 188 | iio_trigger_poll(private, iio_get_time_ns()); | ||
| 189 | return IRQ_HANDLED; | ||
| 190 | } | ||
| 191 | EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll); | ||
| 192 | |||
| 193 | void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time) | ||
| 194 | { | ||
| 195 | int i; | ||
| 196 | if (!trig->use_count) { | ||
| 197 | for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) | ||
| 198 | if (trig->subirqs[i].enabled) { | ||
| 199 | trig->use_count++; | ||
| 200 | handle_nested_irq(trig->subirq_base + i); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | } | ||
| 204 | EXPORT_SYMBOL(iio_trigger_poll_chained); | ||
| 205 | |||
| 206 | void iio_trigger_notify_done(struct iio_trigger *trig) | ||
| 207 | { | ||
| 208 | trig->use_count--; | ||
| 209 | if (trig->use_count == 0 && trig->try_reenable) | ||
| 210 | if (trig->try_reenable(trig)) { | ||
| 211 | /* Missed and interrupt so launch new poll now */ | ||
| 212 | iio_trigger_poll(trig, 0); | ||
| 213 | } | ||
| 214 | } | ||
| 215 | EXPORT_SYMBOL(iio_trigger_notify_done); | ||
| 216 | |||
| 217 | /* Trigger Consumer related functions */ | ||
| 218 | |||
| 219 | /* Complexity in here. With certain triggers (datardy) an acknowledgement | ||
| 220 | * may be needed if the pollfuncs do not include the data read for the | ||
| 221 | * triggering device. | ||
| 222 | * This is not currently handled. Alternative of not enabling trigger unless | ||
| 223 | * the relevant function is in there may be the best option. | ||
| 224 | */ | ||
| 225 | /* Worth protecting against double additions?*/ | ||
| 226 | int iio_trigger_attach_poll_func(struct iio_trigger *trig, | ||
| 227 | struct iio_poll_func *pf) | ||
| 228 | { | ||
| 229 | int ret = 0; | ||
| 230 | bool notinuse | ||
| 231 | = bitmap_empty(trig->pool, CONFIG_IIO_CONSUMERS_PER_TRIGGER); | ||
| 232 | |||
| 233 | pf->irq = iio_trigger_get_irq(trig); | ||
| 234 | ret = request_threaded_irq(pf->irq, pf->h, pf->thread, | ||
| 235 | pf->type, pf->name, | ||
| 236 | pf); | ||
| 237 | if (trig->set_trigger_state && notinuse) | ||
| 238 | ret = trig->set_trigger_state(trig, true); | ||
| 239 | |||
| 240 | return ret; | ||
| 241 | } | ||
| 242 | EXPORT_SYMBOL(iio_trigger_attach_poll_func); | ||
| 243 | |||
| 244 | int iio_trigger_dettach_poll_func(struct iio_trigger *trig, | ||
| 245 | struct iio_poll_func *pf) | ||
| 246 | { | ||
| 247 | int ret = 0; | ||
| 248 | bool no_other_users | ||
| 249 | = (bitmap_weight(trig->pool, | ||
| 250 | CONFIG_IIO_CONSUMERS_PER_TRIGGER) | ||
| 251 | == 1); | ||
| 252 | if (trig->set_trigger_state && no_other_users) { | ||
| 253 | ret = trig->set_trigger_state(trig, false); | ||
| 254 | if (ret) | ||
| 255 | goto error_ret; | ||
| 256 | } | ||
| 257 | iio_trigger_put_irq(trig, pf->irq); | ||
| 258 | free_irq(pf->irq, pf); | ||
| 259 | |||
| 260 | error_ret: | ||
| 261 | return ret; | ||
| 262 | } | ||
| 263 | EXPORT_SYMBOL(iio_trigger_dettach_poll_func); | ||
| 264 | |||
| 265 | irqreturn_t iio_pollfunc_store_time(int irq, void *p) | ||
| 266 | { | ||
| 267 | struct iio_poll_func *pf = p; | ||
| 268 | pf->timestamp = iio_get_time_ns(); | ||
| 269 | return IRQ_WAKE_THREAD; | ||
| 270 | } | ||
| 271 | EXPORT_SYMBOL(iio_pollfunc_store_time); | ||
| 272 | |||
| 273 | struct iio_poll_func | ||
| 274 | *iio_alloc_pollfunc(irqreturn_t (*h)(int irq, void *p), | ||
| 275 | irqreturn_t (*thread)(int irq, void *p), | ||
| 276 | int type, | ||
| 277 | void *private, | ||
| 278 | const char *fmt, | ||
| 279 | ...) | ||
| 280 | { | ||
| 281 | va_list vargs; | ||
| 282 | struct iio_poll_func *pf; | ||
| 283 | |||
| 284 | pf = kmalloc(sizeof *pf, GFP_KERNEL); | ||
| 285 | if (pf == NULL) | ||
| 286 | return NULL; | ||
| 287 | va_start(vargs, fmt); | ||
| 288 | pf->name = kvasprintf(GFP_KERNEL, fmt, vargs); | ||
| 289 | va_end(vargs); | ||
| 290 | if (pf->name == NULL) { | ||
| 291 | kfree(pf); | ||
| 292 | return NULL; | ||
| 293 | } | ||
| 294 | pf->h = h; | ||
| 295 | pf->thread = thread; | ||
| 296 | pf->type = type; | ||
| 297 | pf->private_data = private; | ||
| 298 | |||
| 299 | return pf; | ||
| 300 | } | ||
| 301 | EXPORT_SYMBOL_GPL(iio_alloc_pollfunc); | ||
| 302 | |||
| 303 | void iio_dealloc_pollfunc(struct iio_poll_func *pf) | ||
| 304 | { | ||
| 305 | kfree(pf->name); | ||
| 306 | kfree(pf); | ||
| 307 | } | ||
| 308 | EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc); | ||
| 309 | |||
| 310 | /** | ||
| 311 | * iio_trigger_read_currrent() - trigger consumer sysfs query which trigger | ||
| 312 | * | ||
| 313 | * For trigger consumers the current_trigger interface allows the trigger | ||
| 314 | * used by the device to be queried. | ||
| 315 | **/ | ||
| 316 | static ssize_t iio_trigger_read_current(struct device *dev, | ||
| 317 | struct device_attribute *attr, | ||
| 318 | char *buf) | ||
| 319 | { | ||
| 320 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 321 | int len = 0; | ||
| 322 | if (dev_info->trig) | ||
| 323 | len = sprintf(buf, | ||
| 324 | "%s\n", | ||
| 325 | dev_info->trig->name); | ||
| 326 | return len; | ||
| 327 | } | ||
| 328 | |||
| 329 | /** | ||
| 330 | * iio_trigger_write_current() trigger consumer sysfs set current trigger | ||
| 331 | * | ||
| 332 | * For trigger consumers the current_trigger interface allows the trigger | ||
| 333 | * used for this device to be specified at run time based on the triggers | ||
| 334 | * name. | ||
| 335 | **/ | ||
| 336 | static ssize_t iio_trigger_write_current(struct device *dev, | ||
| 337 | struct device_attribute *attr, | ||
| 338 | const char *buf, | ||
| 339 | size_t len) | ||
| 340 | { | ||
| 341 | struct iio_dev *dev_info = dev_get_drvdata(dev); | ||
| 342 | struct iio_trigger *oldtrig = dev_info->trig; | ||
| 343 | struct iio_trigger *trig; | ||
| 344 | int ret; | ||
| 345 | |||
| 346 | mutex_lock(&dev_info->mlock); | ||
| 347 | if (dev_info->currentmode == INDIO_RING_TRIGGERED) { | ||
| 348 | mutex_unlock(&dev_info->mlock); | ||
| 349 | return -EBUSY; | ||
| 350 | } | ||
| 351 | mutex_unlock(&dev_info->mlock); | ||
| 352 | |||
| 353 | trig = iio_trigger_find_by_name(buf, len); | ||
| 354 | |||
| 355 | if (trig && dev_info->info->validate_trigger) { | ||
| 356 | ret = dev_info->info->validate_trigger(dev_info, trig); | ||
| 357 | if (ret) | ||
| 358 | return ret; | ||
| 359 | } | ||
| 360 | |||
| 361 | if (trig && trig->validate_device) { | ||
| 362 | ret = trig->validate_device(trig, dev_info); | ||
| 363 | if (ret) | ||
| 364 | return ret; | ||
| 365 | } | ||
| 366 | |||
| 367 | dev_info->trig = trig; | ||
| 368 | |||
| 369 | if (oldtrig && dev_info->trig != oldtrig) | ||
| 370 | iio_put_trigger(oldtrig); | ||
| 371 | if (dev_info->trig) | ||
| 372 | iio_get_trigger(dev_info->trig); | ||
| 373 | |||
| 374 | return len; | ||
| 375 | } | ||
| 376 | |||
| 377 | static DEVICE_ATTR(current_trigger, S_IRUGO | S_IWUSR, | ||
| 378 | iio_trigger_read_current, | ||
| 379 | iio_trigger_write_current); | ||
| 380 | |||
| 381 | static struct attribute *iio_trigger_consumer_attrs[] = { | ||
| 382 | &dev_attr_current_trigger.attr, | ||
| 383 | NULL, | ||
| 384 | }; | ||
| 385 | |||
| 386 | static const struct attribute_group iio_trigger_consumer_attr_group = { | ||
| 387 | .name = "trigger", | ||
| 388 | .attrs = iio_trigger_consumer_attrs, | ||
| 389 | }; | ||
| 390 | |||
| 391 | static void iio_trig_release(struct device *device) | ||
| 392 | { | ||
| 393 | struct iio_trigger *trig = to_iio_trigger(device); | ||
| 394 | int i; | ||
| 395 | |||
| 396 | if (trig->subirq_base) { | ||
| 397 | for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) { | ||
| 398 | irq_modify_status(trig->subirq_base + i, | ||
| 399 | IRQ_NOAUTOEN, | ||
| 400 | IRQ_NOREQUEST | IRQ_NOPROBE); | ||
| 401 | irq_set_chip(trig->subirq_base + i, | ||
| 402 | NULL); | ||
| 403 | irq_set_handler(trig->subirq_base + i, | ||
| 404 | NULL); | ||
| 405 | } | ||
| 406 | |||
| 407 | irq_free_descs(trig->subirq_base, | ||
| 408 | CONFIG_IIO_CONSUMERS_PER_TRIGGER); | ||
| 409 | } | ||
| 410 | kfree(trig->name); | ||
| 411 | kfree(trig); | ||
| 412 | iio_put(); | ||
| 413 | } | ||
| 414 | |||
| 415 | static struct device_type iio_trig_type = { | ||
| 416 | .release = iio_trig_release, | ||
| 417 | }; | ||
| 418 | |||
| 419 | static void iio_trig_subirqmask(struct irq_data *d) | ||
| 420 | { | ||
| 421 | struct irq_chip *chip = irq_data_get_irq_chip(d); | ||
| 422 | struct iio_trigger *trig | ||
| 423 | = container_of(chip, | ||
| 424 | struct iio_trigger, subirq_chip); | ||
| 425 | trig->subirqs[d->irq - trig->subirq_base].enabled = false; | ||
| 426 | } | ||
| 427 | |||
| 428 | static void iio_trig_subirqunmask(struct irq_data *d) | ||
| 429 | { | ||
| 430 | struct irq_chip *chip = irq_data_get_irq_chip(d); | ||
| 431 | struct iio_trigger *trig | ||
| 432 | = container_of(chip, | ||
| 433 | struct iio_trigger, subirq_chip); | ||
| 434 | trig->subirqs[d->irq - trig->subirq_base].enabled = true; | ||
| 435 | } | ||
| 436 | |||
| 437 | struct iio_trigger *iio_allocate_trigger(const char *fmt, ...) | ||
| 438 | { | ||
| 439 | va_list vargs; | ||
| 440 | struct iio_trigger *trig; | ||
| 441 | trig = kzalloc(sizeof *trig, GFP_KERNEL); | ||
| 442 | if (trig) { | ||
| 443 | int i; | ||
| 444 | trig->dev.type = &iio_trig_type; | ||
| 445 | trig->dev.bus = &iio_bus_type; | ||
| 446 | device_initialize(&trig->dev); | ||
| 447 | dev_set_drvdata(&trig->dev, (void *)trig); | ||
| 448 | |||
| 449 | mutex_init(&trig->pool_lock); | ||
| 450 | trig->subirq_base | ||
| 451 | = irq_alloc_descs(-1, 0, | ||
| 452 | CONFIG_IIO_CONSUMERS_PER_TRIGGER, | ||
| 453 | 0); | ||
| 454 | if (trig->subirq_base < 0) { | ||
| 455 | kfree(trig); | ||
| 456 | return NULL; | ||
| 457 | } | ||
| 458 | va_start(vargs, fmt); | ||
| 459 | trig->name = kvasprintf(GFP_KERNEL, fmt, vargs); | ||
| 460 | va_end(vargs); | ||
| 461 | if (trig->name == NULL) { | ||
| 462 | irq_free_descs(trig->subirq_base, | ||
| 463 | CONFIG_IIO_CONSUMERS_PER_TRIGGER); | ||
| 464 | kfree(trig); | ||
| 465 | return NULL; | ||
| 466 | } | ||
| 467 | trig->subirq_chip.name = trig->name; | ||
| 468 | trig->subirq_chip.irq_mask = &iio_trig_subirqmask; | ||
| 469 | trig->subirq_chip.irq_unmask = &iio_trig_subirqunmask; | ||
| 470 | for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) { | ||
| 471 | irq_set_chip(trig->subirq_base + i, | ||
| 472 | &trig->subirq_chip); | ||
| 473 | irq_set_handler(trig->subirq_base + i, | ||
| 474 | &handle_simple_irq); | ||
| 475 | irq_modify_status(trig->subirq_base + i, | ||
| 476 | IRQ_NOREQUEST | IRQ_NOAUTOEN, | ||
| 477 | IRQ_NOPROBE); | ||
| 478 | } | ||
| 479 | iio_get(); | ||
| 480 | } | ||
| 481 | return trig; | ||
| 482 | } | ||
| 483 | EXPORT_SYMBOL(iio_allocate_trigger); | ||
| 484 | |||
| 485 | void iio_free_trigger(struct iio_trigger *trig) | ||
| 486 | { | ||
| 487 | if (trig) | ||
| 488 | put_device(&trig->dev); | ||
| 489 | } | ||
| 490 | EXPORT_SYMBOL(iio_free_trigger); | ||
| 491 | |||
| 492 | int iio_device_register_trigger_consumer(struct iio_dev *dev_info) | ||
| 493 | { | ||
| 494 | int ret; | ||
| 495 | ret = sysfs_create_group(&dev_info->dev.kobj, | ||
| 496 | &iio_trigger_consumer_attr_group); | ||
| 497 | return ret; | ||
| 498 | } | ||
| 499 | EXPORT_SYMBOL(iio_device_register_trigger_consumer); | ||
| 500 | |||
| 501 | int iio_device_unregister_trigger_consumer(struct iio_dev *dev_info) | ||
| 502 | { | ||
| 503 | sysfs_remove_group(&dev_info->dev.kobj, | ||
| 504 | &iio_trigger_consumer_attr_group); | ||
| 505 | return 0; | ||
| 506 | } | ||
| 507 | EXPORT_SYMBOL(iio_device_unregister_trigger_consumer); | ||
| 508 | |||
| 509 | int iio_triggered_ring_postenable(struct iio_dev *indio_dev) | ||
| 510 | { | ||
| 511 | return indio_dev->trig | ||
| 512 | ? iio_trigger_attach_poll_func(indio_dev->trig, | ||
| 513 | indio_dev->pollfunc) | ||
| 514 | : 0; | ||
| 515 | } | ||
| 516 | EXPORT_SYMBOL(iio_triggered_ring_postenable); | ||
| 517 | |||
| 518 | int iio_triggered_ring_predisable(struct iio_dev *indio_dev) | ||
| 519 | { | ||
| 520 | return indio_dev->trig | ||
| 521 | ? iio_trigger_dettach_poll_func(indio_dev->trig, | ||
| 522 | indio_dev->pollfunc) | ||
| 523 | : 0; | ||
| 524 | } | ||
| 525 | EXPORT_SYMBOL(iio_triggered_ring_predisable); | ||
diff --git a/drivers/staging/iio/kfifo_buf.c b/drivers/staging/iio/kfifo_buf.c new file mode 100644 index 00000000000..6002368fdcf --- /dev/null +++ b/drivers/staging/iio/kfifo_buf.c | |||
| @@ -0,0 +1,203 @@ | |||
| 1 | #include <linux/slab.h> | ||
| 2 | #include <linux/kernel.h> | ||
| 3 | #include <linux/module.h> | ||
| 4 | #include <linux/device.h> | ||
| 5 | #include <linux/workqueue.h> | ||
| 6 | #include <linux/kfifo.h> | ||
| 7 | #include <linux/mutex.h> | ||
| 8 | |||
| 9 | #include "kfifo_buf.h" | ||
| 10 | |||
| 11 | #define iio_to_kfifo(r) container_of(r, struct iio_kfifo, ring) | ||
| 12 | |||
| 13 | static inline int __iio_allocate_kfifo(struct iio_kfifo *buf, | ||
| 14 | int bytes_per_datum, int length) | ||
| 15 | { | ||
| 16 | if ((length == 0) || (bytes_per_datum == 0)) | ||
| 17 | return -EINVAL; | ||
| 18 | |||
| 19 | __iio_update_ring_buffer(&buf->ring, bytes_per_datum, length); | ||
| 20 | return kfifo_alloc(&buf->kf, bytes_per_datum*length, GFP_KERNEL); | ||
| 21 | } | ||
| 22 | |||
| 23 | static int iio_request_update_kfifo(struct iio_ring_buffer *r) | ||
| 24 | { | ||
| 25 | int ret = 0; | ||
| 26 | struct iio_kfifo *buf = iio_to_kfifo(r); | ||
| 27 | |||
| 28 | mutex_lock(&buf->use_lock); | ||
| 29 | if (!buf->update_needed) | ||
| 30 | goto error_ret; | ||
| 31 | if (buf->use_count) { | ||
| 32 | ret = -EAGAIN; | ||
| 33 | goto error_ret; | ||
| 34 | } | ||
| 35 | kfifo_free(&buf->kf); | ||
| 36 | ret = __iio_allocate_kfifo(buf, buf->ring.bytes_per_datum, | ||
| 37 | buf->ring.length); | ||
| 38 | error_ret: | ||
| 39 | mutex_unlock(&buf->use_lock); | ||
| 40 | return ret; | ||
| 41 | } | ||
| 42 | |||
| 43 | static void iio_mark_kfifo_in_use(struct iio_ring_buffer *r) | ||
| 44 | { | ||
| 45 | struct iio_kfifo *buf = iio_to_kfifo(r); | ||
| 46 | mutex_lock(&buf->use_lock); | ||
| 47 | buf->use_count++; | ||
| 48 | mutex_unlock(&buf->use_lock); | ||
| 49 | } | ||
| 50 | |||
| 51 | static void iio_unmark_kfifo_in_use(struct iio_ring_buffer *r) | ||
| 52 | { | ||
| 53 | struct iio_kfifo *buf = iio_to_kfifo(r); | ||
| 54 | mutex_lock(&buf->use_lock); | ||
| 55 | buf->use_count--; | ||
| 56 | mutex_unlock(&buf->use_lock); | ||
| 57 | } | ||
| 58 | |||
| 59 | static int iio_get_length_kfifo(struct iio_ring_buffer *r) | ||
| 60 | { | ||
| 61 | return r->length; | ||
| 62 | } | ||
| 63 | |||
| 64 | static inline void __iio_init_kfifo(struct iio_kfifo *kf) | ||
| 65 | { | ||
| 66 | mutex_init(&kf->use_lock); | ||
| 67 | } | ||
| 68 | |||
| 69 | static IIO_RING_ENABLE_ATTR; | ||
| 70 | static IIO_RING_BYTES_PER_DATUM_ATTR; | ||
| 71 | static IIO_RING_LENGTH_ATTR; | ||
| 72 | |||
| 73 | static struct attribute *iio_kfifo_attributes[] = { | ||
| 74 | &dev_attr_length.attr, | ||
| 75 | &dev_attr_bytes_per_datum.attr, | ||
| 76 | &dev_attr_enable.attr, | ||
| 77 | NULL, | ||
| 78 | }; | ||
| 79 | |||
| 80 | static struct attribute_group iio_kfifo_attribute_group = { | ||
| 81 | .attrs = iio_kfifo_attributes, | ||
| 82 | }; | ||
| 83 | |||
| 84 | static const struct attribute_group *iio_kfifo_attribute_groups[] = { | ||
| 85 | &iio_kfifo_attribute_group, | ||
| 86 | NULL | ||
| 87 | }; | ||
| 88 | |||
| 89 | static void iio_kfifo_release(struct device *dev) | ||
| 90 | { | ||
| 91 | struct iio_ring_buffer *r = to_iio_ring_buffer(dev); | ||
| 92 | struct iio_kfifo *kf = iio_to_kfifo(r); | ||
| 93 | kfifo_free(&kf->kf); | ||
| 94 | kfree(kf); | ||
| 95 | } | ||
| 96 | |||
| 97 | static struct device_type iio_kfifo_type = { | ||
| 98 | .release = iio_kfifo_release, | ||
| 99 | .groups = iio_kfifo_attribute_groups, | ||
| 100 | }; | ||
| 101 | |||
| 102 | struct iio_ring_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev) | ||
| 103 | { | ||
| 104 | struct iio_kfifo *kf; | ||
| 105 | |||
| 106 | kf = kzalloc(sizeof *kf, GFP_KERNEL); | ||
| 107 | if (!kf) | ||
| 108 | return NULL; | ||
| 109 | kf->update_needed = true; | ||
| 110 | iio_ring_buffer_init(&kf->ring, indio_dev); | ||
| 111 | __iio_init_kfifo(kf); | ||
| 112 | kf->ring.dev.type = &iio_kfifo_type; | ||
| 113 | kf->ring.dev.parent = &indio_dev->dev; | ||
| 114 | dev_set_drvdata(&kf->ring.dev, (void *)&(kf->ring)); | ||
| 115 | |||
| 116 | return &kf->ring; | ||
| 117 | } | ||
| 118 | EXPORT_SYMBOL(iio_kfifo_allocate); | ||
| 119 | |||
| 120 | static int iio_get_bytes_per_datum_kfifo(struct iio_ring_buffer *r) | ||
| 121 | { | ||
| 122 | return r->bytes_per_datum; | ||
| 123 | } | ||
| 124 | |||
| 125 | static int iio_set_bytes_per_datum_kfifo(struct iio_ring_buffer *r, size_t bpd) | ||
| 126 | { | ||
| 127 | if (r->bytes_per_datum != bpd) { | ||
| 128 | r->bytes_per_datum = bpd; | ||
| 129 | if (r->access->mark_param_change) | ||
| 130 | r->access->mark_param_change(r); | ||
| 131 | } | ||
| 132 | return 0; | ||
| 133 | } | ||
| 134 | |||
| 135 | static int iio_mark_update_needed_kfifo(struct iio_ring_buffer *r) | ||
| 136 | { | ||
| 137 | struct iio_kfifo *kf = iio_to_kfifo(r); | ||
| 138 | kf->update_needed = true; | ||
| 139 | return 0; | ||
| 140 | } | ||
| 141 | |||
| 142 | static int iio_set_length_kfifo(struct iio_ring_buffer *r, int length) | ||
| 143 | { | ||
| 144 | if (r->length != length) { | ||
| 145 | r->length = length; | ||
| 146 | if (r->access->mark_param_change) | ||
| 147 | r->access->mark_param_change(r); | ||
| 148 | } | ||
| 149 | return 0; | ||
| 150 | } | ||
| 151 | |||
| 152 | void iio_kfifo_free(struct iio_ring_buffer *r) | ||
| 153 | { | ||
| 154 | if (r) | ||
| 155 | iio_put_ring_buffer(r); | ||
| 156 | } | ||
| 157 | EXPORT_SYMBOL(iio_kfifo_free); | ||
| 158 | |||
| 159 | static int iio_store_to_kfifo(struct iio_ring_buffer *r, | ||
| 160 | u8 *data, | ||
| 161 | s64 timestamp) | ||
| 162 | { | ||
| 163 | int ret; | ||
| 164 | struct iio_kfifo *kf = iio_to_kfifo(r); | ||
| 165 | u8 *datal = kmalloc(r->bytes_per_datum, GFP_KERNEL); | ||
| 166 | memcpy(datal, data, r->bytes_per_datum - sizeof(timestamp)); | ||
| 167 | memcpy(datal + r->bytes_per_datum - sizeof(timestamp), | ||
| 168 | ×tamp, sizeof(timestamp)); | ||
| 169 | ret = kfifo_in(&kf->kf, data, r->bytes_per_datum); | ||
| 170 | if (ret != r->bytes_per_datum) { | ||
| 171 | kfree(datal); | ||
| 172 | return -EBUSY; | ||
| 173 | } | ||
| 174 | kfree(datal); | ||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | static int iio_read_first_n_kfifo(struct iio_ring_buffer *r, | ||
| 179 | size_t n, char __user *buf) | ||
| 180 | { | ||
| 181 | int ret, copied; | ||
| 182 | struct iio_kfifo *kf = iio_to_kfifo(r); | ||
| 183 | |||
| 184 | ret = kfifo_to_user(&kf->kf, buf, r->bytes_per_datum*n, &copied); | ||
| 185 | |||
| 186 | return copied; | ||
| 187 | } | ||
| 188 | |||
| 189 | const struct iio_ring_access_funcs kfifo_access_funcs = { | ||
| 190 | .mark_in_use = &iio_mark_kfifo_in_use, | ||
| 191 | .unmark_in_use = &iio_unmark_kfifo_in_use, | ||
| 192 | .store_to = &iio_store_to_kfifo, | ||
| 193 | .read_first_n = &iio_read_first_n_kfifo, | ||
| 194 | .mark_param_change = &iio_mark_update_needed_kfifo, | ||
| 195 | .request_update = &iio_request_update_kfifo, | ||
| 196 | .get_bytes_per_datum = &iio_get_bytes_per_datum_kfifo, | ||
| 197 | .set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo, | ||
| 198 | .get_length = &iio_get_length_kfifo, | ||
| 199 | .set_length = &iio_set_length_kfifo, | ||
| 200 | }; | ||
| 201 | EXPORT_SYMBOL(kfifo_access_funcs); | ||
| 202 | |||
| 203 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/staging/iio/kfifo_buf.h b/drivers/staging/iio/kfifo_buf.h new file mode 100644 index 00000000000..aac30539b2c --- /dev/null +++ b/drivers/staging/iio/kfifo_buf.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | |||
| 2 | #include <linux/kfifo.h> | ||
| 3 | #include "iio.h" | ||
| 4 | #include "ring_generic.h" | ||
| 5 | |||
| 6 | struct iio_kfifo { | ||
| 7 | struct iio_ring_buffer ring; | ||
| 8 | struct kfifo kf; | ||
| 9 | int use_count; | ||
| 10 | int update_needed; | ||
| 11 | struct mutex use_lock; | ||
| 12 | }; | ||
| 13 | |||
| 14 | extern const struct iio_ring_access_funcs kfifo_access_funcs; | ||
| 15 | |||
| 16 | struct iio_ring_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev); | ||
| 17 | void iio_kfifo_free(struct iio_ring_buffer *r); | ||
| 18 | |||
diff --git a/drivers/staging/iio/light/ltr558als.c b/drivers/staging/iio/light/ltr558als.c new file mode 100644 index 00000000000..01e410b191f --- /dev/null +++ b/drivers/staging/iio/light/ltr558als.c | |||
| @@ -0,0 +1,883 @@ | |||
| 1 | /* Lite-On LTR-558ALS Linux Driver | ||
| 2 | * | ||
| 3 | * Copyright (c) 2012, NVIDIA Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/delay.h> | ||
| 12 | #include <linux/earlysuspend.h> | ||
| 13 | #include <linux/fs.h> | ||
| 14 | #include <linux/i2c.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/input.h> | ||
| 17 | #include <linux/irq.h> | ||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/mutex.h> | ||
| 21 | #include <linux/pm.h> | ||
| 22 | #include <linux/wakelock.h> | ||
| 23 | #include <linux/interrupt.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | #include <asm/gpio.h> | ||
| 26 | #include <asm/uaccess.h> | ||
| 27 | |||
| 28 | #include "ltr558als.h" | ||
| 29 | #include "../iio.h" | ||
| 30 | |||
| 31 | #define DRIVER_VERSION "1.0" | ||
| 32 | #define DEVICE_NAME "LTR_558ALS" | ||
| 33 | |||
| 34 | struct ltr558_chip { | ||
| 35 | struct i2c_client *client; | ||
| 36 | struct mutex lock; | ||
| 37 | struct iio_dev *indio_dev; | ||
| 38 | int irq; | ||
| 39 | |||
| 40 | bool is_als_enable; | ||
| 41 | bool als_enabled_before_suspend; | ||
| 42 | int als_gainrange; | ||
| 43 | int als_persist; | ||
| 44 | int als_reading; | ||
| 45 | int als_high_thres; | ||
| 46 | int als_low_thres; | ||
| 47 | |||
| 48 | bool is_prox_enable; | ||
| 49 | bool prox_enabled_before_suspend; | ||
| 50 | int ps_gainrange; | ||
| 51 | int prox_persist; | ||
| 52 | int prox_reading; | ||
| 53 | int prox_low_thres; | ||
| 54 | int prox_high_thres; | ||
| 55 | }; | ||
| 56 | |||
| 57 | static int ltr558_i2c_read_reg(struct i2c_client *client, u8 regnum) | ||
| 58 | { | ||
| 59 | return i2c_smbus_read_byte_data(client, regnum); | ||
| 60 | } | ||
| 61 | |||
| 62 | static int ltr558_i2c_write_reg(struct i2c_client *client, u8 regnum, u8 value) | ||
| 63 | { | ||
| 64 | int writeerror; | ||
| 65 | |||
| 66 | writeerror = i2c_smbus_write_byte_data(client, regnum, value); | ||
| 67 | if (writeerror < 0) | ||
| 68 | return writeerror; | ||
| 69 | else | ||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int ltr558_ps_enable(struct i2c_client *client, int gainrange) | ||
| 74 | { | ||
| 75 | int error; | ||
| 76 | int setgain; | ||
| 77 | |||
| 78 | switch (gainrange) { | ||
| 79 | case PS_RANGE4: | ||
| 80 | setgain = MODE_PS_ON_Gain4; | ||
| 81 | break; | ||
| 82 | |||
| 83 | case PS_RANGE8: | ||
| 84 | setgain = MODE_PS_ON_Gain8; | ||
| 85 | break; | ||
| 86 | |||
| 87 | case PS_RANGE16: | ||
| 88 | setgain = MODE_PS_ON_Gain16; | ||
| 89 | break; | ||
| 90 | |||
| 91 | case PS_RANGE1: | ||
| 92 | default: | ||
| 93 | setgain = MODE_PS_ON_Gain1; | ||
| 94 | break; | ||
| 95 | } | ||
| 96 | |||
| 97 | error = ltr558_i2c_write_reg(client, LTR558_PS_CONTR, setgain); | ||
| 98 | mdelay(WAKEUP_DELAY); | ||
| 99 | return error; | ||
| 100 | } | ||
| 101 | |||
| 102 | static int ltr558_ps_disable(struct i2c_client *client) | ||
| 103 | { | ||
| 104 | return ltr558_i2c_write_reg(client, LTR558_PS_CONTR, MODE_PS_StdBy); | ||
| 105 | } | ||
| 106 | |||
| 107 | static int ltr558_ps_read(struct i2c_client *client) | ||
| 108 | { | ||
| 109 | int psval_lo = 0, psval_hi = 0, psdata = 0; | ||
| 110 | psval_lo = ltr558_i2c_read_reg(client, LTR558_PS_DATA_0); | ||
| 111 | if (psval_lo < 0){ | ||
| 112 | psdata = psval_lo; | ||
| 113 | goto out; | ||
| 114 | } | ||
| 115 | |||
| 116 | psval_hi = ltr558_i2c_read_reg(client, LTR558_PS_DATA_1); | ||
| 117 | if (psval_hi < 0){ | ||
| 118 | psdata = psval_hi; | ||
| 119 | goto out; | ||
| 120 | } | ||
| 121 | |||
| 122 | psdata = ((psval_hi & 0x07) * 256) + psval_lo; | ||
| 123 | out: | ||
| 124 | return psdata; | ||
| 125 | } | ||
| 126 | |||
| 127 | static int ltr558_als_enable(struct i2c_client *client, int gainrange) | ||
| 128 | { | ||
| 129 | int error = -1; | ||
| 130 | |||
| 131 | if (gainrange == ALS_RANGE1_320) | ||
| 132 | error = ltr558_i2c_write_reg(client, LTR558_ALS_CONTR, | ||
| 133 | MODE_ALS_ON_Range1); | ||
| 134 | else if (gainrange == ALS_RANGE2_64K) | ||
| 135 | error = ltr558_i2c_write_reg(client, LTR558_ALS_CONTR, | ||
| 136 | MODE_ALS_ON_Range2); | ||
| 137 | |||
| 138 | mdelay(WAKEUP_DELAY); | ||
| 139 | return error; | ||
| 140 | } | ||
| 141 | |||
| 142 | static int ltr558_als_disable(struct i2c_client *client) | ||
| 143 | { | ||
| 144 | return ltr558_i2c_write_reg(client, LTR558_ALS_CONTR, MODE_ALS_StdBy); | ||
| 145 | } | ||
| 146 | |||
| 147 | static int ltr558_als_read(struct i2c_client *client) | ||
| 148 | { | ||
| 149 | int alsval_ch0_lo, alsval_ch0_hi; | ||
| 150 | int alsval_ch1_lo, alsval_ch1_hi; | ||
| 151 | unsigned int alsval_ch0 = 0, alsval_ch1 = 0; | ||
| 152 | int luxdata = 0, ratio = 0; | ||
| 153 | long ch0_coeff = 0, ch1_coeff = 0; | ||
| 154 | |||
| 155 | alsval_ch1_lo = ltr558_i2c_read_reg(client, LTR558_ALS_DATA_CH1_0); | ||
| 156 | alsval_ch1_hi = ltr558_i2c_read_reg(client, LTR558_ALS_DATA_CH1_1); | ||
| 157 | alsval_ch1 = (alsval_ch1_hi * 256) + alsval_ch1_lo; | ||
| 158 | |||
| 159 | alsval_ch0_lo = ltr558_i2c_read_reg(client, LTR558_ALS_DATA_CH0_0); | ||
| 160 | alsval_ch0_hi = ltr558_i2c_read_reg(client, LTR558_ALS_DATA_CH0_1); | ||
| 161 | alsval_ch0 = (alsval_ch0_hi * 256) + alsval_ch0_lo; | ||
| 162 | |||
| 163 | if (alsval_ch0 == 0 && alsval_ch1 == 0) | ||
| 164 | return 0; | ||
| 165 | |||
| 166 | /* lux formula */ | ||
| 167 | ratio = (100 * alsval_ch1)/(alsval_ch1 + alsval_ch0); | ||
| 168 | |||
| 169 | if (ratio < 45) { | ||
| 170 | ch0_coeff = 17743; | ||
| 171 | ch1_coeff = -11059; | ||
| 172 | } | ||
| 173 | else if ((ratio >= 45) && (ratio < 64)) { | ||
| 174 | ch0_coeff = 37725; | ||
| 175 | ch1_coeff = 13363; | ||
| 176 | } | ||
| 177 | else if ((ratio >= 64) && (ratio < 85)) { | ||
| 178 | ch0_coeff = 16900; | ||
| 179 | ch1_coeff = 1690; | ||
| 180 | } | ||
| 181 | else if (ratio >= 85) { | ||
| 182 | ch0_coeff = 0; | ||
| 183 | ch1_coeff = 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | luxdata = ((alsval_ch0 * ch0_coeff) - (alsval_ch1 * ch1_coeff))/10000; | ||
| 187 | return luxdata; | ||
| 188 | } | ||
| 189 | |||
| 190 | static bool ltr558_set_proxim_high_threshold(struct i2c_client *client, | ||
| 191 | u32 thresh) | ||
| 192 | { | ||
| 193 | bool st; | ||
| 194 | st = ltr558_i2c_write_reg(client, LTR558_PS_THRES_UP_0, | ||
| 195 | thresh & 0xFF); | ||
| 196 | if (st) | ||
| 197 | st = ltr558_i2c_write_reg(client, LTR558_PS_THRES_UP_1, | ||
| 198 | (thresh >> 8) & 0x07); | ||
| 199 | return st; | ||
| 200 | } | ||
| 201 | |||
| 202 | static bool ltr558_set_proxim_low_threshold(struct i2c_client *client, | ||
| 203 | u32 thresh) | ||
| 204 | { | ||
| 205 | bool st; | ||
| 206 | st = ltr558_i2c_write_reg(client, LTR558_PS_THRES_LOW_0, | ||
| 207 | thresh & 0xFF); | ||
| 208 | if (st) | ||
| 209 | st = ltr558_i2c_write_reg(client, LTR558_PS_THRES_LOW_1, | ||
| 210 | (thresh >> 8) & 0x07); | ||
| 211 | return st; | ||
| 212 | } | ||
| 213 | |||
| 214 | static bool ltr558_set_als_high_threshold(struct i2c_client *client, u32 thresh) | ||
| 215 | { | ||
| 216 | bool st; | ||
| 217 | st = ltr558_i2c_write_reg(client, LTR558_ALS_THRES_UP_0, | ||
| 218 | thresh & 0xFF); | ||
| 219 | if (st) | ||
| 220 | st = ltr558_i2c_write_reg(client, LTR558_ALS_THRES_UP_1, | ||
| 221 | (thresh >> 8) & 0xFF); | ||
| 222 | return st; | ||
| 223 | } | ||
| 224 | |||
| 225 | static bool ltr558_set_als_low_threshold(struct i2c_client *client, u32 thresh) | ||
| 226 | { | ||
| 227 | bool st; | ||
| 228 | st = ltr558_i2c_write_reg(client, LTR558_ALS_THRES_LOW_0, | ||
| 229 | thresh & 0xFF); | ||
| 230 | if (st) | ||
| 231 | st = ltr558_i2c_write_reg(client, LTR558_ALS_THRES_LOW_1, | ||
| 232 | ((thresh >> 8) & 0xFF)); | ||
| 233 | return st; | ||
| 234 | } | ||
| 235 | |||
| 236 | /* Sysfs interface */ | ||
| 237 | |||
| 238 | /* proximity enable/disable */ | ||
| 239 | static ssize_t show_prox_enable(struct device *dev, | ||
| 240 | struct device_attribute *attr, char *buf) | ||
| 241 | { | ||
| 242 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 243 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 244 | |||
| 245 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 246 | if (chip->is_prox_enable) | ||
| 247 | return sprintf(buf, "1\n"); | ||
| 248 | else | ||
| 249 | return sprintf(buf, "0\n"); | ||
| 250 | } | ||
| 251 | |||
| 252 | static ssize_t store_prox_enable(struct device *dev, | ||
| 253 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 254 | { | ||
| 255 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 256 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 257 | struct i2c_client *client = chip->client; | ||
| 258 | int err = 0; | ||
| 259 | unsigned long lval; | ||
| 260 | |||
| 261 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 262 | |||
| 263 | if (strict_strtoul(buf, 10, &lval)) | ||
| 264 | return -EINVAL; | ||
| 265 | if ((lval != 1) && (lval != 0)) { | ||
| 266 | dev_err(dev, "illegal value %lu\n", lval); | ||
| 267 | return -EINVAL; | ||
| 268 | } | ||
| 269 | |||
| 270 | mutex_lock(&chip->lock); | ||
| 271 | if (lval == 1) | ||
| 272 | err = ltr558_ps_enable(client, PS_RANGE1); | ||
| 273 | else | ||
| 274 | err = ltr558_ps_disable(client); | ||
| 275 | |||
| 276 | if (err < 0) | ||
| 277 | dev_err(dev, "Error in enabling proximity\n"); | ||
| 278 | else | ||
| 279 | chip->is_prox_enable = (lval) ? true : false; | ||
| 280 | |||
| 281 | mutex_unlock(&chip->lock); | ||
| 282 | return count; | ||
| 283 | } | ||
| 284 | |||
| 285 | /* Proximity low thresholds */ | ||
| 286 | static ssize_t show_proxim_low_threshold(struct device *dev, | ||
| 287 | struct device_attribute *attr, char *buf) | ||
| 288 | { | ||
| 289 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 290 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 291 | |||
| 292 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 293 | return sprintf(buf, "%d\n", chip->prox_low_thres); | ||
| 294 | } | ||
| 295 | |||
| 296 | static ssize_t store_proxim_low_threshold(struct device *dev, | ||
| 297 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 298 | { | ||
| 299 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 300 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 301 | struct i2c_client *client = chip->client; | ||
| 302 | bool st; | ||
| 303 | unsigned long lval; | ||
| 304 | |||
| 305 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 306 | |||
| 307 | if (strict_strtoul(buf, 10, &lval)) | ||
| 308 | return -EINVAL; | ||
| 309 | |||
| 310 | if ((lval > 0x7FF) || (lval < 0x0)) { | ||
| 311 | dev_err(dev, "The threshold is not supported\n"); | ||
| 312 | return -EINVAL; | ||
| 313 | } | ||
| 314 | |||
| 315 | mutex_lock(&chip->lock); | ||
| 316 | st = ltr558_set_proxim_low_threshold(client, (u8)lval); | ||
| 317 | if (st) | ||
| 318 | chip->prox_low_thres = (int)lval; | ||
| 319 | else | ||
| 320 | dev_err(dev, "Error in setting proximity low threshold\n"); | ||
| 321 | |||
| 322 | mutex_unlock(&chip->lock); | ||
| 323 | return count; | ||
| 324 | } | ||
| 325 | |||
| 326 | /* Proximity high thresholds */ | ||
| 327 | static ssize_t show_proxim_high_threshold(struct device *dev, | ||
| 328 | struct device_attribute *attr, char *buf) | ||
| 329 | { | ||
| 330 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 331 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 332 | |||
| 333 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 334 | return sprintf(buf, "%d\n", chip->prox_high_thres); | ||
| 335 | } | ||
| 336 | |||
| 337 | static ssize_t store_proxim_high_threshold(struct device *dev, | ||
| 338 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 339 | { | ||
| 340 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 341 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 342 | struct i2c_client *client = chip->client; | ||
| 343 | bool st; | ||
| 344 | unsigned long lval; | ||
| 345 | |||
| 346 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 347 | |||
| 348 | if (strict_strtoul(buf, 10, &lval)) | ||
| 349 | return -EINVAL; | ||
| 350 | |||
| 351 | if ((lval > 0x7FF) || (lval < 0x0)) { | ||
| 352 | dev_err(dev, "The threshold is not supported\n"); | ||
| 353 | return -EINVAL; | ||
| 354 | } | ||
| 355 | |||
| 356 | mutex_lock(&chip->lock); | ||
| 357 | st = ltr558_set_proxim_high_threshold(client, lval); | ||
| 358 | if (st) | ||
| 359 | chip->prox_high_thres = (int)lval; | ||
| 360 | else | ||
| 361 | dev_err(dev, "Error in setting proximity high threshold\n"); | ||
| 362 | |||
| 363 | mutex_unlock(&chip->lock); | ||
| 364 | return count; | ||
| 365 | } | ||
| 366 | |||
| 367 | /* als enable/disable */ | ||
| 368 | static ssize_t show_als_enable(struct device *dev, | ||
| 369 | struct device_attribute *attr, char *buf) | ||
| 370 | { | ||
| 371 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 372 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 373 | |||
| 374 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 375 | if (chip->is_als_enable) | ||
| 376 | return sprintf(buf, "1\n"); | ||
| 377 | else | ||
| 378 | return sprintf(buf, "0\n"); | ||
| 379 | } | ||
| 380 | |||
| 381 | static ssize_t store_als_enable(struct device *dev, | ||
| 382 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 383 | { | ||
| 384 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 385 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 386 | struct i2c_client *client = chip->client; | ||
| 387 | int err = 0; | ||
| 388 | unsigned long lval; | ||
| 389 | |||
| 390 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 391 | |||
| 392 | if (strict_strtoul(buf, 10, &lval)) | ||
| 393 | return -EINVAL; | ||
| 394 | if ((lval != 1) && (lval != 0)) { | ||
| 395 | dev_err(dev, "illegal value %lu\n", lval); | ||
| 396 | return -EINVAL; | ||
| 397 | } | ||
| 398 | |||
| 399 | mutex_lock(&chip->lock); | ||
| 400 | if (lval == 1) | ||
| 401 | err = ltr558_als_enable(client, chip->als_gainrange); | ||
| 402 | else | ||
| 403 | err = ltr558_als_disable(client); | ||
| 404 | |||
| 405 | if (err < 0) | ||
| 406 | dev_err(dev, "Error in enabling ALS\n"); | ||
| 407 | else | ||
| 408 | chip->is_als_enable = (lval) ? true : false; | ||
| 409 | |||
| 410 | mutex_unlock(&chip->lock); | ||
| 411 | return count; | ||
| 412 | } | ||
| 413 | |||
| 414 | /* als low thresholds */ | ||
| 415 | static ssize_t show_als_low_threshold(struct device *dev, | ||
| 416 | struct device_attribute *attr, char *buf) | ||
| 417 | { | ||
| 418 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 419 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 420 | |||
| 421 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 422 | return sprintf(buf, "%d\n", chip->als_low_thres); | ||
| 423 | } | ||
| 424 | |||
| 425 | static ssize_t store_als_low_threshold(struct device *dev, | ||
| 426 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 427 | { | ||
| 428 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 429 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 430 | struct i2c_client *client = chip->client; | ||
| 431 | bool st; | ||
| 432 | unsigned long lval; | ||
| 433 | |||
| 434 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 435 | |||
| 436 | if (strict_strtoul(buf, 10, &lval)) | ||
| 437 | return -EINVAL; | ||
| 438 | |||
| 439 | if ((lval > 0xFFFF) || (lval < 0x0)) { | ||
| 440 | dev_err(dev, "The ALS threshold is not supported\n"); | ||
| 441 | return -EINVAL; | ||
| 442 | } | ||
| 443 | |||
| 444 | mutex_lock(&chip->lock); | ||
| 445 | st = ltr558_set_als_low_threshold(client, (int)lval); | ||
| 446 | if (st) | ||
| 447 | chip->als_low_thres = (int)lval; | ||
| 448 | else | ||
| 449 | dev_err(dev, "Error in setting als low threshold\n"); | ||
| 450 | mutex_unlock(&chip->lock); | ||
| 451 | return count; | ||
| 452 | } | ||
| 453 | |||
| 454 | /* Als high thresholds */ | ||
| 455 | static ssize_t show_als_high_threshold(struct device *dev, | ||
| 456 | struct device_attribute *attr, char *buf) | ||
| 457 | { | ||
| 458 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 459 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 460 | |||
| 461 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 462 | return sprintf(buf, "%d\n", chip->als_high_thres); | ||
| 463 | } | ||
| 464 | |||
| 465 | static ssize_t store_als_high_threshold(struct device *dev, | ||
| 466 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 467 | { | ||
| 468 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 469 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 470 | struct i2c_client *client = chip->client; | ||
| 471 | bool st; | ||
| 472 | unsigned long lval; | ||
| 473 | |||
| 474 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 475 | |||
| 476 | if (strict_strtoul(buf, 10, &lval)) | ||
| 477 | return -EINVAL; | ||
| 478 | |||
| 479 | if ((lval > 0xFFFF) || (lval < 0x0)) { | ||
| 480 | dev_err(dev, "The als threshold is not supported\n"); | ||
| 481 | return -EINVAL; | ||
| 482 | } | ||
| 483 | |||
| 484 | mutex_lock(&chip->lock); | ||
| 485 | st = ltr558_set_als_high_threshold(client, (int)lval); | ||
| 486 | if (st) | ||
| 487 | chip->als_high_thres = (int)lval; | ||
| 488 | else | ||
| 489 | dev_err(dev, "Error in setting als high threshold\n"); | ||
| 490 | mutex_unlock(&chip->lock); | ||
| 491 | return count; | ||
| 492 | } | ||
| 493 | |||
| 494 | /* Proximity persist */ | ||
| 495 | static ssize_t show_proxim_persist(struct device *dev, | ||
| 496 | struct device_attribute *attr, char *buf) | ||
| 497 | { | ||
| 498 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 499 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 500 | |||
| 501 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 502 | return sprintf(buf, "%d\n", chip->prox_persist); | ||
| 503 | } | ||
| 504 | |||
| 505 | static ssize_t store_proxim_persist(struct device *dev, | ||
| 506 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 507 | { | ||
| 508 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 509 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 510 | unsigned long lval; | ||
| 511 | |||
| 512 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 513 | |||
| 514 | if (strict_strtoul(buf, 10, &lval)) | ||
| 515 | return -EINVAL; | ||
| 516 | |||
| 517 | if ((lval > 16) || (lval < 0x0)) { | ||
| 518 | dev_err(dev, "The proximity persist is not supported\n"); | ||
| 519 | return -EINVAL; | ||
| 520 | } | ||
| 521 | |||
| 522 | mutex_lock(&chip->lock); | ||
| 523 | chip->prox_persist = (int)lval; | ||
| 524 | mutex_unlock(&chip->lock); | ||
| 525 | return count; | ||
| 526 | } | ||
| 527 | |||
| 528 | /* als/ir persist */ | ||
| 529 | static ssize_t show_als_persist(struct device *dev, | ||
| 530 | struct device_attribute *attr, char *buf) | ||
| 531 | { | ||
| 532 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 533 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 534 | |||
| 535 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 536 | return sprintf(buf, "%d\n", chip->als_persist); | ||
| 537 | } | ||
| 538 | |||
| 539 | static ssize_t store_als_persist(struct device *dev, | ||
| 540 | struct device_attribute *attr, const char *buf, size_t count) | ||
| 541 | { | ||
| 542 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 543 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 544 | unsigned long lval; | ||
| 545 | |||
| 546 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 547 | |||
| 548 | if (strict_strtoul(buf, 10, &lval)) | ||
| 549 | return -EINVAL; | ||
| 550 | |||
| 551 | if ((lval > 16) || (lval < 0x0)) { | ||
| 552 | dev_err(dev, "The als persist is not supported\n"); | ||
| 553 | return -EINVAL; | ||
| 554 | } | ||
| 555 | |||
| 556 | mutex_lock(&chip->lock); | ||
| 557 | chip->als_persist = (int)lval; | ||
| 558 | mutex_unlock(&chip->lock); | ||
| 559 | return count; | ||
| 560 | } | ||
| 561 | |||
| 562 | /* Display proxim data */ | ||
| 563 | static ssize_t show_proxim_data(struct device *dev, | ||
| 564 | struct device_attribute *attr, char *buf) | ||
| 565 | { | ||
| 566 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 567 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 568 | int prox_data = 0; | ||
| 569 | ssize_t buf_count = 0; | ||
| 570 | |||
| 571 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 572 | mutex_lock(&chip->lock); | ||
| 573 | |||
| 574 | if (chip->is_prox_enable) { | ||
| 575 | prox_data = ltr558_ps_read(chip->client); | ||
| 576 | chip->prox_reading = prox_data; | ||
| 577 | buf_count = sprintf(buf, "%d\n", prox_data); | ||
| 578 | } | ||
| 579 | else | ||
| 580 | buf_count = sprintf(buf, "%d\n", chip->prox_reading); | ||
| 581 | mutex_unlock(&chip->lock); | ||
| 582 | return buf_count; | ||
| 583 | } | ||
| 584 | |||
| 585 | /* Display als data */ | ||
| 586 | static ssize_t show_als_data(struct device *dev, | ||
| 587 | struct device_attribute *attr, char *buf) | ||
| 588 | { | ||
| 589 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 590 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 591 | ssize_t buf_count = 0; | ||
| 592 | int als_data = 0; | ||
| 593 | |||
| 594 | dev_vdbg(dev, "%s()\n", __func__); | ||
| 595 | |||
| 596 | mutex_lock(&chip->lock); | ||
| 597 | if (chip->is_als_enable) { | ||
| 598 | als_data = ltr558_als_read(chip->client); | ||
| 599 | buf_count = sprintf(buf, "%d\n", als_data); | ||
| 600 | chip->als_reading = als_data; | ||
| 601 | } | ||
| 602 | else | ||
| 603 | buf_count = sprintf(buf, "%d\n", chip->als_reading); | ||
| 604 | mutex_unlock(&chip->lock); | ||
| 605 | |||
| 606 | return buf_count; | ||
| 607 | } | ||
| 608 | |||
| 609 | /* Read name */ | ||
| 610 | static ssize_t show_name(struct device *dev, | ||
| 611 | struct device_attribute *attr, char *buf) | ||
| 612 | { | ||
| 613 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
| 614 | struct ltr558_chip *chip = indio_dev->dev_data; | ||
| 615 | return sprintf(buf, "%s\n", chip->client->name); | ||
| 616 | } | ||
| 617 | |||
| 618 | static IIO_DEVICE_ATTR(proximity_low_threshold, S_IRUGO | S_IWUSR, | ||
| 619 | show_proxim_low_threshold, store_proxim_low_threshold, 0); | ||
| 620 | static IIO_DEVICE_ATTR(proximity_high_threshold, S_IRUGO | S_IWUSR, | ||
| 621 | show_proxim_high_threshold, store_proxim_high_threshold, 0); | ||
| 622 | static IIO_DEVICE_ATTR(proximity_persist, S_IRUGO | S_IWUSR, | ||
| 623 | show_proxim_persist, store_proxim_persist, 0); | ||
| 624 | static IIO_DEVICE_ATTR(proximity_enable, S_IRUGO | S_IWUSR, | ||
| 625 | show_prox_enable, store_prox_enable, 0); | ||
| 626 | static IIO_DEVICE_ATTR(proximity_value, S_IRUGO, | ||
| 627 | show_proxim_data, NULL, 0); | ||
| 628 | |||
| 629 | static IIO_DEVICE_ATTR(als_low_threshold, S_IRUGO | S_IWUSR, | ||
| 630 | show_als_low_threshold, store_als_low_threshold, 0); | ||
| 631 | static IIO_DEVICE_ATTR(als_high_threshold, S_IRUGO | S_IWUSR, | ||
| 632 | show_als_high_threshold, store_als_high_threshold, 0); | ||
| 633 | static IIO_DEVICE_ATTR(als_persist, S_IRUGO | S_IWUSR, | ||
| 634 | show_als_persist, store_als_persist, 0); | ||
| 635 | static IIO_DEVICE_ATTR(als_enable, S_IRUGO | S_IWUSR, | ||
| 636 | show_als_enable, store_als_enable, 0); | ||
| 637 | static IIO_DEVICE_ATTR(als_value, S_IRUGO, | ||
| 638 | show_als_data, NULL, 0); | ||
| 639 | |||
| 640 | static IIO_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); | ||
| 641 | |||
| 642 | static struct attribute *ltr558_attributes[] = { | ||
| 643 | &iio_dev_attr_name.dev_attr.attr, | ||
| 644 | |||
| 645 | &iio_dev_attr_als_low_threshold.dev_attr.attr, | ||
| 646 | &iio_dev_attr_als_high_threshold.dev_attr.attr, | ||
| 647 | &iio_dev_attr_als_enable.dev_attr.attr, | ||
| 648 | &iio_dev_attr_als_persist.dev_attr.attr, | ||
| 649 | &iio_dev_attr_als_value.dev_attr.attr, | ||
| 650 | |||
| 651 | &iio_dev_attr_proximity_low_threshold.dev_attr.attr, | ||
| 652 | &iio_dev_attr_proximity_high_threshold.dev_attr.attr, | ||
| 653 | &iio_dev_attr_proximity_enable.dev_attr.attr, | ||
| 654 | &iio_dev_attr_proximity_persist.dev_attr.attr, | ||
| 655 | &iio_dev_attr_proximity_value.dev_attr.attr, | ||
| 656 | NULL | ||
| 657 | }; | ||
| 658 | |||
| 659 | static const struct attribute_group ltr558_group = { | ||
| 660 | .attrs = ltr558_attributes, | ||
| 661 | }; | ||
| 662 | |||
| 663 | static int ltr558_chip_init(struct i2c_client *client) | ||
| 664 | { | ||
| 665 | struct ltr558_chip *chip = i2c_get_clientdata(client); | ||
| 666 | int error = 0; | ||
| 667 | |||
| 668 | mdelay(PON_DELAY); | ||
| 669 | |||
| 670 | chip->is_prox_enable = 0; | ||
| 671 | chip->prox_low_thres = 0; | ||
| 672 | chip->prox_high_thres = 0x7FF; | ||
| 673 | chip->prox_reading = 0; | ||
| 674 | |||
| 675 | chip->als_low_thres = 0; | ||
| 676 | chip->als_high_thres = 0xFFFF; | ||
| 677 | chip->als_reading = 0; | ||
| 678 | |||
| 679 | chip->is_als_enable = 0; | ||
| 680 | chip->prox_persist = 0; | ||
| 681 | chip->als_persist = 0; | ||
| 682 | |||
| 683 | /* Enable PS to Gain1 at startup */ | ||
| 684 | chip->ps_gainrange = PS_RANGE1; | ||
| 685 | error = ltr558_ps_enable(client, chip->ps_gainrange); | ||
| 686 | if (error < 0) | ||
| 687 | goto out; | ||
| 688 | |||
| 689 | |||
| 690 | /* Enable ALS to Full Range at startup */ | ||
| 691 | chip->als_gainrange = ALS_RANGE2_64K; | ||
| 692 | error = ltr558_als_enable(client, chip->als_gainrange); | ||
| 693 | if (error < 0) | ||
| 694 | goto out; | ||
| 695 | |||
| 696 | out: | ||
| 697 | return error; | ||
| 698 | } | ||
| 699 | |||
| 700 | static const struct iio_info ltr558_info = { | ||
| 701 | .attrs = <r558_group, | ||
| 702 | .driver_module = THIS_MODULE, | ||
| 703 | }; | ||
| 704 | |||
| 705 | static irqreturn_t threshold_isr(int irq, void *irq_data) | ||
| 706 | { | ||
| 707 | struct ltr558_chip *chip = (struct ltr558_chip *)irq_data; | ||
| 708 | s32 int_reg; | ||
| 709 | struct i2c_client *client = chip->client; | ||
| 710 | |||
| 711 | int_reg = i2c_smbus_read_byte_data(client, LTR558_ALS_PS_STATUS); | ||
| 712 | if (int_reg < 0) { | ||
| 713 | dev_err(&client->dev, "Error in reading register %d, error %d\n", | ||
| 714 | LTR558_ALS_PS_STATUS, int_reg); | ||
| 715 | return IRQ_HANDLED; | ||
| 716 | } | ||
| 717 | |||
| 718 | if (int_reg & STATUS_ALS_INT_TRIGGER) { | ||
| 719 | if (int_reg & STATUS_ALS_NEW_DATA) | ||
| 720 | chip->als_reading = ltr558_als_read(client); | ||
| 721 | } | ||
| 722 | |||
| 723 | if (int_reg & STATUS_PS_INT_TRIGGER) { | ||
| 724 | if (int_reg & STATUS_PS_NEW_DATA) | ||
| 725 | chip->prox_reading = ltr558_ps_read(client); | ||
| 726 | } | ||
| 727 | |||
| 728 | return IRQ_HANDLED; | ||
| 729 | } | ||
| 730 | |||
| 731 | static int ltr558_probe(struct i2c_client *client, | ||
| 732 | const struct i2c_device_id *id) | ||
| 733 | { | ||
| 734 | int ret = 0; | ||
| 735 | struct ltr558_chip *chip; | ||
| 736 | |||
| 737 | /* data memory allocation */ | ||
| 738 | chip = kzalloc(sizeof(struct ltr558_chip), GFP_KERNEL); | ||
| 739 | if (chip == NULL) { | ||
| 740 | printk(KERN_ALERT "%s: LTR-558ALS kzalloc failed.\n", __func__); | ||
| 741 | ret = -ENOMEM; | ||
| 742 | goto exit; | ||
| 743 | } | ||
| 744 | |||
| 745 | i2c_set_clientdata(client, chip); | ||
| 746 | chip->client = client; | ||
| 747 | chip->irq = client->irq; | ||
| 748 | |||
| 749 | if (chip->irq > 0) { | ||
| 750 | ret = request_threaded_irq(chip->irq, NULL, threshold_isr, | ||
| 751 | IRQF_SHARED, "LTR558_ALS", chip); | ||
| 752 | if (ret) { | ||
| 753 | dev_err(&client->dev, "Unable to register irq %d; " | ||
| 754 | "ret %d\n", chip->irq, ret); | ||
| 755 | goto exit_free; | ||
| 756 | } | ||
| 757 | } | ||
| 758 | |||
| 759 | mutex_init(&chip->lock); | ||
| 760 | |||
| 761 | ret = ltr558_chip_init(client); | ||
| 762 | if (ret) | ||
| 763 | goto exit_free; | ||
| 764 | |||
| 765 | chip->indio_dev = iio_allocate_device(0); | ||
| 766 | if (!chip->indio_dev) { | ||
| 767 | dev_err(&client->dev, "iio allocation fails\n"); | ||
| 768 | goto exit_irq; | ||
| 769 | } | ||
| 770 | |||
| 771 | chip->indio_dev->info = <r558_info; | ||
| 772 | chip->indio_dev->dev.parent = &client->dev; | ||
| 773 | chip->indio_dev->dev_data = (void *)(chip); | ||
| 774 | chip->indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 775 | ret = iio_device_register(chip->indio_dev); | ||
| 776 | if (ret) { | ||
| 777 | dev_err(&client->dev, "iio registration fails\n"); | ||
| 778 | goto exit_iio_free; | ||
| 779 | } | ||
| 780 | |||
| 781 | dev_dbg(&client->dev, "%s() success\n", __func__); | ||
| 782 | return 0; | ||
| 783 | |||
| 784 | exit_iio_free: | ||
| 785 | iio_free_device(chip->indio_dev); | ||
| 786 | exit_irq: | ||
| 787 | if (chip->irq > 0) | ||
| 788 | free_irq(chip->irq, chip); | ||
| 789 | exit_free: | ||
| 790 | kfree(chip); | ||
| 791 | exit: | ||
| 792 | return ret; | ||
| 793 | } | ||
| 794 | |||
| 795 | |||
| 796 | static int ltr558_remove(struct i2c_client *client) | ||
| 797 | { | ||
| 798 | struct ltr558_chip *chip = i2c_get_clientdata(client); | ||
| 799 | |||
| 800 | dev_dbg(&client->dev, "%s()\n", __func__); | ||
| 801 | iio_device_unregister(chip->indio_dev); | ||
| 802 | if (chip->irq > 0) | ||
| 803 | free_irq(chip->irq, chip); | ||
| 804 | ltr558_ps_disable(client); | ||
| 805 | ltr558_als_disable(client); | ||
| 806 | kfree(chip); | ||
| 807 | return 0; | ||
| 808 | } | ||
| 809 | |||
| 810 | |||
| 811 | static int ltr558_suspend(struct i2c_client *client, pm_message_t mesg) | ||
| 812 | { | ||
| 813 | struct ltr558_chip *chip = i2c_get_clientdata(client); | ||
| 814 | int ret; | ||
| 815 | |||
| 816 | if (chip->is_als_enable == 1) | ||
| 817 | chip->als_enabled_before_suspend = 1; | ||
| 818 | if (chip->is_prox_enable == 1) | ||
| 819 | chip->prox_enabled_before_suspend = 1; | ||
| 820 | |||
| 821 | ret = ltr558_ps_disable(client); | ||
| 822 | if (ret == 0) | ||
| 823 | ret = ltr558_als_disable(client); | ||
| 824 | |||
| 825 | return ret; | ||
| 826 | } | ||
| 827 | |||
| 828 | |||
| 829 | static int ltr558_resume(struct i2c_client *client) | ||
| 830 | { | ||
| 831 | struct ltr558_chip *chip = i2c_get_clientdata(client); | ||
| 832 | int error = 0; | ||
| 833 | |||
| 834 | mdelay(PON_DELAY); | ||
| 835 | |||
| 836 | if (chip->prox_enabled_before_suspend == 1) { | ||
| 837 | error = ltr558_ps_enable(client, chip->ps_gainrange); | ||
| 838 | if (error < 0) | ||
| 839 | goto out; | ||
| 840 | } | ||
| 841 | |||
| 842 | if (chip->als_enabled_before_suspend == 1) { | ||
| 843 | error = ltr558_als_enable(client, chip->als_gainrange); | ||
| 844 | } | ||
| 845 | out: | ||
| 846 | return error; | ||
| 847 | } | ||
| 848 | |||
| 849 | |||
| 850 | static const struct i2c_device_id ltr558_id[] = { | ||
| 851 | { DEVICE_NAME, 0 }, | ||
| 852 | {} | ||
| 853 | }; | ||
| 854 | |||
| 855 | |||
| 856 | static struct i2c_driver ltr558_driver = { | ||
| 857 | .class = I2C_CLASS_HWMON, | ||
| 858 | .probe = ltr558_probe, | ||
| 859 | .remove = ltr558_remove, | ||
| 860 | .id_table = ltr558_id, | ||
| 861 | .driver = { | ||
| 862 | .owner = THIS_MODULE, | ||
| 863 | .name = DEVICE_NAME, | ||
| 864 | }, | ||
| 865 | .suspend = ltr558_suspend, | ||
| 866 | .resume = ltr558_resume, | ||
| 867 | }; | ||
| 868 | |||
| 869 | |||
| 870 | static int __init ltr558_driverinit(void) | ||
| 871 | { | ||
| 872 | return i2c_add_driver(<r558_driver); | ||
| 873 | } | ||
| 874 | |||
| 875 | |||
| 876 | static void __exit ltr558_driverexit(void) | ||
| 877 | { | ||
| 878 | i2c_del_driver(<r558_driver); | ||
| 879 | } | ||
| 880 | |||
| 881 | |||
| 882 | module_init(ltr558_driverinit) | ||
| 883 | module_exit(ltr558_driverexit) | ||
diff --git a/drivers/staging/iio/light/ltr558als.h b/drivers/staging/iio/light/ltr558als.h new file mode 100644 index 00000000000..17e1b903f66 --- /dev/null +++ b/drivers/staging/iio/light/ltr558als.h | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | /* Lite-On LTR-558ALS Linux Driver | ||
| 2 | * | ||
| 3 | * Copyright (c) 2012, NVIDIA Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License as published by | ||
| 7 | * the Free Software Foundation; either version 2 of the License, or | ||
| 8 | * (at your option) any later version. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef _LTR558_H | ||
| 12 | #define _LTR558_H | ||
| 13 | |||
| 14 | |||
| 15 | /* LTR-558 Registers */ | ||
| 16 | #define LTR558_ALS_CONTR 0x80 | ||
| 17 | #define LTR558_PS_CONTR 0x81 | ||
| 18 | #define LTR558_PS_LED 0x82 | ||
| 19 | #define LTR558_PS_N_PULSES 0x83 | ||
| 20 | #define LTR558_PS_MEAS_RATE 0x84 | ||
| 21 | #define LTR558_ALS_MEAS_RATE 0x85 | ||
| 22 | #define LTR558_MANUFACTURER_ID 0x87 | ||
| 23 | |||
| 24 | #define LTR558_INTERRUPT 0x8F | ||
| 25 | #define LTR558_PS_THRES_UP_0 0x90 | ||
| 26 | #define LTR558_PS_THRES_UP_1 0x91 | ||
| 27 | #define LTR558_PS_THRES_LOW_0 0x92 | ||
| 28 | #define LTR558_PS_THRES_LOW_1 0x93 | ||
| 29 | |||
| 30 | #define LTR558_ALS_THRES_UP_0 0x97 | ||
| 31 | #define LTR558_ALS_THRES_UP_1 0x98 | ||
| 32 | #define LTR558_ALS_THRES_LOW_0 0x99 | ||
| 33 | #define LTR558_ALS_THRES_LOW_1 0x9A | ||
| 34 | |||
| 35 | #define LTR558_INTERRUPT_PERSIST 0x9E | ||
| 36 | |||
| 37 | /* 558's Read Only Registers */ | ||
| 38 | #define LTR558_ALS_DATA_CH1_0 0x88 | ||
| 39 | #define LTR558_ALS_DATA_CH1_1 0x89 | ||
| 40 | #define LTR558_ALS_DATA_CH0_0 0x8A | ||
| 41 | #define LTR558_ALS_DATA_CH0_1 0x8B | ||
| 42 | #define LTR558_ALS_PS_STATUS 0x8C | ||
| 43 | #define LTR558_PS_DATA_0 0x8D | ||
| 44 | #define LTR558_PS_DATA_1 0x8E | ||
| 45 | |||
| 46 | /* ALS PS STATUS 0x8C */ | ||
| 47 | #define STATUS_ALS_GAIN_RANGE1 0x10 | ||
| 48 | #define STATUS_ALS_INT_TRIGGER 0x08 | ||
| 49 | #define STATUS_ALS_NEW_DATA 0x04 | ||
| 50 | #define STATUS_PS_INT_TRIGGER 0x02 | ||
| 51 | #define STATUS_PS_NEW_DATA 0x01 | ||
| 52 | |||
| 53 | /* Basic Operating Modes */ | ||
| 54 | #define MODE_ALS_ON_Range1 0x0B | ||
| 55 | #define MODE_ALS_ON_Range2 0x03 | ||
| 56 | #define MODE_ALS_StdBy 0x00 | ||
| 57 | |||
| 58 | #define MODE_PS_ON_Gain1 0x03 | ||
| 59 | #define MODE_PS_ON_Gain4 0x07 | ||
| 60 | #define MODE_PS_ON_Gain8 0x0B | ||
| 61 | #define MODE_PS_ON_Gain16 0x0F | ||
| 62 | #define MODE_PS_StdBy 0x00 | ||
| 63 | |||
| 64 | #define PS_RANGE1 1 | ||
| 65 | #define PS_RANGE4 2 | ||
| 66 | #define PS_RANGE8 4 | ||
| 67 | #define PS_RANGE16 8 | ||
| 68 | |||
| 69 | #define ALS_RANGE1_320 1 | ||
| 70 | #define ALS_RANGE2_64K 2 | ||
| 71 | |||
| 72 | /* Power On response time in ms */ | ||
| 73 | #define PON_DELAY 600 | ||
| 74 | #define WAKEUP_DELAY 10 | ||
| 75 | |||
| 76 | #endif | ||
diff --git a/drivers/staging/iio/magnetometer/magnet.h b/drivers/staging/iio/magnetometer/magnet.h new file mode 100644 index 00000000000..1260eb7bd41 --- /dev/null +++ b/drivers/staging/iio/magnetometer/magnet.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | |||
| 2 | #include "../sysfs.h" | ||
| 3 | |||
| 4 | /* Magnetometer types of attribute */ | ||
| 5 | |||
| 6 | #define IIO_DEV_ATTR_MAGN_X_OFFSET(_mode, _show, _store, _addr) \ | ||
| 7 | IIO_DEVICE_ATTR(magn_x_offset, _mode, _show, _store, _addr) | ||
| 8 | |||
| 9 | #define IIO_DEV_ATTR_MAGN_Y_OFFSET(_mode, _show, _store, _addr) \ | ||
| 10 | IIO_DEVICE_ATTR(magn_y_offset, _mode, _show, _store, _addr) | ||
| 11 | |||
| 12 | #define IIO_DEV_ATTR_MAGN_Z_OFFSET(_mode, _show, _store, _addr) \ | ||
| 13 | IIO_DEVICE_ATTR(magn_z_offset, _mode, _show, _store, _addr) | ||
| 14 | |||
| 15 | #define IIO_DEV_ATTR_MAGN_X_SCALE(_mode, _show, _store, _addr) \ | ||
| 16 | IIO_DEVICE_ATTR(magn_x_scale, _mode, _show, _store, _addr) | ||
| 17 | |||
| 18 | #define IIO_DEV_ATTR_MAGN_Y_SCALE(_mode, _show, _store, _addr) \ | ||
| 19 | IIO_DEVICE_ATTR(magn_y_scale, _mode, _show, _store, _addr) | ||
| 20 | |||
| 21 | #define IIO_DEV_ATTR_MAGN_Z_SCALE(_mode, _show, _store, _addr) \ | ||
| 22 | IIO_DEVICE_ATTR(magn_z_scale, _mode, _show, _store, _addr) | ||
| 23 | |||
| 24 | #define IIO_DEV_ATTR_MAGN_X(_show, _addr) \ | ||
| 25 | IIO_DEVICE_ATTR(magn_x_raw, S_IRUGO, _show, NULL, _addr) | ||
| 26 | |||
| 27 | #define IIO_DEV_ATTR_MAGN_Y(_show, _addr) \ | ||
| 28 | IIO_DEVICE_ATTR(magn_y_raw, S_IRUGO, _show, NULL, _addr) | ||
| 29 | |||
| 30 | #define IIO_DEV_ATTR_MAGN_Z(_show, _addr) \ | ||
| 31 | IIO_DEVICE_ATTR(magn_z_raw, S_IRUGO, _show, NULL, _addr) | ||
diff --git a/drivers/staging/iio/resolver/ad2s120x.c b/drivers/staging/iio/resolver/ad2s120x.c new file mode 100644 index 00000000000..bed4c725f2d --- /dev/null +++ b/drivers/staging/iio/resolver/ad2s120x.c | |||
| @@ -0,0 +1,177 @@ | |||
| 1 | /* | ||
| 2 | * ad2s120x.c simple support for the ADI Resolver to Digital Converters: AD2S1200/1205 | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010-2010 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | #include <linux/types.h> | ||
| 12 | #include <linux/mutex.h> | ||
| 13 | #include <linux/device.h> | ||
| 14 | #include <linux/spi/spi.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/sysfs.h> | ||
| 17 | #include <linux/delay.h> | ||
| 18 | #include <linux/gpio.h> | ||
| 19 | |||
| 20 | #include "../iio.h" | ||
| 21 | #include "../sysfs.h" | ||
| 22 | |||
| 23 | #define DRV_NAME "ad2s120x" | ||
| 24 | |||
| 25 | /* input pin sample and rdvel is controlled by driver */ | ||
| 26 | #define AD2S120X_PN 2 | ||
| 27 | |||
| 28 | /* input clock on serial interface */ | ||
| 29 | #define AD2S120X_HZ 8192000 | ||
| 30 | /* clock period in nano second */ | ||
| 31 | #define AD2S120X_TSCLK (1000000000/AD2S120X_HZ) | ||
| 32 | |||
| 33 | struct ad2s120x_state { | ||
| 34 | struct mutex lock; | ||
| 35 | struct spi_device *sdev; | ||
| 36 | int sample; | ||
| 37 | int rdvel; | ||
| 38 | u8 rx[2] ____cacheline_aligned; | ||
| 39 | }; | ||
| 40 | |||
| 41 | static ssize_t ad2s120x_show_val(struct device *dev, | ||
| 42 | struct device_attribute *attr, char *buf) | ||
| 43 | { | ||
| 44 | int ret = 0; | ||
| 45 | ssize_t len = 0; | ||
| 46 | u16 pos; | ||
| 47 | s16 vel; | ||
| 48 | u8 status; | ||
| 49 | struct ad2s120x_state *st = iio_priv(dev_get_drvdata(dev)); | ||
| 50 | struct iio_dev_attr *iattr = to_iio_dev_attr(attr); | ||
| 51 | |||
| 52 | mutex_lock(&st->lock); | ||
| 53 | |||
| 54 | gpio_set_value(st->sample, 0); | ||
| 55 | /* delay (6 * AD2S120X_TSCLK + 20) nano seconds */ | ||
| 56 | udelay(1); | ||
| 57 | gpio_set_value(st->sample, 1); | ||
| 58 | gpio_set_value(st->rdvel, iattr->address); | ||
| 59 | ret = spi_read(st->sdev, st->rx, 2); | ||
| 60 | if (ret < 0) | ||
| 61 | goto error_ret; | ||
| 62 | status = st->rx[1]; | ||
| 63 | if (iattr->address) | ||
| 64 | pos = (((u16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); | ||
| 65 | else { | ||
| 66 | vel = (st->rx[0] & 0x80) ? 0xf000 : 0; | ||
| 67 | vel |= (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); | ||
| 68 | } | ||
| 69 | len = sprintf(buf, "%d %c%c%c%c ", iattr->address ? pos : vel, | ||
| 70 | (status & 0x8) ? 'P' : 'V', | ||
| 71 | (status & 0x4) ? 'd' : '_', | ||
| 72 | (status & 0x2) ? 'l' : '_', | ||
| 73 | (status & 0x1) ? '1' : '0'); | ||
| 74 | error_ret: | ||
| 75 | /* delay (2 * AD2S120X_TSCLK + 20) ns for sample pulse */ | ||
| 76 | udelay(1); | ||
| 77 | mutex_unlock(&st->lock); | ||
| 78 | |||
| 79 | return ret ? ret : len; | ||
| 80 | } | ||
| 81 | |||
| 82 | static IIO_DEVICE_ATTR(pos, S_IRUGO, ad2s120x_show_val, NULL, 1); | ||
| 83 | static IIO_DEVICE_ATTR(vel, S_IRUGO, ad2s120x_show_val, NULL, 0); | ||
| 84 | |||
| 85 | static struct attribute *ad2s120x_attributes[] = { | ||
| 86 | &iio_dev_attr_pos.dev_attr.attr, | ||
| 87 | &iio_dev_attr_vel.dev_attr.attr, | ||
| 88 | NULL, | ||
| 89 | }; | ||
| 90 | |||
| 91 | static const struct attribute_group ad2s120x_attribute_group = { | ||
| 92 | .attrs = ad2s120x_attributes, | ||
| 93 | }; | ||
| 94 | |||
| 95 | static const struct iio_info ad2s120x_info = { | ||
| 96 | .attrs = &ad2s120x_attribute_group, | ||
| 97 | .driver_module = THIS_MODULE, | ||
| 98 | }; | ||
| 99 | |||
| 100 | static int __devinit ad2s120x_probe(struct spi_device *spi) | ||
| 101 | { | ||
| 102 | struct ad2s120x_state *st; | ||
| 103 | struct iio_dev *indio_dev; | ||
| 104 | int pn, ret = 0; | ||
| 105 | unsigned short *pins = spi->dev.platform_data; | ||
| 106 | |||
| 107 | for (pn = 0; pn < AD2S120X_PN; pn++) | ||
| 108 | if (gpio_request_one(pins[pn], GPIOF_DIR_OUT, DRV_NAME)) { | ||
| 109 | pr_err("%s: request gpio pin %d failed\n", | ||
| 110 | DRV_NAME, pins[pn]); | ||
| 111 | goto error_ret; | ||
| 112 | } | ||
| 113 | indio_dev = iio_allocate_device(sizeof(*st)); | ||
| 114 | if (indio_dev == NULL) { | ||
| 115 | ret = -ENOMEM; | ||
| 116 | goto error_ret; | ||
| 117 | } | ||
| 118 | spi_set_drvdata(spi, indio_dev); | ||
| 119 | st = iio_priv(indio_dev); | ||
| 120 | mutex_init(&st->lock); | ||
| 121 | st->sdev = spi; | ||
| 122 | st->sample = pins[0]; | ||
| 123 | st->rdvel = pins[1]; | ||
| 124 | |||
| 125 | indio_dev->dev.parent = &spi->dev; | ||
| 126 | indio_dev->info = &ad2s120x_info; | ||
| 127 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
| 128 | |||
| 129 | ret = iio_device_register(indio_dev); | ||
| 130 | if (ret) | ||
| 131 | goto error_free_dev; | ||
| 132 | |||
| 133 | spi->max_speed_hz = AD2S120X_HZ; | ||
| 134 | spi->mode = SPI_MODE_3; | ||
| 135 | spi_setup(spi); | ||
| 136 | |||
| 137 | return 0; | ||
| 138 | |||
| 139 | error_free_dev: | ||
| 140 | iio_free_device(indio_dev); | ||
| 141 | error_ret: | ||
| 142 | for (--pn; pn >= 0; pn--) | ||
| 143 | gpio_free(pins[pn]); | ||
| 144 | return ret; | ||
| 145 | } | ||
| 146 | |||
| 147 | static int __devexit ad2s120x_remove(struct spi_device *spi) | ||
| 148 | { | ||
| 149 | iio_device_unregister(spi_get_drvdata(spi)); | ||
| 150 | |||
| 151 | return 0; | ||
| 152 | } | ||
| 153 | |||
| 154 | static struct spi_driver ad2s120x_driver = { | ||
| 155 | .driver = { | ||
| 156 | .name = DRV_NAME, | ||
| 157 | .owner = THIS_MODULE, | ||
| 158 | }, | ||
| 159 | .probe = ad2s120x_probe, | ||
| 160 | .remove = __devexit_p(ad2s120x_remove), | ||
| 161 | }; | ||
| 162 | |||
| 163 | static __init int ad2s120x_spi_init(void) | ||
| 164 | { | ||
| 165 | return spi_register_driver(&ad2s120x_driver); | ||
| 166 | } | ||
| 167 | module_init(ad2s120x_spi_init); | ||
| 168 | |||
| 169 | static __exit void ad2s120x_spi_exit(void) | ||
| 170 | { | ||
| 171 | spi_unregister_driver(&ad2s120x_driver); | ||
| 172 | } | ||
| 173 | module_exit(ad2s120x_spi_exit); | ||
| 174 | |||
| 175 | MODULE_AUTHOR("Graff Yang <graff.yang@gmail.com>"); | ||
| 176 | MODULE_DESCRIPTION("Analog Devices AD2S1200/1205 Resolver to Digital SPI driver"); | ||
| 177 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/staging/iio/ring_generic.h b/drivers/staging/iio/ring_generic.h new file mode 100644 index 00000000000..3f26f7175b6 --- /dev/null +++ b/drivers/staging/iio/ring_generic.h | |||
| @@ -0,0 +1,288 @@ | |||
| 1 | /* The industrial I/O core - generic ring buffer interfaces. | ||
| 2 | * | ||
| 3 | * Copyright (c) 2008 Jonathan Cameron | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 as published by | ||
| 7 | * the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef _IIO_RING_GENERIC_H_ | ||
| 11 | #define _IIO_RING_GENERIC_H_ | ||
| 12 | #include "iio.h" | ||
| 13 | |||
| 14 | #ifdef CONFIG_IIO_RING_BUFFER | ||
| 15 | |||
| 16 | struct iio_ring_buffer; | ||
| 17 | |||
| 18 | /** | ||
| 19 | * struct iio_ring_access_funcs - access functions for ring buffers. | ||
| 20 | * @mark_in_use: reference counting, typically to prevent module removal | ||
| 21 | * @unmark_in_use: reduce reference count when no longer using ring buffer | ||
| 22 | * @store_to: actually store stuff to the ring buffer | ||
| 23 | * @read_last: get the last element stored | ||
| 24 | * @read_first_n: try to get a specified number of elements (must exist) | ||
| 25 | * @mark_param_change: notify ring that some relevant parameter has changed | ||
| 26 | * Often this means the underlying storage may need to | ||
| 27 | * change. | ||
| 28 | * @request_update: if a parameter change has been marked, update underlying | ||
| 29 | * storage. | ||
| 30 | * @get_bytes_per_datum:get current bytes per datum | ||
| 31 | * @set_bytes_per_datum:set number of bytes per datum | ||
| 32 | * @get_length: get number of datums in ring | ||
| 33 | * @set_length: set number of datums in ring | ||
| 34 | * @is_enabled: query if ring is currently being used | ||
| 35 | * @enable: enable the ring | ||
| 36 | * | ||
| 37 | * The purpose of this structure is to make the ring buffer element | ||
| 38 | * modular as event for a given driver, different usecases may require | ||
| 39 | * different ring designs (space efficiency vs speed for example). | ||
| 40 | * | ||
| 41 | * It is worth noting that a given ring implementation may only support a small | ||
| 42 | * proportion of these functions. The core code 'should' cope fine with any of | ||
| 43 | * them not existing. | ||
| 44 | **/ | ||
| 45 | struct iio_ring_access_funcs { | ||
| 46 | void (*mark_in_use)(struct iio_ring_buffer *ring); | ||
| 47 | void (*unmark_in_use)(struct iio_ring_buffer *ring); | ||
| 48 | |||
| 49 | int (*store_to)(struct iio_ring_buffer *ring, u8 *data, s64 timestamp); | ||
| 50 | int (*read_last)(struct iio_ring_buffer *ring, u8 *data); | ||
| 51 | int (*read_first_n)(struct iio_ring_buffer *ring, | ||
| 52 | size_t n, | ||
| 53 | char __user *buf); | ||
| 54 | |||
| 55 | int (*mark_param_change)(struct iio_ring_buffer *ring); | ||
| 56 | int (*request_update)(struct iio_ring_buffer *ring); | ||
| 57 | |||
| 58 | int (*get_bytes_per_datum)(struct iio_ring_buffer *ring); | ||
| 59 | int (*set_bytes_per_datum)(struct iio_ring_buffer *ring, size_t bpd); | ||
| 60 | int (*get_length)(struct iio_ring_buffer *ring); | ||
| 61 | int (*set_length)(struct iio_ring_buffer *ring, int length); | ||
| 62 | |||
| 63 | int (*is_enabled)(struct iio_ring_buffer *ring); | ||
| 64 | int (*enable)(struct iio_ring_buffer *ring); | ||
| 65 | }; | ||
| 66 | |||
| 67 | struct iio_ring_setup_ops { | ||
| 68 | int (*preenable)(struct iio_dev *); | ||
| 69 | int (*postenable)(struct iio_dev *); | ||
| 70 | int (*predisable)(struct iio_dev *); | ||
| 71 | int (*postdisable)(struct iio_dev *); | ||
| 72 | }; | ||
| 73 | |||
| 74 | /** | ||
| 75 | * struct iio_ring_buffer - general ring buffer structure | ||
| 76 | * @dev: ring buffer device struct | ||
| 77 | * @indio_dev: industrial I/O device structure | ||
| 78 | * @owner: module that owns the ring buffer (for ref counting) | ||
| 79 | * @length: [DEVICE] number of datums in ring | ||
| 80 | * @bytes_per_datum: [DEVICE] size of individual datum including timestamp | ||
| 81 | * @bpe: [DEVICE] size of individual channel value | ||
| 82 | * @scan_el_attrs: [DRIVER] control of scan elements if that scan mode | ||
| 83 | * control method is used | ||
| 84 | * @scan_count: [INTERN] the number of elements in the current scan mode | ||
| 85 | * @scan_mask: [INTERN] bitmask used in masking scan mode elements | ||
| 86 | * @scan_timestamp: [INTERN] does the scan mode include a timestamp | ||
| 87 | * @access_handler: [INTERN] chrdev access handling | ||
| 88 | * @access: [DRIVER] ring access functions associated with the | ||
| 89 | * implementation. | ||
| 90 | * @preenable: [DRIVER] function to run prior to marking ring enabled | ||
| 91 | * @postenable: [DRIVER] function to run after marking ring enabled | ||
| 92 | * @predisable: [DRIVER] function to run prior to marking ring disabled | ||
| 93 | * @postdisable: [DRIVER] function to run after marking ring disabled | ||
| 94 | **/ | ||
| 95 | struct iio_ring_buffer { | ||
| 96 | struct device dev; | ||
| 97 | struct iio_dev *indio_dev; | ||
| 98 | struct module *owner; | ||
| 99 | int length; | ||
| 100 | int bytes_per_datum; | ||
| 101 | int bpe; | ||
| 102 | struct attribute_group *scan_el_attrs; | ||
| 103 | int scan_count; | ||
| 104 | unsigned long scan_mask; | ||
| 105 | bool scan_timestamp; | ||
| 106 | struct iio_handler access_handler; | ||
| 107 | const struct iio_ring_access_funcs *access; | ||
| 108 | const struct iio_ring_setup_ops *setup_ops; | ||
| 109 | struct list_head scan_el_dev_attr_list; | ||
| 110 | |||
| 111 | wait_queue_head_t pollq; | ||
| 112 | bool stufftoread; | ||
| 113 | }; | ||
| 114 | |||
| 115 | /** | ||
| 116 | * iio_ring_buffer_init() - Initialize the buffer structure | ||
| 117 | * @ring: buffer to be initialized | ||
| 118 | * @dev_info: the iio device the buffer is assocated with | ||
| 119 | **/ | ||
| 120 | void iio_ring_buffer_init(struct iio_ring_buffer *ring, | ||
| 121 | struct iio_dev *dev_info); | ||
| 122 | |||
| 123 | /** | ||
| 124 | * __iio_update_ring_buffer() - update common elements of ring buffers | ||
| 125 | * @ring: ring buffer that is the event source | ||
| 126 | * @bytes_per_datum: size of individual datum including timestamp | ||
| 127 | * @length: number of datums in ring | ||
| 128 | **/ | ||
| 129 | static inline void __iio_update_ring_buffer(struct iio_ring_buffer *ring, | ||
| 130 | int bytes_per_datum, int length) | ||
| 131 | { | ||
| 132 | ring->bytes_per_datum = bytes_per_datum; | ||
| 133 | ring->length = length; | ||
| 134 | } | ||
| 135 | |||
| 136 | /* | ||
| 137 | * These are mainly provided to allow for a change of implementation if a device | ||
| 138 | * has a large number of scan elements | ||
| 139 | */ | ||
| 140 | #define IIO_MAX_SCAN_LENGTH 31 | ||
| 141 | |||
| 142 | /* note 0 used as error indicator as it doesn't make sense. */ | ||
| 143 | static inline u32 iio_scan_mask_match(u32 *av_masks, u32 mask) | ||
| 144 | { | ||
| 145 | while (*av_masks) { | ||
| 146 | if (!(~*av_masks & mask)) | ||
| 147 | return *av_masks; | ||
| 148 | av_masks++; | ||
| 149 | } | ||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | static inline int iio_scan_mask_query(struct iio_ring_buffer *ring, int bit) | ||
| 154 | { | ||
| 155 | struct iio_dev *dev_info = ring->indio_dev; | ||
| 156 | u32 mask; | ||
| 157 | |||
| 158 | if (bit > IIO_MAX_SCAN_LENGTH) | ||
| 159 | return -EINVAL; | ||
| 160 | |||
| 161 | if (!ring->scan_mask) | ||
| 162 | return 0; | ||
| 163 | |||
| 164 | if (dev_info->available_scan_masks) | ||
| 165 | mask = iio_scan_mask_match(dev_info->available_scan_masks, | ||
| 166 | ring->scan_mask); | ||
| 167 | else | ||
| 168 | mask = ring->scan_mask; | ||
| 169 | |||
| 170 | if (!mask) | ||
| 171 | return -EINVAL; | ||
| 172 | |||
| 173 | return !!(mask & (1 << bit)); | ||
| 174 | }; | ||
| 175 | |||
| 176 | /** | ||
| 177 | * iio_scan_mask_set() - set particular bit in the scan mask | ||
| 178 | * @ring: the ring buffer whose scan mask we are interested in | ||
| 179 | * @bit: the bit to be set. | ||
| 180 | **/ | ||
| 181 | static inline int iio_scan_mask_set(struct iio_ring_buffer *ring, int bit) | ||
| 182 | { | ||
| 183 | struct iio_dev *dev_info = ring->indio_dev; | ||
| 184 | u32 mask; | ||
| 185 | u32 trialmask = ring->scan_mask | (1 << bit); | ||
| 186 | |||
| 187 | if (bit > IIO_MAX_SCAN_LENGTH) | ||
| 188 | return -EINVAL; | ||
| 189 | if (dev_info->available_scan_masks) { | ||
| 190 | mask = iio_scan_mask_match(dev_info->available_scan_masks, | ||
| 191 | trialmask); | ||
| 192 | if (!mask) | ||
| 193 | return -EINVAL; | ||
| 194 | } | ||
| 195 | ring->scan_mask = trialmask; | ||
| 196 | ring->scan_count++; | ||
| 197 | |||
| 198 | return 0; | ||
| 199 | }; | ||
| 200 | |||
| 201 | /** | ||
| 202 | * iio_put_ring_buffer() - notify done with buffer | ||
| 203 | * @ring: the buffer we are done with. | ||
| 204 | **/ | ||
| 205 | static inline void iio_put_ring_buffer(struct iio_ring_buffer *ring) | ||
| 206 | { | ||
| 207 | put_device(&ring->dev); | ||
| 208 | }; | ||
| 209 | |||
| 210 | #define to_iio_ring_buffer(d) \ | ||
| 211 | container_of(d, struct iio_ring_buffer, dev) | ||
| 212 | |||
| 213 | /** | ||
| 214 | * iio_ring_buffer_register_ex() - register the buffer with IIO core | ||
| 215 | * @ring: the buffer to be registered | ||
| 216 | * @id: the id of the buffer (typically 0) | ||
| 217 | **/ | ||
| 218 | int iio_ring_buffer_register_ex(struct iio_ring_buffer *ring, int id, | ||
| 219 | const struct iio_chan_spec *channels, | ||
| 220 | int num_channels); | ||
| 221 | |||
| 222 | void iio_ring_access_release(struct device *dev); | ||
| 223 | |||
| 224 | /** | ||
| 225 | * iio_ring_buffer_unregister() - unregister the buffer from IIO core | ||
| 226 | * @ring: the buffer to be unregistered | ||
| 227 | **/ | ||
| 228 | void iio_ring_buffer_unregister(struct iio_ring_buffer *ring); | ||
| 229 | |||
| 230 | /** | ||
| 231 | * iio_read_ring_length() - attr func to get number of datums in the buffer | ||
| 232 | **/ | ||
| 233 | ssize_t iio_read_ring_length(struct device *dev, | ||
| 234 | struct device_attribute *attr, | ||
| 235 | char *buf); | ||
| 236 | /** | ||
| 237 | * iio_write_ring_length() - attr func to set number of datums in the buffer | ||
| 238 | **/ | ||
| 239 | ssize_t iio_write_ring_length(struct device *dev, | ||
| 240 | struct device_attribute *attr, | ||
| 241 | const char *buf, | ||
| 242 | size_t len); | ||
| 243 | /** | ||
| 244 | * iio_read_ring_bytes_per_datum() - attr for number of bytes in whole datum | ||
| 245 | **/ | ||
| 246 | ssize_t iio_read_ring_bytes_per_datum(struct device *dev, | ||
| 247 | struct device_attribute *attr, | ||
| 248 | char *buf); | ||
| 249 | /** | ||
| 250 | * iio_store_ring_enable() - attr to turn the buffer on | ||
| 251 | **/ | ||
| 252 | ssize_t iio_store_ring_enable(struct device *dev, | ||
| 253 | struct device_attribute *attr, | ||
| 254 | const char *buf, | ||
| 255 | size_t len); | ||
| 256 | /** | ||
| 257 | * iio_show_ring_enable() - attr to see if the buffer is on | ||
| 258 | **/ | ||
| 259 | ssize_t iio_show_ring_enable(struct device *dev, | ||
| 260 | struct device_attribute *attr, | ||
| 261 | char *buf); | ||
| 262 | #define IIO_RING_LENGTH_ATTR DEVICE_ATTR(length, S_IRUGO | S_IWUSR, \ | ||
| 263 | iio_read_ring_length, \ | ||
| 264 | iio_write_ring_length) | ||
| 265 | #define IIO_RING_BYTES_PER_DATUM_ATTR DEVICE_ATTR(bytes_per_datum, S_IRUGO | S_IWUSR, \ | ||
| 266 | iio_read_ring_bytes_per_datum, NULL) | ||
| 267 | #define IIO_RING_ENABLE_ATTR DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, \ | ||
| 268 | iio_show_ring_enable, \ | ||
| 269 | iio_store_ring_enable) | ||
| 270 | |||
| 271 | int iio_sw_ring_preenable(struct iio_dev *indio_dev); | ||
| 272 | |||
| 273 | #else /* CONFIG_IIO_RING_BUFFER */ | ||
| 274 | |||
| 275 | static inline int iio_ring_buffer_register_ex(struct iio_ring_buffer *ring, | ||
| 276 | int id, | ||
| 277 | struct iio_chan_spec *channels, | ||
| 278 | int num_channels) | ||
| 279 | { | ||
| 280 | return 0; | ||
| 281 | } | ||
| 282 | |||
| 283 | static inline void iio_ring_buffer_unregister(struct iio_ring_buffer *ring) | ||
| 284 | {}; | ||
| 285 | |||
| 286 | #endif /* CONFIG_IIO_RING_BUFFER */ | ||
| 287 | |||
| 288 | #endif /* _IIO_RING_GENERIC_H_ */ | ||
diff --git a/drivers/staging/iio/sysfs.h b/drivers/staging/iio/sysfs.h new file mode 100644 index 00000000000..dd79b584421 --- /dev/null +++ b/drivers/staging/iio/sysfs.h | |||
| @@ -0,0 +1,222 @@ | |||
| 1 | /* The industrial I/O core | ||
| 2 | * | ||
| 3 | *Copyright (c) 2008 Jonathan Cameron | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 as published by | ||
| 7 | * the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * General attributes | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef _INDUSTRIAL_IO_SYSFS_H_ | ||
| 13 | #define _INDUSTRIAL_IO_SYSFS_H_ | ||
| 14 | |||
| 15 | #include "iio.h" | ||
| 16 | |||
| 17 | /** | ||
| 18 | * struct iio_dev_attr - iio specific device attribute | ||
| 19 | * @dev_attr: underlying device attribute | ||
| 20 | * @address: associated register address | ||
| 21 | * @val2: secondary attribute value | ||
| 22 | * @l: list head for maintaining list of dynamically created attrs. | ||
| 23 | */ | ||
| 24 | struct iio_dev_attr { | ||
| 25 | struct device_attribute dev_attr; | ||
| 26 | int address; | ||
| 27 | int val2; | ||
| 28 | struct list_head l; | ||
| 29 | struct iio_chan_spec const *c; | ||
| 30 | }; | ||
| 31 | |||
| 32 | #define to_iio_dev_attr(_dev_attr) \ | ||
| 33 | container_of(_dev_attr, struct iio_dev_attr, dev_attr) | ||
| 34 | |||
| 35 | ssize_t iio_read_const_attr(struct device *dev, | ||
| 36 | struct device_attribute *attr, | ||
| 37 | char *len); | ||
| 38 | |||
| 39 | /** | ||
| 40 | * struct iio_const_attr - constant device specific attribute | ||
| 41 | * often used for things like available modes | ||
| 42 | * @string: attribute string | ||
| 43 | * @dev_attr: underlying device attribute | ||
| 44 | */ | ||
| 45 | struct iio_const_attr { | ||
| 46 | const char *string; | ||
| 47 | struct device_attribute dev_attr; | ||
| 48 | }; | ||
| 49 | |||
| 50 | #define to_iio_const_attr(_dev_attr) \ | ||
| 51 | container_of(_dev_attr, struct iio_const_attr, dev_attr) | ||
| 52 | |||
| 53 | /* Some attributes will be hard coded (device dependent) and not require an | ||
| 54 | address, in these cases pass a negative */ | ||
| 55 | #define IIO_ATTR(_name, _mode, _show, _store, _addr) \ | ||
| 56 | { .dev_attr = __ATTR(_name, _mode, _show, _store), \ | ||
| 57 | .address = _addr } | ||
| 58 | |||
| 59 | #define IIO_DEVICE_ATTR(_name, _mode, _show, _store, _addr) \ | ||
| 60 | struct iio_dev_attr iio_dev_attr_##_name \ | ||
| 61 | = IIO_ATTR(_name, _mode, _show, _store, _addr) | ||
| 62 | |||
| 63 | #define IIO_DEVICE_ATTR_NAMED(_vname, _name, _mode, _show, _store, _addr) \ | ||
| 64 | struct iio_dev_attr iio_dev_attr_##_vname \ | ||
| 65 | = IIO_ATTR(_name, _mode, _show, _store, _addr) | ||
| 66 | |||
| 67 | #define IIO_DEVICE_ATTR_2(_name, _mode, _show, _store, _addr, _val2) \ | ||
| 68 | struct iio_dev_attr iio_dev_attr_##_name \ | ||
| 69 | = IIO_ATTR_2(_name, _mode, _show, _store, _addr, _val2) | ||
| 70 | |||
| 71 | #define IIO_CONST_ATTR(_name, _string) \ | ||
| 72 | struct iio_const_attr iio_const_attr_##_name \ | ||
| 73 | = { .string = _string, \ | ||
| 74 | .dev_attr = __ATTR(_name, S_IRUGO, iio_read_const_attr, NULL)} | ||
| 75 | |||
| 76 | #define IIO_CONST_ATTR_NAMED(_vname, _name, _string) \ | ||
| 77 | struct iio_const_attr iio_const_attr_##_vname \ | ||
| 78 | = { .string = _string, \ | ||
| 79 | .dev_attr = __ATTR(_name, S_IRUGO, iio_read_const_attr, NULL)} | ||
| 80 | /* Generic attributes of onetype or another */ | ||
| 81 | |||
| 82 | /** | ||
| 83 | * IIO_DEV_ATTR_REV - revision number for the device | ||
| 84 | * @_show: output method for the attribute | ||
| 85 | * | ||
| 86 | * Very much device dependent. | ||
| 87 | **/ | ||
| 88 | #define IIO_DEV_ATTR_REV(_show) \ | ||
| 89 | IIO_DEVICE_ATTR(revision, S_IRUGO, _show, NULL, 0) | ||
| 90 | |||
| 91 | /** | ||
| 92 | * IIO_DEV_ATTR_RESET: resets the device | ||
| 93 | **/ | ||
| 94 | #define IIO_DEV_ATTR_RESET(_store) \ | ||
| 95 | IIO_DEVICE_ATTR(reset, S_IWUSR, NULL, _store, 0) | ||
| 96 | |||
| 97 | /** | ||
| 98 | * IIO_CONST_ATTR_NAME - constant identifier | ||
| 99 | * @_string: the name | ||
| 100 | **/ | ||
| 101 | #define IIO_CONST_ATTR_NAME(_string) \ | ||
| 102 | IIO_CONST_ATTR(name, _string) | ||
| 103 | |||
| 104 | /** | ||
| 105 | * IIO_DEV_ATTR_SAMP_FREQ - sets any internal clock frequency | ||
| 106 | * @_mode: sysfs file mode/permissions | ||
| 107 | * @_show: output method for the attribute | ||
| 108 | * @_store: input method for the attribute | ||
| 109 | **/ | ||
| 110 | #define IIO_DEV_ATTR_SAMP_FREQ(_mode, _show, _store) \ | ||
| 111 | IIO_DEVICE_ATTR(sampling_frequency, _mode, _show, _store, 0) | ||
| 112 | |||
| 113 | /** | ||
| 114 | * IIO_DEV_ATTR_AVAIL_SAMP_FREQ - list available sampling frequencies | ||
| 115 | * @_show: output method for the attribute | ||
| 116 | * | ||
| 117 | * May be mode dependent on some devices | ||
| 118 | **/ | ||
| 119 | /* Deprecated */ | ||
| 120 | #define IIO_DEV_ATTR_AVAIL_SAMP_FREQ(_show) \ | ||
| 121 | IIO_DEVICE_ATTR(available_sampling_frequency, S_IRUGO, _show, NULL, 0) | ||
| 122 | |||
| 123 | #define IIO_DEV_ATTR_SAMP_FREQ_AVAIL(_show) \ | ||
| 124 | IIO_DEVICE_ATTR(sampling_frequency_available, S_IRUGO, _show, NULL, 0) | ||
| 125 | /** | ||
| 126 | * IIO_CONST_ATTR_AVAIL_SAMP_FREQ - list available sampling frequencies | ||
| 127 | * @_string: frequency string for the attribute | ||
| 128 | * | ||
| 129 | * Constant version | ||
| 130 | **/ | ||
| 131 | #define IIO_CONST_ATTR_SAMP_FREQ_AVAIL(_string) \ | ||
| 132 | IIO_CONST_ATTR(sampling_frequency_available, _string) | ||
| 133 | |||
| 134 | /** | ||
| 135 | * IIO_DEV_ATTR_SW_RING_ENABLE - enable software ring buffer | ||
| 136 | * @_show: output method for the attribute | ||
| 137 | * @_store: input method for the attribute | ||
| 138 | * | ||
| 139 | * Success may be dependent on attachment of trigger previously. | ||
| 140 | **/ | ||
| 141 | #define IIO_DEV_ATTR_SW_RING_ENABLE(_show, _store) \ | ||
| 142 | IIO_DEVICE_ATTR(sw_ring_enable, S_IRUGO | S_IWUSR, _show, _store, 0) | ||
| 143 | |||
| 144 | /** | ||
| 145 | * IIO_DEV_ATTR_HW_RING_ENABLE - enable hardware ring buffer | ||
| 146 | * @_show: output method for the attribute | ||
| 147 | * @_store: input method for the attribute | ||
| 148 | * | ||
| 149 | * This is a different attribute from the software one as one can envision | ||
| 150 | * schemes where a combination of the two may be used. | ||
| 151 | **/ | ||
| 152 | #define IIO_DEV_ATTR_HW_RING_ENABLE(_show, _store) \ | ||
| 153 | IIO_DEVICE_ATTR(hw_ring_enable, S_IRUGO | S_IWUSR, _show, _store, 0) | ||
| 154 | |||
| 155 | #define IIO_DEV_ATTR_TEMP_RAW(_show) \ | ||
| 156 | IIO_DEVICE_ATTR(temp_raw, S_IRUGO, _show, NULL, 0) | ||
| 157 | |||
| 158 | #define IIO_CONST_ATTR_TEMP_OFFSET(_string) \ | ||
| 159 | IIO_CONST_ATTR(temp_offset, _string) | ||
| 160 | |||
| 161 | #define IIO_CONST_ATTR_TEMP_SCALE(_string) \ | ||
| 162 | IIO_CONST_ATTR(temp_scale, _string) | ||
| 163 | |||
| 164 | /* must match our channel defs */ | ||
| 165 | #define IIO_EV_CLASS_IN IIO_IN | ||
| 166 | #define IIO_EV_CLASS_IN_DIFF IIO_IN_DIFF | ||
| 167 | #define IIO_EV_CLASS_ACCEL IIO_ACCEL | ||
| 168 | #define IIO_EV_CLASS_GYRO IIO_GYRO | ||
| 169 | #define IIO_EV_CLASS_MAGN IIO_MAGN | ||
| 170 | #define IIO_EV_CLASS_LIGHT IIO_LIGHT | ||
| 171 | #define IIO_EV_CLASS_PROXIMITY IIO_PROXIMITY | ||
| 172 | #define IIO_EV_CLASS_TEMP IIO_TEMP | ||
| 173 | |||
| 174 | #define IIO_EV_MOD_X IIO_MOD_X | ||
| 175 | #define IIO_EV_MOD_Y IIO_MOD_Y | ||
| 176 | #define IIO_EV_MOD_Z IIO_MOD_Z | ||
| 177 | #define IIO_EV_MOD_X_AND_Y IIO_MOD_X_AND_Y | ||
| 178 | #define IIO_EV_MOD_X_ANX_Z IIO_MOD_X_AND_Z | ||
| 179 | #define IIO_EV_MOD_Y_AND_Z IIO_MOD_Y_AND_Z | ||
| 180 | #define IIO_EV_MOD_X_AND_Y_AND_Z IIO_MOD_X_AND_Y_AND_Z | ||
| 181 | #define IIO_EV_MOD_X_OR_Y IIO_MOD_X_OR_Y | ||
| 182 | #define IIO_EV_MOD_X_OR_Z IIO_MOD_X_OR_Z | ||
| 183 | #define IIO_EV_MOD_Y_OR_Z IIO_MOD_Y_OR_Z | ||
| 184 | #define IIO_EV_MOD_X_OR_Y_OR_Z IIO_MOD_X_OR_Y_OR_Z | ||
| 185 | |||
| 186 | #define IIO_EV_TYPE_THRESH 0 | ||
| 187 | #define IIO_EV_TYPE_MAG 1 | ||
| 188 | #define IIO_EV_TYPE_ROC 2 | ||
| 189 | |||
| 190 | #define IIO_EV_DIR_EITHER 0 | ||
| 191 | #define IIO_EV_DIR_RISING 1 | ||
| 192 | #define IIO_EV_DIR_FALLING 2 | ||
| 193 | |||
| 194 | #define IIO_EV_TYPE_MAX 8 | ||
| 195 | #define IIO_EV_BIT(type, direction) \ | ||
| 196 | (1 << (type*IIO_EV_TYPE_MAX + direction)) | ||
| 197 | |||
| 198 | #define IIO_EVENT_CODE(channelclass, orient_bit, number, \ | ||
| 199 | modifier, type, direction) \ | ||
| 200 | (channelclass | (orient_bit << 8) | ((number) << 9) | \ | ||
| 201 | ((modifier) << 13) | ((type) << 16) | ((direction) << 24)) | ||
| 202 | |||
| 203 | #define IIO_MOD_EVENT_CODE(channelclass, number, modifier, \ | ||
| 204 | type, direction) \ | ||
| 205 | IIO_EVENT_CODE(channelclass, 1, number, modifier, type, direction) | ||
| 206 | |||
| 207 | #define IIO_UNMOD_EVENT_CODE(channelclass, number, type, direction) \ | ||
| 208 | IIO_EVENT_CODE(channelclass, 0, number, 0, type, direction) | ||
| 209 | |||
| 210 | |||
| 211 | #define IIO_BUFFER_EVENT_CODE(code) \ | ||
| 212 | (IIO_EV_CLASS_BUFFER | (code << 8)) | ||
| 213 | |||
| 214 | #define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 24) & 0xf) | ||
| 215 | |||
| 216 | /* Event code number extraction depends on which type of event we have. | ||
| 217 | * Perhaps review this function in the future*/ | ||
| 218 | #define IIO_EVENT_CODE_EXTRACT_NUM(mask) ((mask >> 9) & 0x0f) | ||
| 219 | |||
| 220 | #define IIO_EVENT_CODE_EXTRACT_MODIFIER(mask) ((mask >> 13) & 0x7) | ||
| 221 | |||
| 222 | #endif /* _INDUSTRIAL_IO_SYSFS_H_ */ | ||
diff --git a/drivers/staging/iio/trigger.h b/drivers/staging/iio/trigger.h new file mode 100644 index 00000000000..e0b58ed749b --- /dev/null +++ b/drivers/staging/iio/trigger.h | |||
| @@ -0,0 +1,188 @@ | |||
| 1 | /* The industrial I/O core, trigger handling functions | ||
| 2 | * | ||
| 3 | * Copyright (c) 2008 Jonathan Cameron | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 as published by | ||
| 7 | * the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | #include <linux/irq.h> | ||
| 10 | |||
| 11 | #ifndef _IIO_TRIGGER_H_ | ||
| 12 | #define _IIO_TRIGGER_H_ | ||
| 13 | |||
| 14 | struct iio_subirq { | ||
| 15 | bool enabled; | ||
| 16 | }; | ||
| 17 | |||
| 18 | /** | ||
| 19 | * struct iio_trigger - industrial I/O trigger device | ||
| 20 | * | ||
| 21 | * @id: [INTERN] unique id number | ||
| 22 | * @name: [DRIVER] unique name | ||
| 23 | * @dev: [DRIVER] associated device (if relevant) | ||
| 24 | * @private_data: [DRIVER] device specific data | ||
| 25 | * @list: [INTERN] used in maintenance of global trigger list | ||
| 26 | * @alloc_list: [DRIVER] used for driver specific trigger list | ||
| 27 | * @owner: [DRIVER] used to monitor usage count of the trigger. | ||
| 28 | * @use_count: use count for the trigger | ||
| 29 | * @set_trigger_state: [DRIVER] switch on/off the trigger on demand | ||
| 30 | * @try_reenable: function to reenable the trigger when the | ||
| 31 | * use count is zero (may be NULL) | ||
| 32 | * @validate_device: function to validate the device when the | ||
| 33 | * current trigger gets changed. | ||
| 34 | * @subirq_chip: [INTERN] associate 'virtual' irq chip. | ||
| 35 | * @subirq_base: [INTERN] base number for irqs provided by trigger. | ||
| 36 | * @subirqs: [INTERN] information about the 'child' irqs. | ||
| 37 | * @pool: [INTERN] bitmap of irqs currently in use. | ||
| 38 | * @pool_lock: [INTERN] protection of the irq pool. | ||
| 39 | **/ | ||
| 40 | struct iio_trigger { | ||
| 41 | int id; | ||
| 42 | const char *name; | ||
| 43 | struct device dev; | ||
| 44 | |||
| 45 | void *private_data; | ||
| 46 | struct list_head list; | ||
| 47 | struct list_head alloc_list; | ||
| 48 | struct module *owner; | ||
| 49 | int use_count; | ||
| 50 | |||
| 51 | int (*set_trigger_state)(struct iio_trigger *trig, bool state); | ||
| 52 | int (*try_reenable)(struct iio_trigger *trig); | ||
| 53 | int (*validate_device)(struct iio_trigger *trig, | ||
| 54 | struct iio_dev *indio_dev); | ||
| 55 | |||
| 56 | struct irq_chip subirq_chip; | ||
| 57 | int subirq_base; | ||
| 58 | |||
| 59 | struct iio_subirq subirqs[CONFIG_IIO_CONSUMERS_PER_TRIGGER]; | ||
| 60 | unsigned long pool[BITS_TO_LONGS(CONFIG_IIO_CONSUMERS_PER_TRIGGER)]; | ||
| 61 | struct mutex pool_lock; | ||
| 62 | }; | ||
| 63 | |||
| 64 | /** | ||
| 65 | * struct iio_poll_func - poll function pair | ||
| 66 | * | ||
| 67 | * @private_data: data specific to device (passed into poll func) | ||
| 68 | * @h: the function that is actually run on trigger | ||
| 69 | * @thread: threaded interrupt part | ||
| 70 | * @type: the type of interrupt (basically if oneshot) | ||
| 71 | * @name: name used to identify the trigger consumer. | ||
| 72 | * @irq: the corresponding irq as allocated from the | ||
| 73 | * trigger pool | ||
| 74 | * @timestamp: some devices need a timestamp grabbed as soon | ||
| 75 | * as possible after the trigger - hence handler | ||
| 76 | * passes it via here. | ||
| 77 | **/ | ||
| 78 | struct iio_poll_func { | ||
| 79 | void *private_data; | ||
| 80 | irqreturn_t (*h)(int irq, void *p); | ||
| 81 | irqreturn_t (*thread)(int irq, void *p); | ||
| 82 | int type; | ||
| 83 | char *name; | ||
| 84 | int irq; | ||
| 85 | s64 timestamp; | ||
| 86 | }; | ||
| 87 | |||
| 88 | static inline struct iio_trigger *to_iio_trigger(struct device *d) | ||
| 89 | { | ||
| 90 | return container_of(d, struct iio_trigger, dev); | ||
| 91 | }; | ||
| 92 | |||
| 93 | static inline void iio_put_trigger(struct iio_trigger *trig) | ||
| 94 | { | ||
| 95 | put_device(&trig->dev); | ||
| 96 | module_put(trig->owner); | ||
| 97 | }; | ||
| 98 | |||
| 99 | static inline void iio_get_trigger(struct iio_trigger *trig) | ||
| 100 | { | ||
| 101 | __module_get(trig->owner); | ||
| 102 | get_device(&trig->dev); | ||
| 103 | }; | ||
| 104 | |||
| 105 | /** | ||
| 106 | * iio_trigger_register() - register a trigger with the IIO core | ||
| 107 | * @trig_info: trigger to be registered | ||
| 108 | **/ | ||
| 109 | int iio_trigger_register(struct iio_trigger *trig_info); | ||
| 110 | |||
| 111 | /** | ||
| 112 | * iio_trigger_unregister() - unregister a trigger from the core | ||
| 113 | * @trig_info: trigger to be unregistered | ||
| 114 | **/ | ||
| 115 | void iio_trigger_unregister(struct iio_trigger *trig_info); | ||
| 116 | |||
| 117 | /** | ||
| 118 | * iio_trigger_attach_poll_func() - add a function pair to be run on trigger | ||
| 119 | * @trig: trigger to which the function pair are being added | ||
| 120 | * @pf: poll function pair | ||
| 121 | **/ | ||
| 122 | int iio_trigger_attach_poll_func(struct iio_trigger *trig, | ||
| 123 | struct iio_poll_func *pf); | ||
| 124 | |||
| 125 | /** | ||
| 126 | * iio_trigger_dettach_poll_func() - remove function pair from those to be | ||
| 127 | * run on trigger | ||
| 128 | * @trig: trigger from which the function is being removed | ||
| 129 | * @pf: poll function pair | ||
| 130 | **/ | ||
| 131 | int iio_trigger_dettach_poll_func(struct iio_trigger *trig, | ||
| 132 | struct iio_poll_func *pf); | ||
| 133 | |||
| 134 | /** | ||
| 135 | * iio_trigger_poll() - called on a trigger occurring | ||
| 136 | * @trig: trigger which occurred | ||
| 137 | * | ||
| 138 | * Typically called in relevant hardware interrupt handler. | ||
| 139 | **/ | ||
| 140 | void iio_trigger_poll(struct iio_trigger *trig, s64 time); | ||
| 141 | void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time); | ||
| 142 | void iio_trigger_notify_done(struct iio_trigger *trig); | ||
| 143 | |||
| 144 | irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private); | ||
| 145 | |||
| 146 | static inline int iio_trigger_get_irq(struct iio_trigger *trig) | ||
| 147 | { | ||
| 148 | int ret; | ||
| 149 | mutex_lock(&trig->pool_lock); | ||
| 150 | ret = bitmap_find_free_region(trig->pool, | ||
| 151 | CONFIG_IIO_CONSUMERS_PER_TRIGGER, | ||
| 152 | ilog2(1)); | ||
| 153 | mutex_unlock(&trig->pool_lock); | ||
| 154 | if (ret >= 0) | ||
| 155 | ret += trig->subirq_base; | ||
| 156 | |||
| 157 | return ret; | ||
| 158 | }; | ||
| 159 | |||
| 160 | static inline void iio_trigger_put_irq(struct iio_trigger *trig, int irq) | ||
| 161 | { | ||
| 162 | mutex_lock(&trig->pool_lock); | ||
| 163 | clear_bit(irq - trig->subirq_base, trig->pool); | ||
| 164 | mutex_unlock(&trig->pool_lock); | ||
| 165 | }; | ||
| 166 | |||
| 167 | struct iio_poll_func | ||
| 168 | *iio_alloc_pollfunc(irqreturn_t (*h)(int irq, void *p), | ||
| 169 | irqreturn_t (*thread)(int irq, void *p), | ||
| 170 | int type, | ||
| 171 | void *private, | ||
| 172 | const char *fmt, | ||
| 173 | ...); | ||
| 174 | void iio_dealloc_pollfunc(struct iio_poll_func *pf); | ||
| 175 | irqreturn_t iio_pollfunc_store_time(int irq, void *p); | ||
| 176 | |||
| 177 | /* | ||
| 178 | * Two functions for common case where all that happens is a pollfunc | ||
| 179 | * is attached and detached from a trigger | ||
| 180 | */ | ||
| 181 | int iio_triggered_ring_postenable(struct iio_dev *indio_dev); | ||
| 182 | int iio_triggered_ring_predisable(struct iio_dev *indio_dev); | ||
| 183 | |||
| 184 | struct iio_trigger *iio_allocate_trigger(const char *fmt, ...) | ||
| 185 | __attribute__((format(printf, 1, 2))); | ||
| 186 | void iio_free_trigger(struct iio_trigger *trig); | ||
| 187 | |||
| 188 | #endif /* _IIO_TRIGGER_H_ */ | ||
diff --git a/drivers/staging/iio/trigger_consumer.h b/drivers/staging/iio/trigger_consumer.h new file mode 100644 index 00000000000..9d52d963777 --- /dev/null +++ b/drivers/staging/iio/trigger_consumer.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | |||
| 2 | /* The industrial I/O core, trigger consumer handling functions | ||
| 3 | * | ||
| 4 | * Copyright (c) 2008 Jonathan Cameron | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License version 2 as published by | ||
| 8 | * the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifdef CONFIG_IIO_TRIGGER | ||
| 12 | /** | ||
| 13 | * iio_device_register_trigger_consumer() - set up an iio_dev to use triggers | ||
| 14 | * @dev_info: iio_dev associated with the device that will consume the trigger | ||
| 15 | **/ | ||
| 16 | int iio_device_register_trigger_consumer(struct iio_dev *dev_info); | ||
| 17 | |||
| 18 | /** | ||
| 19 | * iio_device_unregister_trigger_consumer() - reverse the registration process | ||
| 20 | * @dev_info: iio_dev associated with the device that consumed the trigger | ||
| 21 | **/ | ||
| 22 | int iio_device_unregister_trigger_consumer(struct iio_dev *dev_info); | ||
| 23 | |||
| 24 | #else | ||
| 25 | |||
| 26 | /** | ||
| 27 | * iio_device_register_trigger_consumer() - set up an iio_dev to use triggers | ||
| 28 | * @dev_info: iio_dev associated with the device that will consume the trigger | ||
| 29 | **/ | ||
| 30 | static int iio_device_register_trigger_consumer(struct iio_dev *dev_info) | ||
| 31 | { | ||
| 32 | return 0; | ||
| 33 | }; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * iio_device_unregister_trigger_consumer() - reverse the registration process | ||
| 37 | * @dev_info: iio_dev associated with the device that consumed the trigger | ||
| 38 | **/ | ||
| 39 | static int iio_device_unregister_trigger_consumer(struct iio_dev *dev_info) | ||
| 40 | { | ||
| 41 | return 0; | ||
| 42 | }; | ||
| 43 | |||
| 44 | #endif /* CONFIG_TRIGGER_CONSUMER */ | ||
| 45 | |||
| 46 | |||
| 47 | |||
