1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License version
7 * 2 as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #include <linux/i2c.h>
17 #include <linux/firmware.h>
18 #include <linux/device.h>
19 #include <linux/export.h>
20 #include "../include/linux/libmsrlisthelper.h"
21 #include <linux/module.h>
22 #include <linux/slab.h>
24 /* Tagged binary data container structure definitions. */
26 u32 tag; /*!< Tag identifier, also checks endianness */
27 u32 size; /*!< Container size including this header */
28 u32 version; /*!< Version, format 0xYYMMDDVV */
29 u32 revision; /*!< Revision, format 0xYYMMDDVV */
30 u32 config_bits; /*!< Configuration flag bits set */
31 u32 checksum; /*!< Global checksum, header included */
34 struct tbd_record_header {
35 u32 size; /*!< Size of record including header */
36 u8 format_id; /*!< tbd_format_t enumeration values used */
37 u8 packing_key; /*!< Packing method; 0 = no packing */
38 u16 class_id; /*!< tbd_class_t enumeration values used */
41 struct tbd_data_record_header {
48 #define TBD_CLASS_DRV_ID 2
50 static int set_msr_configuration(struct i2c_client *client, uint8_t *bufptr,
54 * The configuration data contains any number of sequences where
55 * the first byte (that is, uint8_t) that marks the number of bytes
56 * in the sequence to follow, is indeed followed by the indicated
57 * number of bytes of actual data to be written to sensor.
58 * By convention, the first two bytes of actual data should be
59 * understood as an address in the sensor address space (hibyte
60 * followed by lobyte) where the remaining data in the sequence
66 while (ptr < bufptr + size) {
67 struct i2c_msg msg = {
75 /* Where the bytes are located */
79 if (ptr > bufptr + size)
80 /* Accessing data beyond bounds is not tolerated */
83 ret = i2c_transfer(client->adapter, &msg, 1);
85 dev_err(&client->dev, "i2c write error: %d", ret);
92 static int parse_and_apply(struct i2c_client *client, uint8_t *buffer,
95 u8 *endptr8 = buffer + size;
96 struct tbd_data_record_header *header =
97 (struct tbd_data_record_header *)buffer;
99 /* There may be any number of datasets present */
100 unsigned int dataset = 0;
103 /* In below, four variables are read from buffer */
104 if ((uint8_t *)header + sizeof(*header) > endptr8)
107 /* All data should be located within given buffer */
108 if ((uint8_t *)header + header->data_offset +
109 header->data_size > endptr8)
112 /* We have a new valid dataset */
114 /* See whether there is MSR data */
115 /* If yes, update the reg info */
116 if (header->data_size && (header->flags & 1)) {
119 dev_info(&client->dev,
120 "New MSR data for sensor driver (dataset %02d) size:%d\n",
121 dataset, header->data_size);
122 ret = set_msr_configuration(client,
123 buffer + header->data_offset,
128 header = (struct tbd_data_record_header *)(buffer +
129 header->next_offset);
130 } while (header->next_offset);
135 int apply_msr_data(struct i2c_client *client, const struct firmware *fw)
137 struct tbd_header *header;
138 struct tbd_record_header *record;
141 dev_warn(&client->dev, "Drv data is not loaded.\n");
145 if (sizeof(*header) > fw->size)
148 header = (struct tbd_header *)fw->data;
149 /* Check that we have drvb block. */
150 if (memcmp(&header->tag, "DRVB", 4))
154 if (header->size != fw->size)
157 if (sizeof(*header) + sizeof(*record) > fw->size)
160 record = (struct tbd_record_header *)(header + 1);
161 /* Check that class id mathes tbd's drv id. */
162 if (record->class_id != TBD_CLASS_DRV_ID)
165 /* Size 0 shall not be treated as an error */
169 return parse_and_apply(client, (uint8_t *)(record + 1), record->size);
171 EXPORT_SYMBOL_GPL(apply_msr_data);
173 int load_msr_list(struct i2c_client *client, char *name,
174 const struct firmware **fw)
176 int ret = request_firmware(fw, name, &client->dev);
179 dev_err(&client->dev,
180 "Error %d while requesting firmware %s\n",
184 dev_info(&client->dev, "Received %lu bytes drv data\n",
185 (unsigned long)(*fw)->size);
189 EXPORT_SYMBOL_GPL(load_msr_list);
191 void release_msr_list(struct i2c_client *client, const struct firmware *fw)
193 release_firmware(fw);
195 EXPORT_SYMBOL_GPL(release_msr_list);
197 static int init_msrlisthelper(void)
202 static void exit_msrlisthelper(void)
206 module_init(init_msrlisthelper);
207 module_exit(exit_msrlisthelper);
209 MODULE_AUTHOR("Jukka Kaartinen <jukka.o.kaartinen@intel.com>");
210 MODULE_LICENSE("GPL");