1098d3becSSrinivas Pandruvada /* 2098d3becSSrinivas Pandruvada * HID Sensors Driver 3098d3becSSrinivas Pandruvada * Copyright (c) 2013, Intel Corporation. 4098d3becSSrinivas Pandruvada * 5098d3becSSrinivas Pandruvada * This program is free software; you can redistribute it and/or modify it 6098d3becSSrinivas Pandruvada * under the terms and conditions of the GNU General Public License, 7098d3becSSrinivas Pandruvada * version 2, as published by the Free Software Foundation. 8098d3becSSrinivas Pandruvada * 9098d3becSSrinivas Pandruvada * This program is distributed in the hope it will be useful, but WITHOUT 10098d3becSSrinivas Pandruvada * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11098d3becSSrinivas Pandruvada * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12098d3becSSrinivas Pandruvada * more details. 13098d3becSSrinivas Pandruvada * 14098d3becSSrinivas Pandruvada * You should have received a copy of the GNU General Public License along with 15098d3becSSrinivas Pandruvada * this program; if not, write to the Free Software Foundation, Inc. 16098d3becSSrinivas Pandruvada * 17098d3becSSrinivas Pandruvada */ 18098d3becSSrinivas Pandruvada 19098d3becSSrinivas Pandruvada #include <linux/device.h> 20098d3becSSrinivas Pandruvada #include <linux/platform_device.h> 21098d3becSSrinivas Pandruvada #include <linux/module.h> 22098d3becSSrinivas Pandruvada #include <linux/interrupt.h> 23098d3becSSrinivas Pandruvada #include <linux/irq.h> 24098d3becSSrinivas Pandruvada #include <linux/slab.h> 25098d3becSSrinivas Pandruvada #include <linux/hid-sensor-hub.h> 26098d3becSSrinivas Pandruvada #include <linux/iio/iio.h> 27098d3becSSrinivas Pandruvada #include <linux/iio/sysfs.h> 28098d3becSSrinivas Pandruvada #include <linux/iio/buffer.h> 29098d3becSSrinivas Pandruvada #include <linux/iio/trigger_consumer.h> 30098d3becSSrinivas Pandruvada #include <linux/iio/triggered_buffer.h> 31098d3becSSrinivas Pandruvada #include "../common/hid-sensors/hid-sensor-trigger.h" 32098d3becSSrinivas Pandruvada 33098d3becSSrinivas Pandruvada enum incl_3d_channel { 34098d3becSSrinivas Pandruvada CHANNEL_SCAN_INDEX_X, 35098d3becSSrinivas Pandruvada CHANNEL_SCAN_INDEX_Y, 36098d3becSSrinivas Pandruvada CHANNEL_SCAN_INDEX_Z, 37098d3becSSrinivas Pandruvada INCLI_3D_CHANNEL_MAX, 38098d3becSSrinivas Pandruvada }; 39098d3becSSrinivas Pandruvada 40098d3becSSrinivas Pandruvada struct incl_3d_state { 41098d3becSSrinivas Pandruvada struct hid_sensor_hub_callbacks callbacks; 42098d3becSSrinivas Pandruvada struct hid_sensor_common common_attributes; 43098d3becSSrinivas Pandruvada struct hid_sensor_hub_attribute_info incl[INCLI_3D_CHANNEL_MAX]; 44098d3becSSrinivas Pandruvada u32 incl_val[INCLI_3D_CHANNEL_MAX]; 45*be8e48d6SSrinivas Pandruvada int scale_pre_decml; 46*be8e48d6SSrinivas Pandruvada int scale_post_decml; 47*be8e48d6SSrinivas Pandruvada int scale_precision; 48*be8e48d6SSrinivas Pandruvada int value_offset; 49098d3becSSrinivas Pandruvada }; 50098d3becSSrinivas Pandruvada 51098d3becSSrinivas Pandruvada static const u32 incl_3d_addresses[INCLI_3D_CHANNEL_MAX] = { 52098d3becSSrinivas Pandruvada HID_USAGE_SENSOR_ORIENT_TILT_X, 53098d3becSSrinivas Pandruvada HID_USAGE_SENSOR_ORIENT_TILT_Y, 54098d3becSSrinivas Pandruvada HID_USAGE_SENSOR_ORIENT_TILT_Z 55098d3becSSrinivas Pandruvada }; 56098d3becSSrinivas Pandruvada 57098d3becSSrinivas Pandruvada /* Channel definitions */ 58098d3becSSrinivas Pandruvada static const struct iio_chan_spec incl_3d_channels[] = { 59098d3becSSrinivas Pandruvada { 60098d3becSSrinivas Pandruvada .type = IIO_INCLI, 61098d3becSSrinivas Pandruvada .modified = 1, 62098d3becSSrinivas Pandruvada .channel2 = IIO_MOD_X, 63098d3becSSrinivas Pandruvada .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 64098d3becSSrinivas Pandruvada .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | 65098d3becSSrinivas Pandruvada BIT(IIO_CHAN_INFO_SCALE) | 66098d3becSSrinivas Pandruvada BIT(IIO_CHAN_INFO_SAMP_FREQ) | 67098d3becSSrinivas Pandruvada BIT(IIO_CHAN_INFO_HYSTERESIS), 68098d3becSSrinivas Pandruvada .scan_index = CHANNEL_SCAN_INDEX_X, 69098d3becSSrinivas Pandruvada }, { 70098d3becSSrinivas Pandruvada .type = IIO_INCLI, 71098d3becSSrinivas Pandruvada .modified = 1, 72098d3becSSrinivas Pandruvada .channel2 = IIO_MOD_Y, 73098d3becSSrinivas Pandruvada .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 74098d3becSSrinivas Pandruvada .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | 75098d3becSSrinivas Pandruvada BIT(IIO_CHAN_INFO_SCALE) | 76098d3becSSrinivas Pandruvada BIT(IIO_CHAN_INFO_SAMP_FREQ) | 77098d3becSSrinivas Pandruvada BIT(IIO_CHAN_INFO_HYSTERESIS), 78098d3becSSrinivas Pandruvada .scan_index = CHANNEL_SCAN_INDEX_Y, 79098d3becSSrinivas Pandruvada }, { 80098d3becSSrinivas Pandruvada .type = IIO_INCLI, 81098d3becSSrinivas Pandruvada .modified = 1, 82098d3becSSrinivas Pandruvada .channel2 = IIO_MOD_Z, 83098d3becSSrinivas Pandruvada .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 84098d3becSSrinivas Pandruvada .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | 85098d3becSSrinivas Pandruvada BIT(IIO_CHAN_INFO_SCALE) | 86098d3becSSrinivas Pandruvada BIT(IIO_CHAN_INFO_SAMP_FREQ) | 87098d3becSSrinivas Pandruvada BIT(IIO_CHAN_INFO_HYSTERESIS), 88098d3becSSrinivas Pandruvada .scan_index = CHANNEL_SCAN_INDEX_Z, 89098d3becSSrinivas Pandruvada } 90098d3becSSrinivas Pandruvada }; 91098d3becSSrinivas Pandruvada 92098d3becSSrinivas Pandruvada /* Adjust channel real bits based on report descriptor */ 93098d3becSSrinivas Pandruvada static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan, 94098d3becSSrinivas Pandruvada int size) 95098d3becSSrinivas Pandruvada { 96098d3becSSrinivas Pandruvada chan->scan_type.sign = 's'; 97098d3becSSrinivas Pandruvada /* Real storage bits will change based on the report desc. */ 98098d3becSSrinivas Pandruvada chan->scan_type.realbits = size * 8; 99098d3becSSrinivas Pandruvada /* Maximum size of a sample to capture is u32 */ 100098d3becSSrinivas Pandruvada chan->scan_type.storagebits = sizeof(u32) * 8; 101098d3becSSrinivas Pandruvada } 102098d3becSSrinivas Pandruvada 103098d3becSSrinivas Pandruvada /* Channel read_raw handler */ 104098d3becSSrinivas Pandruvada static int incl_3d_read_raw(struct iio_dev *indio_dev, 105098d3becSSrinivas Pandruvada struct iio_chan_spec const *chan, 106098d3becSSrinivas Pandruvada int *val, int *val2, 107098d3becSSrinivas Pandruvada long mask) 108098d3becSSrinivas Pandruvada { 109098d3becSSrinivas Pandruvada struct incl_3d_state *incl_state = iio_priv(indio_dev); 110098d3becSSrinivas Pandruvada int report_id = -1; 111098d3becSSrinivas Pandruvada u32 address; 112098d3becSSrinivas Pandruvada int ret_type; 113098d3becSSrinivas Pandruvada 114098d3becSSrinivas Pandruvada *val = 0; 115098d3becSSrinivas Pandruvada *val2 = 0; 116098d3becSSrinivas Pandruvada switch (mask) { 117098d3becSSrinivas Pandruvada case IIO_CHAN_INFO_RAW: 118098d3becSSrinivas Pandruvada report_id = 119098d3becSSrinivas Pandruvada incl_state->incl[chan->scan_index].report_id; 120098d3becSSrinivas Pandruvada address = incl_3d_addresses[chan->scan_index]; 121098d3becSSrinivas Pandruvada if (report_id >= 0) 122098d3becSSrinivas Pandruvada *val = sensor_hub_input_attr_get_raw_value( 123098d3becSSrinivas Pandruvada incl_state->common_attributes.hsdev, 124098d3becSSrinivas Pandruvada HID_USAGE_SENSOR_INCLINOMETER_3D, address, 125098d3becSSrinivas Pandruvada report_id); 126098d3becSSrinivas Pandruvada else { 127098d3becSSrinivas Pandruvada return -EINVAL; 128098d3becSSrinivas Pandruvada } 129098d3becSSrinivas Pandruvada ret_type = IIO_VAL_INT; 130098d3becSSrinivas Pandruvada break; 131098d3becSSrinivas Pandruvada case IIO_CHAN_INFO_SCALE: 132*be8e48d6SSrinivas Pandruvada *val = incl_state->scale_pre_decml; 133*be8e48d6SSrinivas Pandruvada *val2 = incl_state->scale_post_decml; 134*be8e48d6SSrinivas Pandruvada ret_type = incl_state->scale_precision; 135098d3becSSrinivas Pandruvada break; 136098d3becSSrinivas Pandruvada case IIO_CHAN_INFO_OFFSET: 137*be8e48d6SSrinivas Pandruvada *val = incl_state->value_offset; 138098d3becSSrinivas Pandruvada ret_type = IIO_VAL_INT; 139098d3becSSrinivas Pandruvada break; 140098d3becSSrinivas Pandruvada case IIO_CHAN_INFO_SAMP_FREQ: 141098d3becSSrinivas Pandruvada ret_type = hid_sensor_read_samp_freq_value( 142098d3becSSrinivas Pandruvada &incl_state->common_attributes, val, val2); 143098d3becSSrinivas Pandruvada break; 144098d3becSSrinivas Pandruvada case IIO_CHAN_INFO_HYSTERESIS: 145098d3becSSrinivas Pandruvada ret_type = hid_sensor_read_raw_hyst_value( 146098d3becSSrinivas Pandruvada &incl_state->common_attributes, val, val2); 147098d3becSSrinivas Pandruvada break; 148098d3becSSrinivas Pandruvada default: 149098d3becSSrinivas Pandruvada ret_type = -EINVAL; 150098d3becSSrinivas Pandruvada break; 151098d3becSSrinivas Pandruvada } 152098d3becSSrinivas Pandruvada 153098d3becSSrinivas Pandruvada return ret_type; 154098d3becSSrinivas Pandruvada } 155098d3becSSrinivas Pandruvada 156098d3becSSrinivas Pandruvada /* Channel write_raw handler */ 157098d3becSSrinivas Pandruvada static int incl_3d_write_raw(struct iio_dev *indio_dev, 158098d3becSSrinivas Pandruvada struct iio_chan_spec const *chan, 159098d3becSSrinivas Pandruvada int val, 160098d3becSSrinivas Pandruvada int val2, 161098d3becSSrinivas Pandruvada long mask) 162098d3becSSrinivas Pandruvada { 163098d3becSSrinivas Pandruvada struct incl_3d_state *incl_state = iio_priv(indio_dev); 164098d3becSSrinivas Pandruvada int ret; 165098d3becSSrinivas Pandruvada 166098d3becSSrinivas Pandruvada switch (mask) { 167098d3becSSrinivas Pandruvada case IIO_CHAN_INFO_SAMP_FREQ: 168098d3becSSrinivas Pandruvada ret = hid_sensor_write_samp_freq_value( 169098d3becSSrinivas Pandruvada &incl_state->common_attributes, val, val2); 170098d3becSSrinivas Pandruvada break; 171098d3becSSrinivas Pandruvada case IIO_CHAN_INFO_HYSTERESIS: 172098d3becSSrinivas Pandruvada ret = hid_sensor_write_raw_hyst_value( 173098d3becSSrinivas Pandruvada &incl_state->common_attributes, val, val2); 174098d3becSSrinivas Pandruvada break; 175098d3becSSrinivas Pandruvada default: 176098d3becSSrinivas Pandruvada ret = -EINVAL; 177098d3becSSrinivas Pandruvada } 178098d3becSSrinivas Pandruvada 179098d3becSSrinivas Pandruvada return ret; 180098d3becSSrinivas Pandruvada } 181098d3becSSrinivas Pandruvada 182098d3becSSrinivas Pandruvada static const struct iio_info incl_3d_info = { 183098d3becSSrinivas Pandruvada .driver_module = THIS_MODULE, 184098d3becSSrinivas Pandruvada .read_raw = &incl_3d_read_raw, 185098d3becSSrinivas Pandruvada .write_raw = &incl_3d_write_raw, 186098d3becSSrinivas Pandruvada }; 187098d3becSSrinivas Pandruvada 188098d3becSSrinivas Pandruvada /* Function to push data to buffer */ 189098d3becSSrinivas Pandruvada static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) 190098d3becSSrinivas Pandruvada { 191098d3becSSrinivas Pandruvada dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); 192098d3becSSrinivas Pandruvada iio_push_to_buffers(indio_dev, (u8 *)data); 193098d3becSSrinivas Pandruvada } 194098d3becSSrinivas Pandruvada 195098d3becSSrinivas Pandruvada /* Callback handler to send event after all samples are received and captured */ 196098d3becSSrinivas Pandruvada static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev, 197098d3becSSrinivas Pandruvada unsigned usage_id, 198098d3becSSrinivas Pandruvada void *priv) 199098d3becSSrinivas Pandruvada { 200098d3becSSrinivas Pandruvada struct iio_dev *indio_dev = platform_get_drvdata(priv); 201098d3becSSrinivas Pandruvada struct incl_3d_state *incl_state = iio_priv(indio_dev); 202098d3becSSrinivas Pandruvada 203098d3becSSrinivas Pandruvada dev_dbg(&indio_dev->dev, "incl_3d_proc_event [%d]\n", 204098d3becSSrinivas Pandruvada incl_state->common_attributes.data_ready); 205098d3becSSrinivas Pandruvada if (incl_state->common_attributes.data_ready) 206098d3becSSrinivas Pandruvada hid_sensor_push_data(indio_dev, 207098d3becSSrinivas Pandruvada (u8 *)incl_state->incl_val, 208098d3becSSrinivas Pandruvada sizeof(incl_state->incl_val)); 209098d3becSSrinivas Pandruvada 210098d3becSSrinivas Pandruvada return 0; 211098d3becSSrinivas Pandruvada } 212098d3becSSrinivas Pandruvada 213098d3becSSrinivas Pandruvada /* Capture samples in local storage */ 214098d3becSSrinivas Pandruvada static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev, 215098d3becSSrinivas Pandruvada unsigned usage_id, 216098d3becSSrinivas Pandruvada size_t raw_len, char *raw_data, 217098d3becSSrinivas Pandruvada void *priv) 218098d3becSSrinivas Pandruvada { 219098d3becSSrinivas Pandruvada struct iio_dev *indio_dev = platform_get_drvdata(priv); 220098d3becSSrinivas Pandruvada struct incl_3d_state *incl_state = iio_priv(indio_dev); 221098d3becSSrinivas Pandruvada int ret = 0; 222098d3becSSrinivas Pandruvada 223098d3becSSrinivas Pandruvada switch (usage_id) { 224098d3becSSrinivas Pandruvada case HID_USAGE_SENSOR_ORIENT_TILT_X: 225098d3becSSrinivas Pandruvada incl_state->incl_val[CHANNEL_SCAN_INDEX_X] = *(u32 *)raw_data; 226098d3becSSrinivas Pandruvada break; 227098d3becSSrinivas Pandruvada case HID_USAGE_SENSOR_ORIENT_TILT_Y: 228098d3becSSrinivas Pandruvada incl_state->incl_val[CHANNEL_SCAN_INDEX_Y] = *(u32 *)raw_data; 229098d3becSSrinivas Pandruvada break; 230098d3becSSrinivas Pandruvada case HID_USAGE_SENSOR_ORIENT_TILT_Z: 231098d3becSSrinivas Pandruvada incl_state->incl_val[CHANNEL_SCAN_INDEX_Z] = *(u32 *)raw_data; 232098d3becSSrinivas Pandruvada break; 233098d3becSSrinivas Pandruvada default: 234098d3becSSrinivas Pandruvada ret = -EINVAL; 235098d3becSSrinivas Pandruvada break; 236098d3becSSrinivas Pandruvada } 237098d3becSSrinivas Pandruvada 238098d3becSSrinivas Pandruvada return ret; 239098d3becSSrinivas Pandruvada } 240098d3becSSrinivas Pandruvada 241098d3becSSrinivas Pandruvada /* Parse report which is specific to an usage id*/ 242098d3becSSrinivas Pandruvada static int incl_3d_parse_report(struct platform_device *pdev, 243098d3becSSrinivas Pandruvada struct hid_sensor_hub_device *hsdev, 244098d3becSSrinivas Pandruvada struct iio_chan_spec *channels, 245098d3becSSrinivas Pandruvada unsigned usage_id, 246098d3becSSrinivas Pandruvada struct incl_3d_state *st) 247098d3becSSrinivas Pandruvada { 248098d3becSSrinivas Pandruvada int ret; 249098d3becSSrinivas Pandruvada 250098d3becSSrinivas Pandruvada ret = sensor_hub_input_get_attribute_info(hsdev, 251098d3becSSrinivas Pandruvada HID_INPUT_REPORT, 252098d3becSSrinivas Pandruvada usage_id, 253098d3becSSrinivas Pandruvada HID_USAGE_SENSOR_ORIENT_TILT_X, 254098d3becSSrinivas Pandruvada &st->incl[CHANNEL_SCAN_INDEX_X]); 255098d3becSSrinivas Pandruvada if (ret) 256098d3becSSrinivas Pandruvada return ret; 257098d3becSSrinivas Pandruvada incl_3d_adjust_channel_bit_mask(&channels[CHANNEL_SCAN_INDEX_X], 258098d3becSSrinivas Pandruvada st->incl[CHANNEL_SCAN_INDEX_X].size); 259098d3becSSrinivas Pandruvada 260098d3becSSrinivas Pandruvada ret = sensor_hub_input_get_attribute_info(hsdev, 261098d3becSSrinivas Pandruvada HID_INPUT_REPORT, 262098d3becSSrinivas Pandruvada usage_id, 263098d3becSSrinivas Pandruvada HID_USAGE_SENSOR_ORIENT_TILT_Y, 264098d3becSSrinivas Pandruvada &st->incl[CHANNEL_SCAN_INDEX_Y]); 265098d3becSSrinivas Pandruvada if (ret) 266098d3becSSrinivas Pandruvada return ret; 267098d3becSSrinivas Pandruvada incl_3d_adjust_channel_bit_mask(&channels[CHANNEL_SCAN_INDEX_Y], 268098d3becSSrinivas Pandruvada st->incl[CHANNEL_SCAN_INDEX_Y].size); 269098d3becSSrinivas Pandruvada 270098d3becSSrinivas Pandruvada ret = sensor_hub_input_get_attribute_info(hsdev, 271098d3becSSrinivas Pandruvada HID_INPUT_REPORT, 272098d3becSSrinivas Pandruvada usage_id, 273098d3becSSrinivas Pandruvada HID_USAGE_SENSOR_ORIENT_TILT_Z, 274098d3becSSrinivas Pandruvada &st->incl[CHANNEL_SCAN_INDEX_Z]); 275098d3becSSrinivas Pandruvada if (ret) 276098d3becSSrinivas Pandruvada return ret; 277098d3becSSrinivas Pandruvada incl_3d_adjust_channel_bit_mask(&channels[CHANNEL_SCAN_INDEX_Z], 278098d3becSSrinivas Pandruvada st->incl[CHANNEL_SCAN_INDEX_Z].size); 279098d3becSSrinivas Pandruvada 280098d3becSSrinivas Pandruvada dev_dbg(&pdev->dev, "incl_3d %x:%x, %x:%x, %x:%x\n", 281098d3becSSrinivas Pandruvada st->incl[0].index, 282098d3becSSrinivas Pandruvada st->incl[0].report_id, 283098d3becSSrinivas Pandruvada st->incl[1].index, st->incl[1].report_id, 284098d3becSSrinivas Pandruvada st->incl[2].index, st->incl[2].report_id); 285098d3becSSrinivas Pandruvada 286*be8e48d6SSrinivas Pandruvada st->scale_precision = hid_sensor_format_scale( 287*be8e48d6SSrinivas Pandruvada HID_USAGE_SENSOR_INCLINOMETER_3D, 288*be8e48d6SSrinivas Pandruvada &st->incl[CHANNEL_SCAN_INDEX_X], 289*be8e48d6SSrinivas Pandruvada &st->scale_pre_decml, &st->scale_post_decml); 290*be8e48d6SSrinivas Pandruvada 291098d3becSSrinivas Pandruvada /* Set Sensitivity field ids, when there is no individual modifier */ 292098d3becSSrinivas Pandruvada if (st->common_attributes.sensitivity.index < 0) { 293098d3becSSrinivas Pandruvada sensor_hub_input_get_attribute_info(hsdev, 294098d3becSSrinivas Pandruvada HID_FEATURE_REPORT, usage_id, 295098d3becSSrinivas Pandruvada HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | 296098d3becSSrinivas Pandruvada HID_USAGE_SENSOR_DATA_ORIENTATION, 297098d3becSSrinivas Pandruvada &st->common_attributes.sensitivity); 298098d3becSSrinivas Pandruvada dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", 299098d3becSSrinivas Pandruvada st->common_attributes.sensitivity.index, 300098d3becSSrinivas Pandruvada st->common_attributes.sensitivity.report_id); 301098d3becSSrinivas Pandruvada } 302098d3becSSrinivas Pandruvada return ret; 303098d3becSSrinivas Pandruvada } 304098d3becSSrinivas Pandruvada 305098d3becSSrinivas Pandruvada /* Function to initialize the processing for usage id */ 306098d3becSSrinivas Pandruvada static int hid_incl_3d_probe(struct platform_device *pdev) 307098d3becSSrinivas Pandruvada { 308098d3becSSrinivas Pandruvada int ret; 309098d3becSSrinivas Pandruvada static char *name = "incli_3d"; 310098d3becSSrinivas Pandruvada struct iio_dev *indio_dev; 311098d3becSSrinivas Pandruvada struct incl_3d_state *incl_state; 312098d3becSSrinivas Pandruvada struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; 313098d3becSSrinivas Pandruvada struct iio_chan_spec *channels; 314098d3becSSrinivas Pandruvada 315098d3becSSrinivas Pandruvada indio_dev = devm_iio_device_alloc(&pdev->dev, 316098d3becSSrinivas Pandruvada sizeof(struct incl_3d_state)); 317098d3becSSrinivas Pandruvada if (indio_dev == NULL) 318098d3becSSrinivas Pandruvada return -ENOMEM; 319098d3becSSrinivas Pandruvada 320098d3becSSrinivas Pandruvada platform_set_drvdata(pdev, indio_dev); 321098d3becSSrinivas Pandruvada 322098d3becSSrinivas Pandruvada incl_state = iio_priv(indio_dev); 323098d3becSSrinivas Pandruvada incl_state->common_attributes.hsdev = hsdev; 324098d3becSSrinivas Pandruvada incl_state->common_attributes.pdev = pdev; 325098d3becSSrinivas Pandruvada 326098d3becSSrinivas Pandruvada ret = hid_sensor_parse_common_attributes(hsdev, 327098d3becSSrinivas Pandruvada HID_USAGE_SENSOR_INCLINOMETER_3D, 328098d3becSSrinivas Pandruvada &incl_state->common_attributes); 329098d3becSSrinivas Pandruvada if (ret) { 330098d3becSSrinivas Pandruvada dev_err(&pdev->dev, "failed to setup common attributes\n"); 331098d3becSSrinivas Pandruvada return ret; 332098d3becSSrinivas Pandruvada } 333098d3becSSrinivas Pandruvada 334098d3becSSrinivas Pandruvada channels = kmemdup(incl_3d_channels, sizeof(incl_3d_channels), 335098d3becSSrinivas Pandruvada GFP_KERNEL); 336098d3becSSrinivas Pandruvada if (!channels) { 337098d3becSSrinivas Pandruvada dev_err(&pdev->dev, "failed to duplicate channels\n"); 338098d3becSSrinivas Pandruvada return -ENOMEM; 339098d3becSSrinivas Pandruvada } 340098d3becSSrinivas Pandruvada 341098d3becSSrinivas Pandruvada ret = incl_3d_parse_report(pdev, hsdev, channels, 342098d3becSSrinivas Pandruvada HID_USAGE_SENSOR_INCLINOMETER_3D, incl_state); 343098d3becSSrinivas Pandruvada if (ret) { 344098d3becSSrinivas Pandruvada dev_err(&pdev->dev, "failed to setup attributes\n"); 345098d3becSSrinivas Pandruvada goto error_free_dev_mem; 346098d3becSSrinivas Pandruvada } 347098d3becSSrinivas Pandruvada 348098d3becSSrinivas Pandruvada indio_dev->channels = channels; 349098d3becSSrinivas Pandruvada indio_dev->num_channels = ARRAY_SIZE(incl_3d_channels); 350098d3becSSrinivas Pandruvada indio_dev->dev.parent = &pdev->dev; 351098d3becSSrinivas Pandruvada indio_dev->info = &incl_3d_info; 352098d3becSSrinivas Pandruvada indio_dev->name = name; 353098d3becSSrinivas Pandruvada indio_dev->modes = INDIO_DIRECT_MODE; 354098d3becSSrinivas Pandruvada 355098d3becSSrinivas Pandruvada ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, 356098d3becSSrinivas Pandruvada NULL, NULL); 357098d3becSSrinivas Pandruvada if (ret) { 358098d3becSSrinivas Pandruvada dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); 359098d3becSSrinivas Pandruvada goto error_free_dev_mem; 360098d3becSSrinivas Pandruvada } 361098d3becSSrinivas Pandruvada incl_state->common_attributes.data_ready = false; 362098d3becSSrinivas Pandruvada ret = hid_sensor_setup_trigger(indio_dev, name, 363098d3becSSrinivas Pandruvada &incl_state->common_attributes); 364098d3becSSrinivas Pandruvada if (ret) { 365098d3becSSrinivas Pandruvada dev_err(&pdev->dev, "trigger setup failed\n"); 366098d3becSSrinivas Pandruvada goto error_unreg_buffer_funcs; 367098d3becSSrinivas Pandruvada } 368098d3becSSrinivas Pandruvada 369098d3becSSrinivas Pandruvada ret = iio_device_register(indio_dev); 370098d3becSSrinivas Pandruvada if (ret) { 371098d3becSSrinivas Pandruvada dev_err(&pdev->dev, "device register failed\n"); 372098d3becSSrinivas Pandruvada goto error_remove_trigger; 373098d3becSSrinivas Pandruvada } 374098d3becSSrinivas Pandruvada 375098d3becSSrinivas Pandruvada incl_state->callbacks.send_event = incl_3d_proc_event; 376098d3becSSrinivas Pandruvada incl_state->callbacks.capture_sample = incl_3d_capture_sample; 377098d3becSSrinivas Pandruvada incl_state->callbacks.pdev = pdev; 378098d3becSSrinivas Pandruvada ret = sensor_hub_register_callback(hsdev, 379098d3becSSrinivas Pandruvada HID_USAGE_SENSOR_INCLINOMETER_3D, 380098d3becSSrinivas Pandruvada &incl_state->callbacks); 381098d3becSSrinivas Pandruvada if (ret) { 382098d3becSSrinivas Pandruvada dev_err(&pdev->dev, "callback reg failed\n"); 383098d3becSSrinivas Pandruvada goto error_iio_unreg; 384098d3becSSrinivas Pandruvada } 385098d3becSSrinivas Pandruvada 386098d3becSSrinivas Pandruvada return 0; 387098d3becSSrinivas Pandruvada 388098d3becSSrinivas Pandruvada error_iio_unreg: 389098d3becSSrinivas Pandruvada iio_device_unregister(indio_dev); 390098d3becSSrinivas Pandruvada error_remove_trigger: 391098d3becSSrinivas Pandruvada hid_sensor_remove_trigger(&incl_state->common_attributes); 392098d3becSSrinivas Pandruvada error_unreg_buffer_funcs: 393098d3becSSrinivas Pandruvada iio_triggered_buffer_cleanup(indio_dev); 394098d3becSSrinivas Pandruvada error_free_dev_mem: 395098d3becSSrinivas Pandruvada kfree(indio_dev->channels); 396098d3becSSrinivas Pandruvada return ret; 397098d3becSSrinivas Pandruvada } 398098d3becSSrinivas Pandruvada 399098d3becSSrinivas Pandruvada /* Function to deinitialize the processing for usage id */ 400098d3becSSrinivas Pandruvada static int hid_incl_3d_remove(struct platform_device *pdev) 401098d3becSSrinivas Pandruvada { 402098d3becSSrinivas Pandruvada struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; 403098d3becSSrinivas Pandruvada struct iio_dev *indio_dev = platform_get_drvdata(pdev); 404098d3becSSrinivas Pandruvada struct incl_3d_state *incl_state = iio_priv(indio_dev); 405098d3becSSrinivas Pandruvada 406098d3becSSrinivas Pandruvada sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D); 407098d3becSSrinivas Pandruvada iio_device_unregister(indio_dev); 408098d3becSSrinivas Pandruvada hid_sensor_remove_trigger(&incl_state->common_attributes); 409098d3becSSrinivas Pandruvada iio_triggered_buffer_cleanup(indio_dev); 410098d3becSSrinivas Pandruvada kfree(indio_dev->channels); 411098d3becSSrinivas Pandruvada 412098d3becSSrinivas Pandruvada return 0; 413098d3becSSrinivas Pandruvada } 414098d3becSSrinivas Pandruvada 415098d3becSSrinivas Pandruvada static struct platform_device_id hid_incl_3d_ids[] = { 416098d3becSSrinivas Pandruvada { 417098d3becSSrinivas Pandruvada /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ 418098d3becSSrinivas Pandruvada .name = "HID-SENSOR-200086", 419098d3becSSrinivas Pandruvada }, 420098d3becSSrinivas Pandruvada { /* sentinel */ } 421098d3becSSrinivas Pandruvada }; 422098d3becSSrinivas Pandruvada MODULE_DEVICE_TABLE(platform, hid_incl_3d_ids); 423098d3becSSrinivas Pandruvada 424098d3becSSrinivas Pandruvada static struct platform_driver hid_incl_3d_platform_driver = { 425098d3becSSrinivas Pandruvada .id_table = hid_incl_3d_ids, 426098d3becSSrinivas Pandruvada .driver = { 427098d3becSSrinivas Pandruvada .name = KBUILD_MODNAME, 428098d3becSSrinivas Pandruvada .owner = THIS_MODULE, 429098d3becSSrinivas Pandruvada }, 430098d3becSSrinivas Pandruvada .probe = hid_incl_3d_probe, 431098d3becSSrinivas Pandruvada .remove = hid_incl_3d_remove, 432098d3becSSrinivas Pandruvada }; 433098d3becSSrinivas Pandruvada module_platform_driver(hid_incl_3d_platform_driver); 434098d3becSSrinivas Pandruvada 435098d3becSSrinivas Pandruvada MODULE_DESCRIPTION("HID Sensor Inclinometer 3D"); 436098d3becSSrinivas Pandruvada MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); 437098d3becSSrinivas Pandruvada MODULE_LICENSE("GPL"); 438