162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/media/i2c/ccs/ccs-reg-access.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Generic driver for MIPI CCS/SMIA/SMIA++ compliant camera sensors
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2020 Intel Corporation
862306a36Sopenharmony_ci * Copyright (C) 2011--2012 Nokia Corporation
962306a36Sopenharmony_ci * Contact: Sakari Ailus <sakari.ailus@linux.intel.com>
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <asm/unaligned.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/delay.h>
1562306a36Sopenharmony_ci#include <linux/i2c.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "ccs.h"
1862306a36Sopenharmony_ci#include "ccs-limits.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic u32 float_to_u32_mul_1000000(struct i2c_client *client, u32 phloat)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	s32 exp;
2362306a36Sopenharmony_ci	u64 man;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	if (phloat >= 0x80000000) {
2662306a36Sopenharmony_ci		dev_err(&client->dev, "this is a negative number\n");
2762306a36Sopenharmony_ci		return 0;
2862306a36Sopenharmony_ci	}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	if (phloat == 0x7f800000)
3162306a36Sopenharmony_ci		return ~0; /* Inf. */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	if ((phloat & 0x7f800000) == 0x7f800000) {
3462306a36Sopenharmony_ci		dev_err(&client->dev, "NaN or other special number\n");
3562306a36Sopenharmony_ci		return 0;
3662306a36Sopenharmony_ci	}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	/* Valid cases begin here */
3962306a36Sopenharmony_ci	if (phloat == 0)
4062306a36Sopenharmony_ci		return 0; /* Valid zero */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	if (phloat > 0x4f800000)
4362306a36Sopenharmony_ci		return ~0; /* larger than 4294967295 */
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/*
4662306a36Sopenharmony_ci	 * Unbias exponent (note how phloat is now guaranteed to
4762306a36Sopenharmony_ci	 * have 0 in the high bit)
4862306a36Sopenharmony_ci	 */
4962306a36Sopenharmony_ci	exp = ((int32_t)phloat >> 23) - 127;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/* Extract mantissa, add missing '1' bit and it's in MHz */
5262306a36Sopenharmony_ci	man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (exp < 0)
5562306a36Sopenharmony_ci		man >>= -exp;
5662306a36Sopenharmony_ci	else
5762306a36Sopenharmony_ci		man <<= exp;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	man >>= 23; /* Remove mantissa bias */
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return man & 0xffffffff;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/*
6662306a36Sopenharmony_ci * Read a 8/16/32-bit i2c register.  The value is returned in 'val'.
6762306a36Sopenharmony_ci * Returns zero if successful, or non-zero otherwise.
6862306a36Sopenharmony_ci */
6962306a36Sopenharmony_cistatic int ____ccs_read_addr(struct ccs_sensor *sensor, u16 reg, u16 len,
7062306a36Sopenharmony_ci			     u32 *val)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
7362306a36Sopenharmony_ci	struct i2c_msg msg;
7462306a36Sopenharmony_ci	unsigned char data_buf[sizeof(u32)] = { 0 };
7562306a36Sopenharmony_ci	unsigned char offset_buf[sizeof(u16)];
7662306a36Sopenharmony_ci	int r;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (len > sizeof(data_buf))
7962306a36Sopenharmony_ci		return -EINVAL;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	msg.addr = client->addr;
8262306a36Sopenharmony_ci	msg.flags = 0;
8362306a36Sopenharmony_ci	msg.len = sizeof(offset_buf);
8462306a36Sopenharmony_ci	msg.buf = offset_buf;
8562306a36Sopenharmony_ci	put_unaligned_be16(reg, offset_buf);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	r = i2c_transfer(client->adapter, &msg, 1);
8862306a36Sopenharmony_ci	if (r != 1) {
8962306a36Sopenharmony_ci		if (r >= 0)
9062306a36Sopenharmony_ci			r = -EBUSY;
9162306a36Sopenharmony_ci		goto err;
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	msg.len = len;
9562306a36Sopenharmony_ci	msg.flags = I2C_M_RD;
9662306a36Sopenharmony_ci	msg.buf = &data_buf[sizeof(data_buf) - len];
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	r = i2c_transfer(client->adapter, &msg, 1);
9962306a36Sopenharmony_ci	if (r != 1) {
10062306a36Sopenharmony_ci		if (r >= 0)
10162306a36Sopenharmony_ci			r = -EBUSY;
10262306a36Sopenharmony_ci		goto err;
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	*val = get_unaligned_be32(data_buf);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	return 0;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cierr:
11062306a36Sopenharmony_ci	dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return r;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/* Read a register using 8-bit access only. */
11662306a36Sopenharmony_cistatic int ____ccs_read_addr_8only(struct ccs_sensor *sensor, u16 reg,
11762306a36Sopenharmony_ci				   u16 len, u32 *val)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	unsigned int i;
12062306a36Sopenharmony_ci	int rval;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	*val = 0;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
12562306a36Sopenharmony_ci		u32 val8;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci		rval = ____ccs_read_addr(sensor, reg + i, 1, &val8);
12862306a36Sopenharmony_ci		if (rval < 0)
12962306a36Sopenharmony_ci			return rval;
13062306a36Sopenharmony_ci		*val |= val8 << ((len - i - 1) << 3);
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	return 0;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ciunsigned int ccs_reg_width(u32 reg)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	if (reg & CCS_FL_16BIT)
13962306a36Sopenharmony_ci		return sizeof(u16);
14062306a36Sopenharmony_ci	if (reg & CCS_FL_32BIT)
14162306a36Sopenharmony_ci		return sizeof(u32);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return sizeof(u8);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic u32 ireal32_to_u32_mul_1000000(struct i2c_client *client, u32 val)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	if (val >> 10 > U32_MAX / 15625) {
14962306a36Sopenharmony_ci		dev_warn(&client->dev, "value %u overflows!\n", val);
15062306a36Sopenharmony_ci		return U32_MAX;
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return ((val >> 10) * 15625) +
15462306a36Sopenharmony_ci		(val & GENMASK(9, 0)) * 15625 / 1024;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ciu32 ccs_reg_conv(struct ccs_sensor *sensor, u32 reg, u32 val)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (reg & CCS_FL_FLOAT_IREAL) {
16262306a36Sopenharmony_ci		if (CCS_LIM(sensor, CLOCK_CAPA_TYPE_CAPABILITY) &
16362306a36Sopenharmony_ci		    CCS_CLOCK_CAPA_TYPE_CAPABILITY_IREAL)
16462306a36Sopenharmony_ci			val = ireal32_to_u32_mul_1000000(client, val);
16562306a36Sopenharmony_ci		else
16662306a36Sopenharmony_ci			val = float_to_u32_mul_1000000(client, val);
16762306a36Sopenharmony_ci	} else if (reg & CCS_FL_IREAL) {
16862306a36Sopenharmony_ci		val = ireal32_to_u32_mul_1000000(client, val);
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	return val;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/*
17562306a36Sopenharmony_ci * Read a 8/16/32-bit i2c register.  The value is returned in 'val'.
17662306a36Sopenharmony_ci * Returns zero if successful, or non-zero otherwise.
17762306a36Sopenharmony_ci */
17862306a36Sopenharmony_cistatic int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val,
17962306a36Sopenharmony_ci			   bool only8, bool conv)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	unsigned int len = ccs_reg_width(reg);
18262306a36Sopenharmony_ci	int rval;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (!only8)
18562306a36Sopenharmony_ci		rval = ____ccs_read_addr(sensor, CCS_REG_ADDR(reg), len, val);
18662306a36Sopenharmony_ci	else
18762306a36Sopenharmony_ci		rval = ____ccs_read_addr_8only(sensor, CCS_REG_ADDR(reg), len,
18862306a36Sopenharmony_ci					       val);
18962306a36Sopenharmony_ci	if (rval < 0)
19062306a36Sopenharmony_ci		return rval;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (!conv)
19362306a36Sopenharmony_ci		return 0;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	*val = ccs_reg_conv(sensor, reg, *val);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	return 0;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic int __ccs_read_data(struct ccs_reg *regs, size_t num_regs,
20162306a36Sopenharmony_ci			   u32 reg, u32 *val)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	unsigned int width = ccs_reg_width(reg);
20462306a36Sopenharmony_ci	size_t i;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	for (i = 0; i < num_regs; i++, regs++) {
20762306a36Sopenharmony_ci		u8 *data;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		if (regs->addr + regs->len < CCS_REG_ADDR(reg) + width)
21062306a36Sopenharmony_ci			continue;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		if (regs->addr > CCS_REG_ADDR(reg))
21362306a36Sopenharmony_ci			break;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		data = &regs->value[CCS_REG_ADDR(reg) - regs->addr];
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		switch (width) {
21862306a36Sopenharmony_ci		case sizeof(u8):
21962306a36Sopenharmony_ci			*val = *data;
22062306a36Sopenharmony_ci			break;
22162306a36Sopenharmony_ci		case sizeof(u16):
22262306a36Sopenharmony_ci			*val = get_unaligned_be16(data);
22362306a36Sopenharmony_ci			break;
22462306a36Sopenharmony_ci		case sizeof(u32):
22562306a36Sopenharmony_ci			*val = get_unaligned_be32(data);
22662306a36Sopenharmony_ci			break;
22762306a36Sopenharmony_ci		default:
22862306a36Sopenharmony_ci			WARN_ON(1);
22962306a36Sopenharmony_ci			return -EINVAL;
23062306a36Sopenharmony_ci		}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci		return 0;
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	return -ENOENT;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic int ccs_read_data(struct ccs_sensor *sensor, u32 reg, u32 *val)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	if (!__ccs_read_data(sensor->sdata.sensor_read_only_regs,
24162306a36Sopenharmony_ci			     sensor->sdata.num_sensor_read_only_regs,
24262306a36Sopenharmony_ci			     reg, val))
24362306a36Sopenharmony_ci		return 0;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	return __ccs_read_data(sensor->mdata.module_read_only_regs,
24662306a36Sopenharmony_ci			       sensor->mdata.num_module_read_only_regs,
24762306a36Sopenharmony_ci			       reg, val);
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic int ccs_read_addr_raw(struct ccs_sensor *sensor, u32 reg, u32 *val,
25162306a36Sopenharmony_ci			     bool force8, bool quirk, bool conv, bool data)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	int rval;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (data) {
25662306a36Sopenharmony_ci		rval = ccs_read_data(sensor, reg, val);
25762306a36Sopenharmony_ci		if (!rval)
25862306a36Sopenharmony_ci			return 0;
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (quirk) {
26262306a36Sopenharmony_ci		*val = 0;
26362306a36Sopenharmony_ci		rval = ccs_call_quirk(sensor, reg_access, false, &reg, val);
26462306a36Sopenharmony_ci		if (rval == -ENOIOCTLCMD)
26562306a36Sopenharmony_ci			return 0;
26662306a36Sopenharmony_ci		if (rval < 0)
26762306a36Sopenharmony_ci			return rval;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		if (force8)
27062306a36Sopenharmony_ci			return __ccs_read_addr(sensor, reg, val, true, conv);
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	return __ccs_read_addr(sensor, reg, val,
27462306a36Sopenharmony_ci			       ccs_needs_quirk(sensor,
27562306a36Sopenharmony_ci					       CCS_QUIRK_FLAG_8BIT_READ_ONLY),
27662306a36Sopenharmony_ci			       conv);
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ciint ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	return ccs_read_addr_raw(sensor, reg, val, false, true, true, true);
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ciint ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	return ccs_read_addr_raw(sensor, reg, val, true, true, true, true);
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ciint ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	return ccs_read_addr_raw(sensor, reg, val, false, true, false, true);
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic int ccs_write_retry(struct i2c_client *client, struct i2c_msg *msg)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	unsigned int retries;
29762306a36Sopenharmony_ci	int r;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	for (retries = 0; retries < 10; retries++) {
30062306a36Sopenharmony_ci		/*
30162306a36Sopenharmony_ci		 * Due to unknown reason sensor stops responding. This
30262306a36Sopenharmony_ci		 * loop is a temporaty solution until the root cause
30362306a36Sopenharmony_ci		 * is found.
30462306a36Sopenharmony_ci		 */
30562306a36Sopenharmony_ci		r = i2c_transfer(client->adapter, msg, 1);
30662306a36Sopenharmony_ci		if (r != 1) {
30762306a36Sopenharmony_ci			usleep_range(1000, 2000);
30862306a36Sopenharmony_ci			continue;
30962306a36Sopenharmony_ci		}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci		if (retries)
31262306a36Sopenharmony_ci			dev_err(&client->dev,
31362306a36Sopenharmony_ci				"sensor i2c stall encountered. retries: %d\n",
31462306a36Sopenharmony_ci				retries);
31562306a36Sopenharmony_ci		return 0;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	return r;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ciint ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
32462306a36Sopenharmony_ci	struct i2c_msg msg;
32562306a36Sopenharmony_ci	unsigned char data[6];
32662306a36Sopenharmony_ci	unsigned int len = ccs_reg_width(reg);
32762306a36Sopenharmony_ci	int r;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (len > sizeof(data) - 2)
33062306a36Sopenharmony_ci		return -EINVAL;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	msg.addr = client->addr;
33362306a36Sopenharmony_ci	msg.flags = 0; /* Write */
33462306a36Sopenharmony_ci	msg.len = 2 + len;
33562306a36Sopenharmony_ci	msg.buf = data;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	put_unaligned_be16(CCS_REG_ADDR(reg), data);
33862306a36Sopenharmony_ci	put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	dev_dbg(&client->dev, "writing reg 0x%4.4x value 0x%*.*x (%u)\n",
34162306a36Sopenharmony_ci		CCS_REG_ADDR(reg), ccs_reg_width(reg) << 1,
34262306a36Sopenharmony_ci		ccs_reg_width(reg) << 1, val, val);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	r = ccs_write_retry(client, &msg);
34562306a36Sopenharmony_ci	if (r)
34662306a36Sopenharmony_ci		dev_err(&client->dev,
34762306a36Sopenharmony_ci			"wrote 0x%x to offset 0x%x error %d\n", val,
34862306a36Sopenharmony_ci			CCS_REG_ADDR(reg), r);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	return r;
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci/*
35462306a36Sopenharmony_ci * Write to a 8/16-bit register.
35562306a36Sopenharmony_ci * Returns zero if successful, or non-zero otherwise.
35662306a36Sopenharmony_ci */
35762306a36Sopenharmony_ciint ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	int rval;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	rval = ccs_call_quirk(sensor, reg_access, true, &reg, &val);
36262306a36Sopenharmony_ci	if (rval == -ENOIOCTLCMD)
36362306a36Sopenharmony_ci		return 0;
36462306a36Sopenharmony_ci	if (rval < 0)
36562306a36Sopenharmony_ci		return rval;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	return ccs_write_addr_no_quirk(sensor, reg, val);
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci#define MAX_WRITE_LEN	32U
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ciint ccs_write_data_regs(struct ccs_sensor *sensor, struct ccs_reg *regs,
37362306a36Sopenharmony_ci			size_t num_regs)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
37662306a36Sopenharmony_ci	unsigned char buf[2 + MAX_WRITE_LEN];
37762306a36Sopenharmony_ci	struct i2c_msg msg = {
37862306a36Sopenharmony_ci		.addr = client->addr,
37962306a36Sopenharmony_ci		.buf = buf,
38062306a36Sopenharmony_ci	};
38162306a36Sopenharmony_ci	size_t i;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	for (i = 0; i < num_regs; i++, regs++) {
38462306a36Sopenharmony_ci		unsigned char *regdata = regs->value;
38562306a36Sopenharmony_ci		unsigned int j;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci		for (j = 0; j < regs->len;
38862306a36Sopenharmony_ci		     j += msg.len - 2, regdata += msg.len - 2) {
38962306a36Sopenharmony_ci			char printbuf[(MAX_WRITE_LEN << 1) +
39062306a36Sopenharmony_ci				      1 /* \0 */] = { 0 };
39162306a36Sopenharmony_ci			int rval;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci			msg.len = min(regs->len - j, MAX_WRITE_LEN);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci			bin2hex(printbuf, regdata, msg.len);
39662306a36Sopenharmony_ci			dev_dbg(&client->dev,
39762306a36Sopenharmony_ci				"writing msr reg 0x%4.4x value 0x%s\n",
39862306a36Sopenharmony_ci				regs->addr + j, printbuf);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci			put_unaligned_be16(regs->addr + j, buf);
40162306a36Sopenharmony_ci			memcpy(buf + 2, regdata, msg.len);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci			msg.len += 2;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci			rval = ccs_write_retry(client, &msg);
40662306a36Sopenharmony_ci			if (rval) {
40762306a36Sopenharmony_ci				dev_err(&client->dev,
40862306a36Sopenharmony_ci					"error writing %u octets to address 0x%4.4x\n",
40962306a36Sopenharmony_ci					msg.len, regs->addr + j);
41062306a36Sopenharmony_ci				return rval;
41162306a36Sopenharmony_ci			}
41262306a36Sopenharmony_ci		}
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	return 0;
41662306a36Sopenharmony_ci}
417