diff mbox

[3/3] IO: hid-sensor-magn-3d: Add in support for True/Magnetic North HID usages

Message ID 1401311175-12784-4-git-send-email-reyad.attiyat@gmail.com (mailing list archive)
State New, archived
Delegated to: Jiri Kosina
Headers show

Commit Message

Reyad Attiyat May 28, 2014, 9:06 p.m. UTC
Updated magn_3d_channel enum for all possible north channels

Added functions to setup iio_chan_spec array depending on
a hid usage report

Renamed magn_val to iio_val to differentiate the index being used

Updated magn_3d_state struct to hold pointer array (magn_val_addr[]) to
iio_val and a count of the iio channels found

Updated magn_3d_parse_report to scan for all compass usages
and create channels for each

Signed-off-by: Reyad Attiyat <reyad.attiyat@gmail.com>
---
 drivers/iio/magnetometer/hid-sensor-magn-3d.c | 278 +++++++++++++++++---------
 1 file changed, 183 insertions(+), 95 deletions(-)

Comments

Reyad Attiyat May 28, 2014, 9:15 p.m. UTC | #1
> +static void sensor_hub_fill_attr_info(
> +               struct hid_sensor_hub_attribute_info *info,
> +               s32 index, s32 report_id, struct hid_field *field)
> +{
> +       info->index = index;
> +       info->report_id = report_id;
> +       info->units = field->unit;
> +       info->unit_expo = field->unit_exponent;
> +       info->size = (field->report_size * field->report_count)/8;
> +       info->logical_minimum = field->logical_minimum;
> +       info->logical_maximum = field->logical_maximum;
>  }

I copied this function from hid/hid-sensor-hub.c as it is marked
static in that file. I use it to fill attributes as I find them.
Should I create an another patch to make it non-static?

> +       list_for_each_entry(report, &report_enum->report_list, list) {
> +               for (i = 0; i < report->maxfield; ++i) {
> +                       field = report->field[i];
> +
> +                       for (j = 0; j < field->maxusage; j++) {
> +                               usage = &(field->usage[j]);
> +

This is how I mange to find all possible hid reports in the parse
reports function. I noticed that in the other function that was used,
sensor_hub_input_get_attribute_info(),  it only uses field->usage[0].
Is there a reason for this and should I change my current
implementation?
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
srinivas pandruvada May 28, 2014, 9:25 p.m. UTC | #2
On 05/28/2014 02:15 PM, Reyad Attiyat wrote:
>> +static void sensor_hub_fill_attr_info(
>> +               struct hid_sensor_hub_attribute_info *info,
>> +               s32 index, s32 report_id, struct hid_field *field)
>> +{
>> +       info->index = index;
>> +       info->report_id = report_id;
>> +       info->units = field->unit;
>> +       info->unit_expo = field->unit_exponent;
>> +       info->size = (field->report_size * field->report_count)/8;
>> +       info->logical_minimum = field->logical_minimum;
>> +       info->logical_maximum = field->logical_maximum;
>>   }
> I copied this function from hid/hid-sensor-hub.c as it is marked
> static in that file. I use it to fill attributes as I find them.
> Should I create an another patch to make it non-static?

I didn't check your implementation. But 
sensor_hub_input_get_attribute_info()
function is not enough? We are already using to get other attributes for 
x, y and Z.

Thanks,
Srinivas


>> +       list_for_each_entry(report, &report_enum->report_list, list) {
>> +               for (i = 0; i < report->maxfield; ++i) {
>> +                       field = report->field[i];
>> +
>> +                       for (j = 0; j < field->maxusage; j++) {
>> +                               usage = &(field->usage[j]);
>> +
> This is how I mange to find all possible hid reports in the parse
> reports function. I noticed that in the other function that was used,
> sensor_hub_input_get_attribute_info(),  it only uses field->usage[0].
> Is there a reason for this and should I change my current
> implementation?
>

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reyad Attiyat May 28, 2014, 9:35 p.m. UTC | #3
Hey Srinivas,

Well I could use sensor_hub_input_get_attribute_info() for each usage
attribute. I was just thinking that since each usage attribute is
found in a row, one for each field I think, it'd be easier to create
iio channels that way. This would eliminate running the for loop
search for usage id each time.

I realize that my parse_report function is quite ugly espically ending
in four closing parenthesis and copying code from
sensor_hub_input_get_attribute_info(). I will change it if you don't
think it will slow down the driver or have any negative effects.

Thanks,
Reyad



On Wed, May 28, 2014 at 4:25 PM, Srinivas Pandruvada
<srinivas.pandruvada@linux.intel.com> wrote:
> On 05/28/2014 02:15 PM, Reyad Attiyat wrote:
>>>
>>> +static void sensor_hub_fill_attr_info(
>>> +               struct hid_sensor_hub_attribute_info *info,
>>> +               s32 index, s32 report_id, struct hid_field *field)
>>> +{
>>> +       info->index = index;
>>> +       info->report_id = report_id;
>>> +       info->units = field->unit;
>>> +       info->unit_expo = field->unit_exponent;
>>> +       info->size = (field->report_size * field->report_count)/8;
>>> +       info->logical_minimum = field->logical_minimum;
>>> +       info->logical_maximum = field->logical_maximum;
>>>   }
>>
>> I copied this function from hid/hid-sensor-hub.c as it is marked
>> static in that file. I use it to fill attributes as I find them.
>> Should I create an another patch to make it non-static?
>
>
> I didn't check your implementation. But
> sensor_hub_input_get_attribute_info()
> function is not enough? We are already using to get other attributes for x,
> y and Z.
>
> Thanks,
> Srinivas
>
>
>
>>> +       list_for_each_entry(report, &report_enum->report_list, list) {
>>> +               for (i = 0; i < report->maxfield; ++i) {
>>> +                       field = report->field[i];
>>> +
>>> +                       for (j = 0; j < field->maxusage; j++) {
>>> +                               usage = &(field->usage[j]);
>>> +
>>
>> This is how I mange to find all possible hid reports in the parse
>> reports function. I noticed that in the other function that was used,
>> sensor_hub_input_get_attribute_info(),  it only uses field->usage[0].
>> Is there a reason for this and should I change my current
>> implementation?
>>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
srinivas pandruvada May 28, 2014, 9:56 p.m. UTC | #4
Hi Reyad,

  On 05/28/2014 02:35 PM, Reyad Attiyat wrote:
> Hey Srinivas,
>
> Well I could use sensor_hub_input_get_attribute_info() for each usage
> attribute. I was just thinking that since each usage attribute is
> found in a row, one for each field I think, it'd be easier to create
> iio channels that way. This would eliminate running the for loop
> search for usage id each time.
It shouldn't be an issue for few more attributes. The idea is that
we don't expose the report level parsing information to the client drivers.
The client shouldn't worry about which collection or report it belongs to.

In this way if we have to enhance the parse function for newer
FW changes or quirks, it is only done at one place. Clients are not
affected at all.

Alternatively
we can enhance API, which takes multiple usage ids and fills information
in a single call. What do you think about this?

Thanks,
Srinivas

>
> I realize that my parse_report function is quite ugly espically ending
> in four closing parenthesis and copying code from
> sensor_hub_input_get_attribute_info(). I will change it if you don't
> think it will slow down the driver or have any negative effects.
>
> Thanks,
> Reyad
>
>
>
> On Wed, May 28, 2014 at 4:25 PM, Srinivas Pandruvada
> <srinivas.pandruvada@linux.intel.com> wrote:
>> On 05/28/2014 02:15 PM, Reyad Attiyat wrote:
>>>> +static void sensor_hub_fill_attr_info(
>>>> +               struct hid_sensor_hub_attribute_info *info,
>>>> +               s32 index, s32 report_id, struct hid_field *field)
>>>> +{
>>>> +       info->index = index;
>>>> +       info->report_id = report_id;
>>>> +       info->units = field->unit;
>>>> +       info->unit_expo = field->unit_exponent;
>>>> +       info->size = (field->report_size * field->report_count)/8;
>>>> +       info->logical_minimum = field->logical_minimum;
>>>> +       info->logical_maximum = field->logical_maximum;
>>>>    }
>>> I copied this function from hid/hid-sensor-hub.c as it is marked
>>> static in that file. I use it to fill attributes as I find them.
>>> Should I create an another patch to make it non-static?
>>
>> I didn't check your implementation. But
>> sensor_hub_input_get_attribute_info()
>> function is not enough? We are already using to get other attributes for x,
>> y and Z.
>>
>> Thanks,
>> Srinivas
>>
>>
>>
>>>> +       list_for_each_entry(report, &report_enum->report_list, list) {
>>>> +               for (i = 0; i < report->maxfield; ++i) {
>>>> +                       field = report->field[i];
>>>> +
>>>> +                       for (j = 0; j < field->maxusage; j++) {
>>>> +                               usage = &(field->usage[j]);
>>>> +
>>> This is how I mange to find all possible hid reports in the parse
>>> reports function. I noticed that in the other function that was used,
>>> sensor_hub_input_get_attribute_info(),  it only uses field->usage[0].
>>> Is there a reason for this and should I change my current
>>> implementation?
>>>

--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Reyad Attiyat May 28, 2014, 9:59 p.m. UTC | #5
Forgot to forward to list


---------- Forwarded message ----------
From: Reyad Attiyat <reyad.attiyat@gmail.com>
Date: Wed, May 28, 2014 at 4:57 PM
Subject: Re: [PATCH 3/3] IO: hid-sensor-magn-3d: Add in support for
True/Magnetic North HID usages
To: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>


Hey Srinivas,

> It shouldn't be an issue for few more attributes. The idea is that
> we don't expose the report level parsing information to the client drivers.
> The client shouldn't worry about which collection or report it belongs to.
>
Makes sense.

> In this way if we have to enhance the parse function for newer
> FW changes or quirks, it is only done at one place. Clients are not
> affected at all.
>
> Alternatively
> we can enhance API, which takes multiple usage ids and fills information
> in a single call. What do you think about this?

Yes this seems like a great idea. I will try and implement this and
resubmit these patches.

Thank You,
Reyad Attiyat
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index 6d162b7..7ffac17 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -34,63 +34,54 @@  enum magn_3d_channel {
 	CHANNEL_SCAN_INDEX_X,
 	CHANNEL_SCAN_INDEX_Y,
 	CHANNEL_SCAN_INDEX_Z,
+	CHANNEL_SCAN_INDEX_NORTH,
+	CHANNEL_SCAN_INDEX_NORTH_TRUE,
+	CHANNEL_SCAN_INDEX_NORTH_TILT_COMP,
+	CHANNEL_SCAN_INDEX_NORTH_TRUE_TILT_COMP,
 	MAGN_3D_CHANNEL_MAX,
 };
 
+#define IIO_CHANNEL_MAX MAGN_3D_CHANNEL_MAX
+
 struct magn_3d_state {
 	struct hid_sensor_hub_callbacks callbacks;
 	struct hid_sensor_common common_attributes;
 	struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX];
-	u32 magn_val[MAGN_3D_CHANNEL_MAX];
-};
+	u32 *magn_val_addr[MAGN_3D_CHANNEL_MAX];
 
-static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = {
-	HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS,
-	HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS,
-	HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS
+	u32 iio_val[IIO_CHANNEL_MAX];
+	int num_iio_channels;
 };
 
-/* Channel definitions */
-static const struct iio_chan_spec magn_3d_channels[] = {
-	{
-		.type = IIO_MAGN,
-		.modified = 1,
-		.channel2 = IIO_MOD_X,
-		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
-		BIT(IIO_CHAN_INFO_SCALE) |
-		BIT(IIO_CHAN_INFO_SAMP_FREQ) |
-		BIT(IIO_CHAN_INFO_HYSTERESIS),
-		.scan_index = CHANNEL_SCAN_INDEX_X,
-	}, {
-		.type = IIO_MAGN,
-		.modified = 1,
-		.channel2 = IIO_MOD_Y,
-		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
-		BIT(IIO_CHAN_INFO_SCALE) |
-		BIT(IIO_CHAN_INFO_SAMP_FREQ) |
-		BIT(IIO_CHAN_INFO_HYSTERESIS),
-		.scan_index = CHANNEL_SCAN_INDEX_Y,
-	}, {
-		.type = IIO_MAGN,
-		.modified = 1,
-		.channel2 = IIO_MOD_Z,
-		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
-		BIT(IIO_CHAN_INFO_SCALE) |
-		BIT(IIO_CHAN_INFO_SAMP_FREQ) |
-		BIT(IIO_CHAN_INFO_HYSTERESIS),
-		.scan_index = CHANNEL_SCAN_INDEX_Z,
+/* Find index into magn_3d_state magn[] and magn_val_addr[] from HID Usage  */
+static int magn_3d_usage_id_to_chan_index(unsigned usage_id){
+	int offset = -1;
+
+	switch (usage_id) {
+	case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS:
+		offset = CHANNEL_SCAN_INDEX_X;
+		break;
+	case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS:
+		offset = CHANNEL_SCAN_INDEX_Y;
+		break;
+	case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS:
+		offset = CHANNEL_SCAN_INDEX_Z;
+		break;
+	case HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH:
+		offset = CHANNEL_SCAN_INDEX_NORTH_TILT_COMP;
+		break;
+	case HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH:
+		offset = CHANNEL_SCAN_INDEX_NORTH_TRUE_TILT_COMP;
+		break;
+	case HID_USAGE_SENSOR_ORIENT_MAGN_NORTH:
+		offset = CHANNEL_SCAN_INDEX_NORTH;
+		break;
+	case HID_USAGE_SENSOR_ORIENT_TRUE_NORTH:
+		offset = CHANNEL_SCAN_INDEX_NORTH_TRUE;
+		break;
 	}
-};
 
-/* Adjust channel real bits based on report descriptor */
-static void magn_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels,
-						int channel, int size)
-{
-	channels[channel].scan_type.sign = 's';
-	/* Real storage bits will change based on the report desc. */
-	channels[channel].scan_type.realbits = size * 8;
-	/* Maximum size of a sample to capture is u32 */
-	channels[channel].scan_type.storagebits = sizeof(u32) * 8;
+	return offset;
 }
 
 /* Channel read_raw handler */
@@ -101,21 +92,31 @@  static int magn_3d_read_raw(struct iio_dev *indio_dev,
 {
 	struct magn_3d_state *magn_state = iio_priv(indio_dev);
 	int report_id = -1;
-	u32 address;
+	unsigned usage_id;
+	int chan_index = -1;
 	int ret;
 	int ret_type;
 
+	dev_dbg(&indio_dev->dev, "magn_3d_read_raw\n");
+
 	*val = 0;
 	*val2 = 0;
 	switch (mask) {
 	case 0:
+		/* We store the HID usage ID of the iio channel
+		 * in its address field
+		 */
+		usage_id = chan->address;
+		chan_index = magn_3d_usage_id_to_chan_index(usage_id);
+		if(chan_index < 0)
+			return -EINVAL;
+
 		report_id =
-			magn_state->magn[chan->scan_index].report_id;
-		address = magn_3d_addresses[chan->scan_index];
+			magn_state->magn[chan_index].report_id;
 		if (report_id >= 0)
 			*val = sensor_hub_input_attr_get_raw_value(
 				magn_state->common_attributes.hsdev,
-				HID_USAGE_SENSOR_COMPASS_3D, address,
+				HID_USAGE_SENSOR_COMPASS_3D, usage_id,
 				report_id);
 		else {
 			*val = 0;
@@ -202,12 +203,13 @@  static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev,
 				magn_state->common_attributes.data_ready);
 	if (magn_state->common_attributes.data_ready)
 		hid_sensor_push_data(indio_dev,
-				magn_state->magn_val,
-				sizeof(magn_state->magn_val));
+				&(magn_state->iio_val),
+				sizeof(magn_state->iio_val));
 
 	return 0;
 }
 
+
 /* Capture samples in local storage */
 static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
 				unsigned usage_id,
@@ -217,62 +219,147 @@  static int magn_3d_capture_sample(struct hid_sensor_hub_device *hsdev,
 	struct iio_dev *indio_dev = platform_get_drvdata(priv);
 	struct magn_3d_state *magn_state = iio_priv(indio_dev);
 	int offset;
+	u32 *magn_val;
 	int ret = -EINVAL;
 
-	switch (usage_id) {
+	offset = magn_3d_usage_id_to_chan_index(usage_id);
+	if(offset < 0)
+		return ret;
+
+	magn_val = magn_state->magn_val_addr[offset];
+	if(!magn_val)
+		return ret;
+
+	*(magn_val) =  *(u32 *)raw_data;
+
+	return 0;
+}
+
+/* Setup the iio_chan_spec for HID Usage ID */
+static int magn_3d_setup_iio_chan(unsigned usage_id,
+				struct iio_chan_spec* channel,
+				u32 size,
+				struct magn_3d_state *st)
+{
+	int ret = -1;
+
+	if(channel == NULL)
+		return ret;
+
+	channel->type = IIO_MAGN;
+	channel->address = usage_id;
+	channel->modified = 1;
+
+	switch (usage_id){
+	case HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH:
+		channel->channel2 = IIO_MOD_MAGN_NORTH_TILT_COMP;
+		break;
+	case HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH:
+		channel->channel2 = IIO_MOD_MAGN_NORTH_TRUE_TILT_COMP;
+		break;
+	case HID_USAGE_SENSOR_ORIENT_MAGN_NORTH:
+		channel->channel2 = IIO_MOD_MAGN_NORTH;
+		break;
+	case HID_USAGE_SENSOR_ORIENT_TRUE_NORTH:
+		channel->channel2 = IIO_MOD_MAGN_NORTH_TRUE;
+		break;
 	case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS:
+		channel->channel2 = IIO_MOD_X;
+		break;
 	case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS:
+		channel->channel2 = IIO_MOD_Y;
+		break;
 	case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS:
-		offset = usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS;
-		magn_state->magn_val[CHANNEL_SCAN_INDEX_X + offset] =
-						*(u32 *)raw_data;
-		ret = 0;
-	break;
-	default:
+		channel->channel2 = IIO_MOD_Z;
 		break;
+	default:
+		return ret;
 	}
 
-	return ret;
+	channel->info_mask_shared_by_type =
+		BIT(IIO_CHAN_INFO_OFFSET) |
+		BIT(IIO_CHAN_INFO_SCALE) |
+		BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+		BIT(IIO_CHAN_INFO_HYSTERESIS);
+
+	channel->scan_type.sign = 's';
+	/* Real storage bits will change based on the report desc. */
+	channel->scan_type.realbits = size * 8;
+	/* Maximum size of a sample to capture is u32 */
+	channel->scan_type.storagebits = sizeof(u32) * 8;
+
+	return 0;
+}
+
+static void sensor_hub_fill_attr_info(
+		struct hid_sensor_hub_attribute_info *info,
+		s32 index, s32 report_id, struct hid_field *field)
+{
+	info->index = index;
+	info->report_id = report_id;
+	info->units = field->unit;
+	info->unit_expo = field->unit_exponent;
+	info->size = (field->report_size * field->report_count)/8;
+	info->logical_minimum = field->logical_minimum;
+	info->logical_maximum = field->logical_maximum;
 }
 
-/* Parse report which is specific to an usage id*/
+/* Read the HID reports and setup IIO Channels */
 static int magn_3d_parse_report(struct platform_device *pdev,
 				struct hid_sensor_hub_device *hsdev,
-				struct iio_chan_spec *channels,
+				struct iio_chan_spec *iio_chans,
 				unsigned usage_id,
 				struct magn_3d_state *st)
 {
-	int ret;
+	int ret = -1;
 	int i;
-
-	for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) {
-		ret = sensor_hub_input_get_attribute_info(hsdev,
-				HID_INPUT_REPORT,
-				usage_id,
-				HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS + i,
-				&st->magn[CHANNEL_SCAN_INDEX_X + i]);
-		if (ret < 0)
-			break;
-		magn_3d_adjust_channel_bit_mask(channels,
-				CHANNEL_SCAN_INDEX_X + i,
-				st->magn[CHANNEL_SCAN_INDEX_X + i].size);
-	}
-	dev_dbg(&pdev->dev, "magn_3d %x:%x, %x:%x, %x:%x\n",
-			st->magn[0].index,
-			st->magn[0].report_id,
-			st->magn[1].index, st->magn[1].report_id,
-			st->magn[2].index, st->magn[2].report_id);
-
-	/* Set Sensitivity field ids, when there is no individual modifier */
-	if (st->common_attributes.sensitivity.index < 0) {
-		sensor_hub_input_get_attribute_info(hsdev,
-			HID_FEATURE_REPORT, usage_id,
-			HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS |
-			HID_USAGE_SENSOR_DATA_ORIENTATION,
-			&st->common_attributes.sensitivity);
-		dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n",
-			st->common_attributes.sensitivity.index,
-			st->common_attributes.sensitivity.report_id);
+	int j;
+
+	struct hid_report *report;
+	struct hid_field *field;
+	struct hid_report_enum *report_enum;
+	struct hid_device *hdev = hsdev->hdev;
+	struct hid_usage *usage = NULL;
+
+	dev_dbg(&pdev->dev, "magn_north_parse_reports Usage ID: %x\n", usage_id);
+	report_enum = &hdev->report_enum[HID_INPUT_REPORT];
+	list_for_each_entry(report, &report_enum->report_list, list) {
+		for (i = 0; i < report->maxfield; ++i) {
+			field = report->field[i];
+
+			for (j = 0; j < field->maxusage; j++) {
+				usage = &(field->usage[j]);
+
+				/* Check if collection_index is valid */
+				if(usage->collection_index >=
+					   hsdev->start_collection_index &&
+				   usage->collection_index <
+					   hsdev->end_collection_index &&
+				   usage->hid >=
+					   HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH &&
+				   usage->hid <=
+					   HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS)
+				{
+					struct hid_sensor_hub_attribute_info *usage_attr;
+					int magn_index = magn_3d_usage_id_to_chan_index(usage->hid);
+					int iio_index = st->num_iio_channels++;
+
+					if(magn_index >= 0 && magn_index < MAGN_3D_CHANNEL_MAX &&
+						iio_index >= 0 && iio_index < IIO_CHANNEL_MAX){
+						usage_attr = &(st->magn[magn_index]);
+
+						sensor_hub_fill_attr_info(usage_attr, i,
+									report->id,
+									field);
+						ret = magn_3d_setup_iio_chan(usage->hid,
+								&(iio_chans[iio_index]),
+								usage_attr->size,
+								st);
+						st->magn_val_addr[magn_index] = &(st->iio_val[iio_index]);
+					}
+				}
+			}
+		}
 	}
 
 	return ret;
@@ -307,10 +394,11 @@  static int hid_magn_3d_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	channels = kmemdup(magn_3d_channels, sizeof(magn_3d_channels),
-			   GFP_KERNEL);
+	channels = kcalloc(MAGN_3D_CHANNEL_MAX,
+			sizeof(struct iio_chan_spec),
+			GFP_KERNEL);
 	if (!channels) {
-		dev_err(&pdev->dev, "failed to duplicate channels\n");
+		dev_err(&pdev->dev, "failed to allocate memory for iio channel\n");
 		return -ENOMEM;
 	}
 
@@ -322,7 +410,7 @@  static int hid_magn_3d_probe(struct platform_device *pdev)
 	}
 
 	indio_dev->channels = channels;
-	indio_dev->num_channels = ARRAY_SIZE(magn_3d_channels);
+	indio_dev->num_channels = magn_state->num_iio_channels;
 	indio_dev->dev.parent = &pdev->dev;
 	indio_dev->info = &magn_3d_info;
 	indio_dev->name = name;