1*c5bdbef7Ssrinivas pandruvada /* 2*c5bdbef7Ssrinivas pandruvada * HID Sensors Driver 3*c5bdbef7Ssrinivas pandruvada * Copyright (c) 2012, Intel Corporation. 4*c5bdbef7Ssrinivas pandruvada * 5*c5bdbef7Ssrinivas pandruvada * This program is free software; you can redistribute it and/or modify it 6*c5bdbef7Ssrinivas pandruvada * under the terms and conditions of the GNU General Public License, 7*c5bdbef7Ssrinivas pandruvada * version 2, as published by the Free Software Foundation. 8*c5bdbef7Ssrinivas pandruvada * 9*c5bdbef7Ssrinivas pandruvada * This program is distributed in the hope it will be useful, but WITHOUT 10*c5bdbef7Ssrinivas pandruvada * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11*c5bdbef7Ssrinivas pandruvada * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12*c5bdbef7Ssrinivas pandruvada * more details. 13*c5bdbef7Ssrinivas pandruvada * 14*c5bdbef7Ssrinivas pandruvada * You should have received a copy of the GNU General Public License along with 15*c5bdbef7Ssrinivas pandruvada * this program; if not, write to the Free Software Foundation, Inc., 16*c5bdbef7Ssrinivas pandruvada * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 17*c5bdbef7Ssrinivas pandruvada * 18*c5bdbef7Ssrinivas pandruvada */ 19*c5bdbef7Ssrinivas pandruvada #include <linux/device.h> 20*c5bdbef7Ssrinivas pandruvada #include <linux/platform_device.h> 21*c5bdbef7Ssrinivas pandruvada #include <linux/module.h> 22*c5bdbef7Ssrinivas pandruvada #include <linux/interrupt.h> 23*c5bdbef7Ssrinivas pandruvada #include <linux/irq.h> 24*c5bdbef7Ssrinivas pandruvada #include <linux/slab.h> 25*c5bdbef7Ssrinivas pandruvada #include <linux/hid-sensor-hub.h> 26*c5bdbef7Ssrinivas pandruvada #include <linux/iio/iio.h> 27*c5bdbef7Ssrinivas pandruvada #include <linux/iio/sysfs.h> 28*c5bdbef7Ssrinivas pandruvada #include <linux/iio/buffer.h> 29*c5bdbef7Ssrinivas pandruvada #include <linux/iio/trigger_consumer.h> 30*c5bdbef7Ssrinivas pandruvada #include <linux/iio/triggered_buffer.h> 31*c5bdbef7Ssrinivas pandruvada #include "../common/hid-sensors/hid-sensor-attributes.h" 32*c5bdbef7Ssrinivas pandruvada #include "../common/hid-sensors/hid-sensor-trigger.h" 33*c5bdbef7Ssrinivas pandruvada 34*c5bdbef7Ssrinivas pandruvada /*Format: HID-SENSOR-usage_id_in_hex*/ 35*c5bdbef7Ssrinivas pandruvada /*Usage ID from spec for Gyro-3D: 0x200076*/ 36*c5bdbef7Ssrinivas pandruvada #define DRIVER_NAME "HID-SENSOR-200076" 37*c5bdbef7Ssrinivas pandruvada 38*c5bdbef7Ssrinivas pandruvada enum gyro_3d_channel { 39*c5bdbef7Ssrinivas pandruvada CHANNEL_SCAN_INDEX_X, 40*c5bdbef7Ssrinivas pandruvada CHANNEL_SCAN_INDEX_Y, 41*c5bdbef7Ssrinivas pandruvada CHANNEL_SCAN_INDEX_Z, 42*c5bdbef7Ssrinivas pandruvada GYRO_3D_CHANNEL_MAX, 43*c5bdbef7Ssrinivas pandruvada }; 44*c5bdbef7Ssrinivas pandruvada 45*c5bdbef7Ssrinivas pandruvada struct gyro_3d_state { 46*c5bdbef7Ssrinivas pandruvada struct hid_sensor_hub_callbacks callbacks; 47*c5bdbef7Ssrinivas pandruvada struct hid_sensor_iio_common common_attributes; 48*c5bdbef7Ssrinivas pandruvada struct hid_sensor_hub_attribute_info gyro[GYRO_3D_CHANNEL_MAX]; 49*c5bdbef7Ssrinivas pandruvada u32 gyro_val[GYRO_3D_CHANNEL_MAX]; 50*c5bdbef7Ssrinivas pandruvada }; 51*c5bdbef7Ssrinivas pandruvada 52*c5bdbef7Ssrinivas pandruvada static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = { 53*c5bdbef7Ssrinivas pandruvada HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS, 54*c5bdbef7Ssrinivas pandruvada HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS, 55*c5bdbef7Ssrinivas pandruvada HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS 56*c5bdbef7Ssrinivas pandruvada }; 57*c5bdbef7Ssrinivas pandruvada 58*c5bdbef7Ssrinivas pandruvada /* Channel definitions */ 59*c5bdbef7Ssrinivas pandruvada static const struct iio_chan_spec gyro_3d_channels[] = { 60*c5bdbef7Ssrinivas pandruvada { 61*c5bdbef7Ssrinivas pandruvada .type = IIO_ANGL_VEL, 62*c5bdbef7Ssrinivas pandruvada .modified = 1, 63*c5bdbef7Ssrinivas pandruvada .channel2 = IIO_MOD_X, 64*c5bdbef7Ssrinivas pandruvada .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | 65*c5bdbef7Ssrinivas pandruvada IIO_CHAN_INFO_SCALE_SHARED_BIT | 66*c5bdbef7Ssrinivas pandruvada IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | 67*c5bdbef7Ssrinivas pandruvada IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, 68*c5bdbef7Ssrinivas pandruvada .scan_index = CHANNEL_SCAN_INDEX_X, 69*c5bdbef7Ssrinivas pandruvada }, { 70*c5bdbef7Ssrinivas pandruvada .type = IIO_ANGL_VEL, 71*c5bdbef7Ssrinivas pandruvada .modified = 1, 72*c5bdbef7Ssrinivas pandruvada .channel2 = IIO_MOD_Y, 73*c5bdbef7Ssrinivas pandruvada .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | 74*c5bdbef7Ssrinivas pandruvada IIO_CHAN_INFO_SCALE_SHARED_BIT | 75*c5bdbef7Ssrinivas pandruvada IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | 76*c5bdbef7Ssrinivas pandruvada IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, 77*c5bdbef7Ssrinivas pandruvada .scan_index = CHANNEL_SCAN_INDEX_Y, 78*c5bdbef7Ssrinivas pandruvada }, { 79*c5bdbef7Ssrinivas pandruvada .type = IIO_ANGL_VEL, 80*c5bdbef7Ssrinivas pandruvada .modified = 1, 81*c5bdbef7Ssrinivas pandruvada .channel2 = IIO_MOD_Z, 82*c5bdbef7Ssrinivas pandruvada .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | 83*c5bdbef7Ssrinivas pandruvada IIO_CHAN_INFO_SCALE_SHARED_BIT | 84*c5bdbef7Ssrinivas pandruvada IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | 85*c5bdbef7Ssrinivas pandruvada IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, 86*c5bdbef7Ssrinivas pandruvada .scan_index = CHANNEL_SCAN_INDEX_Z, 87*c5bdbef7Ssrinivas pandruvada } 88*c5bdbef7Ssrinivas pandruvada }; 89*c5bdbef7Ssrinivas pandruvada 90*c5bdbef7Ssrinivas pandruvada /* Adjust channel real bits based on report descriptor */ 91*c5bdbef7Ssrinivas pandruvada static void gyro_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels, 92*c5bdbef7Ssrinivas pandruvada int channel, int size) 93*c5bdbef7Ssrinivas pandruvada { 94*c5bdbef7Ssrinivas pandruvada channels[channel].scan_type.sign = 's'; 95*c5bdbef7Ssrinivas pandruvada /* Real storage bits will change based on the report desc. */ 96*c5bdbef7Ssrinivas pandruvada channels[channel].scan_type.realbits = size * 8; 97*c5bdbef7Ssrinivas pandruvada /* Maximum size of a sample to capture is u32 */ 98*c5bdbef7Ssrinivas pandruvada channels[channel].scan_type.storagebits = sizeof(u32) * 8; 99*c5bdbef7Ssrinivas pandruvada } 100*c5bdbef7Ssrinivas pandruvada 101*c5bdbef7Ssrinivas pandruvada /* Channel read_raw handler */ 102*c5bdbef7Ssrinivas pandruvada static int gyro_3d_read_raw(struct iio_dev *indio_dev, 103*c5bdbef7Ssrinivas pandruvada struct iio_chan_spec const *chan, 104*c5bdbef7Ssrinivas pandruvada int *val, int *val2, 105*c5bdbef7Ssrinivas pandruvada long mask) 106*c5bdbef7Ssrinivas pandruvada { 107*c5bdbef7Ssrinivas pandruvada struct gyro_3d_state *gyro_state = iio_priv(indio_dev); 108*c5bdbef7Ssrinivas pandruvada int report_id = -1; 109*c5bdbef7Ssrinivas pandruvada u32 address; 110*c5bdbef7Ssrinivas pandruvada int ret; 111*c5bdbef7Ssrinivas pandruvada int ret_type; 112*c5bdbef7Ssrinivas pandruvada 113*c5bdbef7Ssrinivas pandruvada *val = 0; 114*c5bdbef7Ssrinivas pandruvada *val2 = 0; 115*c5bdbef7Ssrinivas pandruvada switch (mask) { 116*c5bdbef7Ssrinivas pandruvada case 0: 117*c5bdbef7Ssrinivas pandruvada report_id = gyro_state->gyro[chan->scan_index].report_id; 118*c5bdbef7Ssrinivas pandruvada address = gyro_3d_addresses[chan->scan_index]; 119*c5bdbef7Ssrinivas pandruvada if (report_id >= 0) 120*c5bdbef7Ssrinivas pandruvada *val = sensor_hub_input_attr_get_raw_value( 121*c5bdbef7Ssrinivas pandruvada gyro_state->common_attributes.hsdev, 122*c5bdbef7Ssrinivas pandruvada HID_USAGE_SENSOR_GYRO_3D, address, 123*c5bdbef7Ssrinivas pandruvada report_id); 124*c5bdbef7Ssrinivas pandruvada else { 125*c5bdbef7Ssrinivas pandruvada *val = 0; 126*c5bdbef7Ssrinivas pandruvada return -EINVAL; 127*c5bdbef7Ssrinivas pandruvada } 128*c5bdbef7Ssrinivas pandruvada ret_type = IIO_VAL_INT; 129*c5bdbef7Ssrinivas pandruvada break; 130*c5bdbef7Ssrinivas pandruvada case IIO_CHAN_INFO_SCALE: 131*c5bdbef7Ssrinivas pandruvada *val = gyro_state->gyro[CHANNEL_SCAN_INDEX_X].units; 132*c5bdbef7Ssrinivas pandruvada ret_type = IIO_VAL_INT; 133*c5bdbef7Ssrinivas pandruvada break; 134*c5bdbef7Ssrinivas pandruvada case IIO_CHAN_INFO_OFFSET: 135*c5bdbef7Ssrinivas pandruvada *val = hid_sensor_convert_exponent( 136*c5bdbef7Ssrinivas pandruvada gyro_state->gyro[CHANNEL_SCAN_INDEX_X].unit_expo); 137*c5bdbef7Ssrinivas pandruvada ret_type = IIO_VAL_INT; 138*c5bdbef7Ssrinivas pandruvada break; 139*c5bdbef7Ssrinivas pandruvada case IIO_CHAN_INFO_SAMP_FREQ: 140*c5bdbef7Ssrinivas pandruvada ret = hid_sensor_read_samp_freq_value( 141*c5bdbef7Ssrinivas pandruvada &gyro_state->common_attributes, val, val2); 142*c5bdbef7Ssrinivas pandruvada ret_type = IIO_VAL_INT_PLUS_MICRO; 143*c5bdbef7Ssrinivas pandruvada break; 144*c5bdbef7Ssrinivas pandruvada case IIO_CHAN_INFO_HYSTERESIS: 145*c5bdbef7Ssrinivas pandruvada ret = hid_sensor_read_raw_hyst_value( 146*c5bdbef7Ssrinivas pandruvada &gyro_state->common_attributes, val, val2); 147*c5bdbef7Ssrinivas pandruvada ret_type = IIO_VAL_INT_PLUS_MICRO; 148*c5bdbef7Ssrinivas pandruvada break; 149*c5bdbef7Ssrinivas pandruvada default: 150*c5bdbef7Ssrinivas pandruvada ret_type = -EINVAL; 151*c5bdbef7Ssrinivas pandruvada break; 152*c5bdbef7Ssrinivas pandruvada } 153*c5bdbef7Ssrinivas pandruvada 154*c5bdbef7Ssrinivas pandruvada return ret_type; 155*c5bdbef7Ssrinivas pandruvada } 156*c5bdbef7Ssrinivas pandruvada 157*c5bdbef7Ssrinivas pandruvada /* Channel write_raw handler */ 158*c5bdbef7Ssrinivas pandruvada static int gyro_3d_write_raw(struct iio_dev *indio_dev, 159*c5bdbef7Ssrinivas pandruvada struct iio_chan_spec const *chan, 160*c5bdbef7Ssrinivas pandruvada int val, 161*c5bdbef7Ssrinivas pandruvada int val2, 162*c5bdbef7Ssrinivas pandruvada long mask) 163*c5bdbef7Ssrinivas pandruvada { 164*c5bdbef7Ssrinivas pandruvada struct gyro_3d_state *gyro_state = iio_priv(indio_dev); 165*c5bdbef7Ssrinivas pandruvada int ret = 0; 166*c5bdbef7Ssrinivas pandruvada 167*c5bdbef7Ssrinivas pandruvada switch (mask) { 168*c5bdbef7Ssrinivas pandruvada case IIO_CHAN_INFO_SAMP_FREQ: 169*c5bdbef7Ssrinivas pandruvada ret = hid_sensor_write_samp_freq_value( 170*c5bdbef7Ssrinivas pandruvada &gyro_state->common_attributes, val, val2); 171*c5bdbef7Ssrinivas pandruvada break; 172*c5bdbef7Ssrinivas pandruvada case IIO_CHAN_INFO_HYSTERESIS: 173*c5bdbef7Ssrinivas pandruvada ret = hid_sensor_write_raw_hyst_value( 174*c5bdbef7Ssrinivas pandruvada &gyro_state->common_attributes, val, val2); 175*c5bdbef7Ssrinivas pandruvada break; 176*c5bdbef7Ssrinivas pandruvada default: 177*c5bdbef7Ssrinivas pandruvada ret = -EINVAL; 178*c5bdbef7Ssrinivas pandruvada } 179*c5bdbef7Ssrinivas pandruvada 180*c5bdbef7Ssrinivas pandruvada return ret; 181*c5bdbef7Ssrinivas pandruvada } 182*c5bdbef7Ssrinivas pandruvada 183*c5bdbef7Ssrinivas pandruvada static int gyro_3d_write_raw_get_fmt(struct iio_dev *indio_dev, 184*c5bdbef7Ssrinivas pandruvada struct iio_chan_spec const *chan, 185*c5bdbef7Ssrinivas pandruvada long mask) 186*c5bdbef7Ssrinivas pandruvada { 187*c5bdbef7Ssrinivas pandruvada return IIO_VAL_INT_PLUS_MICRO; 188*c5bdbef7Ssrinivas pandruvada } 189*c5bdbef7Ssrinivas pandruvada 190*c5bdbef7Ssrinivas pandruvada static const struct iio_info gyro_3d_info = { 191*c5bdbef7Ssrinivas pandruvada .driver_module = THIS_MODULE, 192*c5bdbef7Ssrinivas pandruvada .read_raw = &gyro_3d_read_raw, 193*c5bdbef7Ssrinivas pandruvada .write_raw = &gyro_3d_write_raw, 194*c5bdbef7Ssrinivas pandruvada .write_raw_get_fmt = &gyro_3d_write_raw_get_fmt, 195*c5bdbef7Ssrinivas pandruvada }; 196*c5bdbef7Ssrinivas pandruvada 197*c5bdbef7Ssrinivas pandruvada /* Function to push data to buffer */ 198*c5bdbef7Ssrinivas pandruvada static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) 199*c5bdbef7Ssrinivas pandruvada { 200*c5bdbef7Ssrinivas pandruvada struct iio_buffer *buffer = indio_dev->buffer; 201*c5bdbef7Ssrinivas pandruvada s64 timestamp = iio_get_time_ns(); 202*c5bdbef7Ssrinivas pandruvada int datum_sz; 203*c5bdbef7Ssrinivas pandruvada 204*c5bdbef7Ssrinivas pandruvada dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); 205*c5bdbef7Ssrinivas pandruvada if (!buffer) { 206*c5bdbef7Ssrinivas pandruvada dev_err(&indio_dev->dev, "Buffer == NULL\n"); 207*c5bdbef7Ssrinivas pandruvada return; 208*c5bdbef7Ssrinivas pandruvada } 209*c5bdbef7Ssrinivas pandruvada datum_sz = buffer->access->get_bytes_per_datum(buffer); 210*c5bdbef7Ssrinivas pandruvada if (len > datum_sz) { 211*c5bdbef7Ssrinivas pandruvada dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len, 212*c5bdbef7Ssrinivas pandruvada datum_sz); 213*c5bdbef7Ssrinivas pandruvada return; 214*c5bdbef7Ssrinivas pandruvada } 215*c5bdbef7Ssrinivas pandruvada buffer->access->store_to(buffer, (u8 *)data, timestamp); 216*c5bdbef7Ssrinivas pandruvada } 217*c5bdbef7Ssrinivas pandruvada 218*c5bdbef7Ssrinivas pandruvada /* Callback handler to send event after all samples are received and captured */ 219*c5bdbef7Ssrinivas pandruvada static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, 220*c5bdbef7Ssrinivas pandruvada unsigned usage_id, 221*c5bdbef7Ssrinivas pandruvada void *priv) 222*c5bdbef7Ssrinivas pandruvada { 223*c5bdbef7Ssrinivas pandruvada struct iio_dev *indio_dev = platform_get_drvdata(priv); 224*c5bdbef7Ssrinivas pandruvada struct gyro_3d_state *gyro_state = iio_priv(indio_dev); 225*c5bdbef7Ssrinivas pandruvada 226*c5bdbef7Ssrinivas pandruvada dev_dbg(&indio_dev->dev, "gyro_3d_proc_event [%d]\n", 227*c5bdbef7Ssrinivas pandruvada gyro_state->common_attributes.data_ready); 228*c5bdbef7Ssrinivas pandruvada if (gyro_state->common_attributes.data_ready) 229*c5bdbef7Ssrinivas pandruvada hid_sensor_push_data(indio_dev, 230*c5bdbef7Ssrinivas pandruvada (u8 *)gyro_state->gyro_val, 231*c5bdbef7Ssrinivas pandruvada sizeof(gyro_state->gyro_val)); 232*c5bdbef7Ssrinivas pandruvada 233*c5bdbef7Ssrinivas pandruvada return 0; 234*c5bdbef7Ssrinivas pandruvada } 235*c5bdbef7Ssrinivas pandruvada 236*c5bdbef7Ssrinivas pandruvada /* Capture samples in local storage */ 237*c5bdbef7Ssrinivas pandruvada static int gyro_3d_capture_sample(struct hid_sensor_hub_device *hsdev, 238*c5bdbef7Ssrinivas pandruvada unsigned usage_id, 239*c5bdbef7Ssrinivas pandruvada size_t raw_len, char *raw_data, 240*c5bdbef7Ssrinivas pandruvada void *priv) 241*c5bdbef7Ssrinivas pandruvada { 242*c5bdbef7Ssrinivas pandruvada struct iio_dev *indio_dev = platform_get_drvdata(priv); 243*c5bdbef7Ssrinivas pandruvada struct gyro_3d_state *gyro_state = iio_priv(indio_dev); 244*c5bdbef7Ssrinivas pandruvada int offset; 245*c5bdbef7Ssrinivas pandruvada int ret = -EINVAL; 246*c5bdbef7Ssrinivas pandruvada 247*c5bdbef7Ssrinivas pandruvada switch (usage_id) { 248*c5bdbef7Ssrinivas pandruvada case HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS: 249*c5bdbef7Ssrinivas pandruvada case HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS: 250*c5bdbef7Ssrinivas pandruvada case HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS: 251*c5bdbef7Ssrinivas pandruvada offset = usage_id - HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS; 252*c5bdbef7Ssrinivas pandruvada gyro_state->gyro_val[CHANNEL_SCAN_INDEX_X + offset] = 253*c5bdbef7Ssrinivas pandruvada *(u32 *)raw_data; 254*c5bdbef7Ssrinivas pandruvada ret = 0; 255*c5bdbef7Ssrinivas pandruvada break; 256*c5bdbef7Ssrinivas pandruvada default: 257*c5bdbef7Ssrinivas pandruvada break; 258*c5bdbef7Ssrinivas pandruvada } 259*c5bdbef7Ssrinivas pandruvada 260*c5bdbef7Ssrinivas pandruvada return ret; 261*c5bdbef7Ssrinivas pandruvada } 262*c5bdbef7Ssrinivas pandruvada 263*c5bdbef7Ssrinivas pandruvada /* Parse report which is specific to an usage id*/ 264*c5bdbef7Ssrinivas pandruvada static int gyro_3d_parse_report(struct platform_device *pdev, 265*c5bdbef7Ssrinivas pandruvada struct hid_sensor_hub_device *hsdev, 266*c5bdbef7Ssrinivas pandruvada struct iio_chan_spec *channels, 267*c5bdbef7Ssrinivas pandruvada unsigned usage_id, 268*c5bdbef7Ssrinivas pandruvada struct gyro_3d_state *st) 269*c5bdbef7Ssrinivas pandruvada { 270*c5bdbef7Ssrinivas pandruvada int ret; 271*c5bdbef7Ssrinivas pandruvada int i; 272*c5bdbef7Ssrinivas pandruvada 273*c5bdbef7Ssrinivas pandruvada for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) { 274*c5bdbef7Ssrinivas pandruvada ret = sensor_hub_input_get_attribute_info(hsdev, 275*c5bdbef7Ssrinivas pandruvada HID_INPUT_REPORT, 276*c5bdbef7Ssrinivas pandruvada usage_id, 277*c5bdbef7Ssrinivas pandruvada HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS + i, 278*c5bdbef7Ssrinivas pandruvada &st->gyro[CHANNEL_SCAN_INDEX_X + i]); 279*c5bdbef7Ssrinivas pandruvada if (ret < 0) 280*c5bdbef7Ssrinivas pandruvada break; 281*c5bdbef7Ssrinivas pandruvada gyro_3d_adjust_channel_bit_mask(channels, 282*c5bdbef7Ssrinivas pandruvada CHANNEL_SCAN_INDEX_X + i, 283*c5bdbef7Ssrinivas pandruvada st->gyro[CHANNEL_SCAN_INDEX_X + i].size); 284*c5bdbef7Ssrinivas pandruvada } 285*c5bdbef7Ssrinivas pandruvada dev_dbg(&pdev->dev, "gyro_3d %x:%x, %x:%x, %x:%x\n", 286*c5bdbef7Ssrinivas pandruvada st->gyro[0].index, 287*c5bdbef7Ssrinivas pandruvada st->gyro[0].report_id, 288*c5bdbef7Ssrinivas pandruvada st->gyro[1].index, st->gyro[1].report_id, 289*c5bdbef7Ssrinivas pandruvada st->gyro[2].index, st->gyro[2].report_id); 290*c5bdbef7Ssrinivas pandruvada 291*c5bdbef7Ssrinivas pandruvada return ret; 292*c5bdbef7Ssrinivas pandruvada } 293*c5bdbef7Ssrinivas pandruvada 294*c5bdbef7Ssrinivas pandruvada /* Function to initialize the processing for usage id */ 295*c5bdbef7Ssrinivas pandruvada static int __devinit hid_gyro_3d_probe(struct platform_device *pdev) 296*c5bdbef7Ssrinivas pandruvada { 297*c5bdbef7Ssrinivas pandruvada int ret = 0; 298*c5bdbef7Ssrinivas pandruvada static const char *name = "gyro_3d"; 299*c5bdbef7Ssrinivas pandruvada struct iio_dev *indio_dev; 300*c5bdbef7Ssrinivas pandruvada struct gyro_3d_state *gyro_state; 301*c5bdbef7Ssrinivas pandruvada struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; 302*c5bdbef7Ssrinivas pandruvada struct iio_chan_spec *channels; 303*c5bdbef7Ssrinivas pandruvada 304*c5bdbef7Ssrinivas pandruvada indio_dev = iio_device_alloc(sizeof(struct gyro_3d_state)); 305*c5bdbef7Ssrinivas pandruvada if (indio_dev == NULL) { 306*c5bdbef7Ssrinivas pandruvada ret = -ENOMEM; 307*c5bdbef7Ssrinivas pandruvada goto error_ret; 308*c5bdbef7Ssrinivas pandruvada } 309*c5bdbef7Ssrinivas pandruvada platform_set_drvdata(pdev, indio_dev); 310*c5bdbef7Ssrinivas pandruvada 311*c5bdbef7Ssrinivas pandruvada gyro_state = iio_priv(indio_dev); 312*c5bdbef7Ssrinivas pandruvada gyro_state->common_attributes.hsdev = hsdev; 313*c5bdbef7Ssrinivas pandruvada gyro_state->common_attributes.pdev = pdev; 314*c5bdbef7Ssrinivas pandruvada 315*c5bdbef7Ssrinivas pandruvada ret = hid_sensor_parse_common_attributes(hsdev, 316*c5bdbef7Ssrinivas pandruvada HID_USAGE_SENSOR_GYRO_3D, 317*c5bdbef7Ssrinivas pandruvada &gyro_state->common_attributes); 318*c5bdbef7Ssrinivas pandruvada if (ret) { 319*c5bdbef7Ssrinivas pandruvada dev_err(&pdev->dev, "failed to setup common attributes\n"); 320*c5bdbef7Ssrinivas pandruvada goto error_free_dev; 321*c5bdbef7Ssrinivas pandruvada } 322*c5bdbef7Ssrinivas pandruvada 323*c5bdbef7Ssrinivas pandruvada channels = kmemdup(gyro_3d_channels, 324*c5bdbef7Ssrinivas pandruvada sizeof(gyro_3d_channels), 325*c5bdbef7Ssrinivas pandruvada GFP_KERNEL); 326*c5bdbef7Ssrinivas pandruvada if (!channels) { 327*c5bdbef7Ssrinivas pandruvada dev_err(&pdev->dev, "failed to duplicate channels\n"); 328*c5bdbef7Ssrinivas pandruvada goto error_free_dev; 329*c5bdbef7Ssrinivas pandruvada } 330*c5bdbef7Ssrinivas pandruvada 331*c5bdbef7Ssrinivas pandruvada ret = gyro_3d_parse_report(pdev, hsdev, channels, 332*c5bdbef7Ssrinivas pandruvada HID_USAGE_SENSOR_GYRO_3D, gyro_state); 333*c5bdbef7Ssrinivas pandruvada if (ret) { 334*c5bdbef7Ssrinivas pandruvada dev_err(&pdev->dev, "failed to setup attributes\n"); 335*c5bdbef7Ssrinivas pandruvada goto error_free_dev_mem; 336*c5bdbef7Ssrinivas pandruvada } 337*c5bdbef7Ssrinivas pandruvada 338*c5bdbef7Ssrinivas pandruvada indio_dev->channels = channels; 339*c5bdbef7Ssrinivas pandruvada indio_dev->num_channels = ARRAY_SIZE(gyro_3d_channels); 340*c5bdbef7Ssrinivas pandruvada indio_dev->dev.parent = &pdev->dev; 341*c5bdbef7Ssrinivas pandruvada indio_dev->info = &gyro_3d_info; 342*c5bdbef7Ssrinivas pandruvada indio_dev->name = name; 343*c5bdbef7Ssrinivas pandruvada indio_dev->modes = INDIO_DIRECT_MODE; 344*c5bdbef7Ssrinivas pandruvada 345*c5bdbef7Ssrinivas pandruvada ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, 346*c5bdbef7Ssrinivas pandruvada NULL, NULL); 347*c5bdbef7Ssrinivas pandruvada if (ret) { 348*c5bdbef7Ssrinivas pandruvada dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); 349*c5bdbef7Ssrinivas pandruvada goto error_free_dev_mem; 350*c5bdbef7Ssrinivas pandruvada } 351*c5bdbef7Ssrinivas pandruvada gyro_state->common_attributes.data_ready = false; 352*c5bdbef7Ssrinivas pandruvada ret = hid_sensor_setup_trigger(indio_dev, name, 353*c5bdbef7Ssrinivas pandruvada &gyro_state->common_attributes); 354*c5bdbef7Ssrinivas pandruvada if (ret < 0) { 355*c5bdbef7Ssrinivas pandruvada dev_err(&pdev->dev, "trigger setup failed\n"); 356*c5bdbef7Ssrinivas pandruvada goto error_unreg_buffer_funcs; 357*c5bdbef7Ssrinivas pandruvada } 358*c5bdbef7Ssrinivas pandruvada 359*c5bdbef7Ssrinivas pandruvada ret = iio_device_register(indio_dev); 360*c5bdbef7Ssrinivas pandruvada if (ret) { 361*c5bdbef7Ssrinivas pandruvada dev_err(&pdev->dev, "device register failed\n"); 362*c5bdbef7Ssrinivas pandruvada goto error_remove_trigger; 363*c5bdbef7Ssrinivas pandruvada } 364*c5bdbef7Ssrinivas pandruvada 365*c5bdbef7Ssrinivas pandruvada gyro_state->callbacks.send_event = gyro_3d_proc_event; 366*c5bdbef7Ssrinivas pandruvada gyro_state->callbacks.capture_sample = gyro_3d_capture_sample; 367*c5bdbef7Ssrinivas pandruvada gyro_state->callbacks.pdev = pdev; 368*c5bdbef7Ssrinivas pandruvada ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D, 369*c5bdbef7Ssrinivas pandruvada &gyro_state->callbacks); 370*c5bdbef7Ssrinivas pandruvada if (ret < 0) { 371*c5bdbef7Ssrinivas pandruvada dev_err(&pdev->dev, "callback reg failed\n"); 372*c5bdbef7Ssrinivas pandruvada goto error_iio_unreg; 373*c5bdbef7Ssrinivas pandruvada } 374*c5bdbef7Ssrinivas pandruvada 375*c5bdbef7Ssrinivas pandruvada return ret; 376*c5bdbef7Ssrinivas pandruvada 377*c5bdbef7Ssrinivas pandruvada error_iio_unreg: 378*c5bdbef7Ssrinivas pandruvada iio_device_unregister(indio_dev); 379*c5bdbef7Ssrinivas pandruvada error_remove_trigger: 380*c5bdbef7Ssrinivas pandruvada hid_sensor_remove_trigger(indio_dev); 381*c5bdbef7Ssrinivas pandruvada error_unreg_buffer_funcs: 382*c5bdbef7Ssrinivas pandruvada iio_triggered_buffer_cleanup(indio_dev); 383*c5bdbef7Ssrinivas pandruvada error_free_dev_mem: 384*c5bdbef7Ssrinivas pandruvada kfree(indio_dev->channels); 385*c5bdbef7Ssrinivas pandruvada error_free_dev: 386*c5bdbef7Ssrinivas pandruvada iio_device_free(indio_dev); 387*c5bdbef7Ssrinivas pandruvada error_ret: 388*c5bdbef7Ssrinivas pandruvada return ret; 389*c5bdbef7Ssrinivas pandruvada } 390*c5bdbef7Ssrinivas pandruvada 391*c5bdbef7Ssrinivas pandruvada /* Function to deinitialize the processing for usage id */ 392*c5bdbef7Ssrinivas pandruvada static int __devinit hid_gyro_3d_remove(struct platform_device *pdev) 393*c5bdbef7Ssrinivas pandruvada { 394*c5bdbef7Ssrinivas pandruvada struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; 395*c5bdbef7Ssrinivas pandruvada struct iio_dev *indio_dev = platform_get_drvdata(pdev); 396*c5bdbef7Ssrinivas pandruvada 397*c5bdbef7Ssrinivas pandruvada sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D); 398*c5bdbef7Ssrinivas pandruvada iio_device_unregister(indio_dev); 399*c5bdbef7Ssrinivas pandruvada hid_sensor_remove_trigger(indio_dev); 400*c5bdbef7Ssrinivas pandruvada iio_triggered_buffer_cleanup(indio_dev); 401*c5bdbef7Ssrinivas pandruvada kfree(indio_dev->channels); 402*c5bdbef7Ssrinivas pandruvada iio_device_free(indio_dev); 403*c5bdbef7Ssrinivas pandruvada 404*c5bdbef7Ssrinivas pandruvada return 0; 405*c5bdbef7Ssrinivas pandruvada } 406*c5bdbef7Ssrinivas pandruvada 407*c5bdbef7Ssrinivas pandruvada static struct platform_driver hid_gyro_3d_platform_driver = { 408*c5bdbef7Ssrinivas pandruvada .driver = { 409*c5bdbef7Ssrinivas pandruvada .name = DRIVER_NAME, 410*c5bdbef7Ssrinivas pandruvada .owner = THIS_MODULE, 411*c5bdbef7Ssrinivas pandruvada }, 412*c5bdbef7Ssrinivas pandruvada .probe = hid_gyro_3d_probe, 413*c5bdbef7Ssrinivas pandruvada .remove = hid_gyro_3d_remove, 414*c5bdbef7Ssrinivas pandruvada }; 415*c5bdbef7Ssrinivas pandruvada module_platform_driver(hid_gyro_3d_platform_driver); 416*c5bdbef7Ssrinivas pandruvada 417*c5bdbef7Ssrinivas pandruvada MODULE_DESCRIPTION("HID Sensor Gyroscope 3D"); 418*c5bdbef7Ssrinivas pandruvada MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); 419*c5bdbef7Ssrinivas pandruvada MODULE_LICENSE("GPL"); 420