xref: /linux/drivers/media/i2c/ccs/ccs-reg-access.c (revision 7ec462100ef9142344ddbf86f2c3008b97acddbe)
1b24cc2a1SSakari Ailus // SPDX-License-Identifier: GPL-2.0-only
2b24cc2a1SSakari Ailus /*
3b24cc2a1SSakari Ailus  * drivers/media/i2c/ccs/ccs-reg-access.c
4b24cc2a1SSakari Ailus  *
5b24cc2a1SSakari Ailus  * Generic driver for MIPI CCS/SMIA/SMIA++ compliant camera sensors
6b24cc2a1SSakari Ailus  *
7b24cc2a1SSakari Ailus  * Copyright (C) 2020 Intel Corporation
8b24cc2a1SSakari Ailus  * Copyright (C) 2011--2012 Nokia Corporation
97389d01cSSakari Ailus  * Contact: Sakari Ailus <sakari.ailus@linux.intel.com>
10b24cc2a1SSakari Ailus  */
11b24cc2a1SSakari Ailus 
12*5f60d5f6SAl Viro #include <linux/unaligned.h>
13b24cc2a1SSakari Ailus 
14b24cc2a1SSakari Ailus #include <linux/delay.h>
15b24cc2a1SSakari Ailus #include <linux/i2c.h>
16b24cc2a1SSakari Ailus 
17b24cc2a1SSakari Ailus #include "ccs.h"
18fe652254SSakari Ailus #include "ccs-limits.h"
19b24cc2a1SSakari Ailus 
float_to_u32_mul_1000000(struct i2c_client * client,u32 phloat)20dffbdf37SSakari Ailus static u32 float_to_u32_mul_1000000(struct i2c_client *client, u32 phloat)
21b24cc2a1SSakari Ailus {
22dffbdf37SSakari Ailus 	s32 exp;
23dffbdf37SSakari Ailus 	u64 man;
24b24cc2a1SSakari Ailus 
25b24cc2a1SSakari Ailus 	if (phloat >= 0x80000000) {
26b24cc2a1SSakari Ailus 		dev_err(&client->dev, "this is a negative number\n");
27b24cc2a1SSakari Ailus 		return 0;
28b24cc2a1SSakari Ailus 	}
29b24cc2a1SSakari Ailus 
30b24cc2a1SSakari Ailus 	if (phloat == 0x7f800000)
31b24cc2a1SSakari Ailus 		return ~0; /* Inf. */
32b24cc2a1SSakari Ailus 
33b24cc2a1SSakari Ailus 	if ((phloat & 0x7f800000) == 0x7f800000) {
34b24cc2a1SSakari Ailus 		dev_err(&client->dev, "NaN or other special number\n");
35b24cc2a1SSakari Ailus 		return 0;
36b24cc2a1SSakari Ailus 	}
37b24cc2a1SSakari Ailus 
38b24cc2a1SSakari Ailus 	/* Valid cases begin here */
39b24cc2a1SSakari Ailus 	if (phloat == 0)
40b24cc2a1SSakari Ailus 		return 0; /* Valid zero */
41b24cc2a1SSakari Ailus 
42b24cc2a1SSakari Ailus 	if (phloat > 0x4f800000)
43b24cc2a1SSakari Ailus 		return ~0; /* larger than 4294967295 */
44b24cc2a1SSakari Ailus 
45b24cc2a1SSakari Ailus 	/*
46b24cc2a1SSakari Ailus 	 * Unbias exponent (note how phloat is now guaranteed to
47b24cc2a1SSakari Ailus 	 * have 0 in the high bit)
48b24cc2a1SSakari Ailus 	 */
49b24cc2a1SSakari Ailus 	exp = ((int32_t)phloat >> 23) - 127;
50b24cc2a1SSakari Ailus 
51b24cc2a1SSakari Ailus 	/* Extract mantissa, add missing '1' bit and it's in MHz */
52b24cc2a1SSakari Ailus 	man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL;
53b24cc2a1SSakari Ailus 
54b24cc2a1SSakari Ailus 	if (exp < 0)
55b24cc2a1SSakari Ailus 		man >>= -exp;
56b24cc2a1SSakari Ailus 	else
57b24cc2a1SSakari Ailus 		man <<= exp;
58b24cc2a1SSakari Ailus 
59b24cc2a1SSakari Ailus 	man >>= 23; /* Remove mantissa bias */
60b24cc2a1SSakari Ailus 
61b24cc2a1SSakari Ailus 	return man & 0xffffffff;
62b24cc2a1SSakari Ailus }
63b24cc2a1SSakari Ailus 
64b24cc2a1SSakari Ailus 
ireal32_to_u32_mul_1000000(struct i2c_client * client,u32 val)65fe652254SSakari Ailus static u32 ireal32_to_u32_mul_1000000(struct i2c_client *client, u32 val)
66fe652254SSakari Ailus {
67fe652254SSakari Ailus 	if (val >> 10 > U32_MAX / 15625) {
68fe652254SSakari Ailus 		dev_warn(&client->dev, "value %u overflows!\n", val);
69fe652254SSakari Ailus 		return U32_MAX;
70fe652254SSakari Ailus 	}
71fe652254SSakari Ailus 
72fe652254SSakari Ailus 	return ((val >> 10) * 15625) +
73fe652254SSakari Ailus 		(val & GENMASK(9, 0)) * 15625 / 1024;
74fe652254SSakari Ailus }
75fe652254SSakari Ailus 
ccs_reg_conv(struct ccs_sensor * sensor,u32 reg,u32 val)767d2f8ddaSSakari Ailus u32 ccs_reg_conv(struct ccs_sensor *sensor, u32 reg, u32 val)
777d2f8ddaSSakari Ailus {
787d2f8ddaSSakari Ailus 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
797d2f8ddaSSakari Ailus 
80fe652254SSakari Ailus 	if (reg & CCS_FL_FLOAT_IREAL) {
81fe652254SSakari Ailus 		if (CCS_LIM(sensor, CLOCK_CAPA_TYPE_CAPABILITY) &
82fe652254SSakari Ailus 		    CCS_CLOCK_CAPA_TYPE_CAPABILITY_IREAL)
83fe652254SSakari Ailus 			val = ireal32_to_u32_mul_1000000(client, val);
84fe652254SSakari Ailus 		else
857d2f8ddaSSakari Ailus 			val = float_to_u32_mul_1000000(client, val);
86fe652254SSakari Ailus 	} else if (reg & CCS_FL_IREAL) {
87fe652254SSakari Ailus 		val = ireal32_to_u32_mul_1000000(client, val);
88fe652254SSakari Ailus 	}
897d2f8ddaSSakari Ailus 
907d2f8ddaSSakari Ailus 	return val;
917d2f8ddaSSakari Ailus }
927d2f8ddaSSakari Ailus 
93b24cc2a1SSakari Ailus /*
94b24cc2a1SSakari Ailus  * Read a 8/16/32-bit i2c register.  The value is returned in 'val'.
95b24cc2a1SSakari Ailus  * Returns zero if successful, or non-zero otherwise.
96b24cc2a1SSakari Ailus  */
__ccs_read_addr(struct ccs_sensor * sensor,u32 reg,u32 * val,bool only8,bool conv)97b24cc2a1SSakari Ailus static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val,
987d2f8ddaSSakari Ailus 			   bool only8, bool conv)
99b24cc2a1SSakari Ailus {
10052932211SSakari Ailus 	u64 __val;
101b24cc2a1SSakari Ailus 	int rval;
102b24cc2a1SSakari Ailus 
10352932211SSakari Ailus 	rval = cci_read(sensor->regmap, reg, &__val, NULL);
104b24cc2a1SSakari Ailus 	if (rval < 0)
105b24cc2a1SSakari Ailus 		return rval;
106b24cc2a1SSakari Ailus 
10752932211SSakari Ailus 	*val = conv ? ccs_reg_conv(sensor, reg, __val) : __val;
108b24cc2a1SSakari Ailus 
109b24cc2a1SSakari Ailus 	return 0;
110b24cc2a1SSakari Ailus }
111b24cc2a1SSakari Ailus 
__ccs_static_data_read_ro_reg(struct ccs_reg * regs,size_t num_regs,u32 reg,u32 * val)112d180509cSSakari Ailus static int __ccs_static_data_read_ro_reg(struct ccs_reg *regs, size_t num_regs,
1131b398012SSakari Ailus 					 u32 reg, u32 *val)
1141b398012SSakari Ailus {
11552932211SSakari Ailus 	unsigned int width = CCI_REG_WIDTH_BYTES(reg);
1161b398012SSakari Ailus 	size_t i;
1171b398012SSakari Ailus 
1181b398012SSakari Ailus 	for (i = 0; i < num_regs; i++, regs++) {
119dffbdf37SSakari Ailus 		u8 *data;
1201b398012SSakari Ailus 
1211b398012SSakari Ailus 		if (regs->addr + regs->len < CCS_REG_ADDR(reg) + width)
1221b398012SSakari Ailus 			continue;
1231b398012SSakari Ailus 
1241b398012SSakari Ailus 		if (regs->addr > CCS_REG_ADDR(reg))
1251b398012SSakari Ailus 			break;
1261b398012SSakari Ailus 
1271b398012SSakari Ailus 		data = &regs->value[CCS_REG_ADDR(reg) - regs->addr];
1281b398012SSakari Ailus 
1291b398012SSakari Ailus 		switch (width) {
130dffbdf37SSakari Ailus 		case sizeof(u8):
1311b398012SSakari Ailus 			*val = *data;
1321b398012SSakari Ailus 			break;
133dffbdf37SSakari Ailus 		case sizeof(u16):
1341b398012SSakari Ailus 			*val = get_unaligned_be16(data);
1351b398012SSakari Ailus 			break;
136dffbdf37SSakari Ailus 		case sizeof(u32):
1371b398012SSakari Ailus 			*val = get_unaligned_be32(data);
1381b398012SSakari Ailus 			break;
1391b398012SSakari Ailus 		default:
1401b398012SSakari Ailus 			WARN_ON(1);
1411b398012SSakari Ailus 			return -EINVAL;
1421b398012SSakari Ailus 		}
1431b398012SSakari Ailus 
1441b398012SSakari Ailus 		return 0;
1451b398012SSakari Ailus 	}
1461b398012SSakari Ailus 
1471b398012SSakari Ailus 	return -ENOENT;
1481b398012SSakari Ailus }
1491b398012SSakari Ailus 
150d180509cSSakari Ailus static int
ccs_static_data_read_ro_reg(struct ccs_sensor * sensor,u32 reg,u32 * val)151d180509cSSakari Ailus ccs_static_data_read_ro_reg(struct ccs_sensor *sensor, u32 reg, u32 *val)
1521b398012SSakari Ailus {
153d180509cSSakari Ailus 	if (!__ccs_static_data_read_ro_reg(sensor->sdata.sensor_read_only_regs,
1541b398012SSakari Ailus 					   sensor->sdata.num_sensor_read_only_regs,
1551b398012SSakari Ailus 					   reg, val))
1561b398012SSakari Ailus 		return 0;
1571b398012SSakari Ailus 
158d180509cSSakari Ailus 	return __ccs_static_data_read_ro_reg(sensor->mdata.module_read_only_regs,
1591b398012SSakari Ailus 					     sensor->mdata.num_module_read_only_regs,
1601b398012SSakari Ailus 					     reg, val);
1611b398012SSakari Ailus }
1621b398012SSakari Ailus 
ccs_read_addr_raw(struct ccs_sensor * sensor,u32 reg,u32 * val,bool force8,bool quirk,bool conv,bool data)1632989a457SSakari Ailus static int ccs_read_addr_raw(struct ccs_sensor *sensor, u32 reg, u32 *val,
1641b398012SSakari Ailus 			     bool force8, bool quirk, bool conv, bool data)
165b24cc2a1SSakari Ailus {
166b24cc2a1SSakari Ailus 	int rval;
167b24cc2a1SSakari Ailus 
1681b398012SSakari Ailus 	if (data) {
169d180509cSSakari Ailus 		rval = ccs_static_data_read_ro_reg(sensor, reg, val);
1701b398012SSakari Ailus 		if (!rval)
1711b398012SSakari Ailus 			return 0;
1721b398012SSakari Ailus 	}
1731b398012SSakari Ailus 
1742989a457SSakari Ailus 	if (quirk) {
175b24cc2a1SSakari Ailus 		*val = 0;
176b24cc2a1SSakari Ailus 		rval = ccs_call_quirk(sensor, reg_access, false, &reg, val);
177b24cc2a1SSakari Ailus 		if (rval == -ENOIOCTLCMD)
178b24cc2a1SSakari Ailus 			return 0;
179b24cc2a1SSakari Ailus 		if (rval < 0)
180b24cc2a1SSakari Ailus 			return rval;
181b24cc2a1SSakari Ailus 
182b24cc2a1SSakari Ailus 		if (force8)
1837d2f8ddaSSakari Ailus 			return __ccs_read_addr(sensor, reg, val, true, conv);
1842989a457SSakari Ailus 	}
185b24cc2a1SSakari Ailus 
1862989a457SSakari Ailus 	return __ccs_read_addr(sensor, reg, val,
1872989a457SSakari Ailus 			       ccs_needs_quirk(sensor,
1887d2f8ddaSSakari Ailus 					       CCS_QUIRK_FLAG_8BIT_READ_ONLY),
1897d2f8ddaSSakari Ailus 			       conv);
190b24cc2a1SSakari Ailus }
191b24cc2a1SSakari Ailus 
ccs_read_addr(struct ccs_sensor * sensor,u32 reg,u32 * val)192b24cc2a1SSakari Ailus int ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val)
193b24cc2a1SSakari Ailus {
1941b398012SSakari Ailus 	return ccs_read_addr_raw(sensor, reg, val, false, true, true, true);
195b24cc2a1SSakari Ailus }
196b24cc2a1SSakari Ailus 
ccs_read_addr_8only(struct ccs_sensor * sensor,u32 reg,u32 * val)197b24cc2a1SSakari Ailus int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val)
198b24cc2a1SSakari Ailus {
1991b398012SSakari Ailus 	return ccs_read_addr_raw(sensor, reg, val, true, true, true, true);
2007d2f8ddaSSakari Ailus }
2017d2f8ddaSSakari Ailus 
ccs_read_addr_noconv(struct ccs_sensor * sensor,u32 reg,u32 * val)2027d2f8ddaSSakari Ailus int ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val)
2037d2f8ddaSSakari Ailus {
2041b398012SSakari Ailus 	return ccs_read_addr_raw(sensor, reg, val, false, true, false, true);
205b24cc2a1SSakari Ailus }
206b24cc2a1SSakari Ailus 
207b24cc2a1SSakari Ailus /*
208b24cc2a1SSakari Ailus  * Write to a 8/16-bit register.
209b24cc2a1SSakari Ailus  * Returns zero if successful, or non-zero otherwise.
210b24cc2a1SSakari Ailus  */
ccs_write_addr(struct ccs_sensor * sensor,u32 reg,u32 val)211b24cc2a1SSakari Ailus int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val)
212b24cc2a1SSakari Ailus {
21352932211SSakari Ailus 	unsigned int retries = 10;
214b24cc2a1SSakari Ailus 	int rval;
215b24cc2a1SSakari Ailus 
216b24cc2a1SSakari Ailus 	rval = ccs_call_quirk(sensor, reg_access, true, &reg, &val);
217b24cc2a1SSakari Ailus 	if (rval == -ENOIOCTLCMD)
218b24cc2a1SSakari Ailus 		return 0;
219b24cc2a1SSakari Ailus 	if (rval < 0)
220b24cc2a1SSakari Ailus 		return rval;
221b24cc2a1SSakari Ailus 
22252932211SSakari Ailus 	rval = 0;
22352932211SSakari Ailus 	do {
22452932211SSakari Ailus 		if (cci_write(sensor->regmap, reg, val, &rval))
22552932211SSakari Ailus 			fsleep(1000);
22652932211SSakari Ailus 	} while (rval && --retries);
22752932211SSakari Ailus 
22852932211SSakari Ailus 	return rval;
229b24cc2a1SSakari Ailus }
2302538d322SSakari Ailus 
2312538d322SSakari Ailus #define MAX_WRITE_LEN	32U
2322538d322SSakari Ailus 
ccs_write_data_regs(struct ccs_sensor * sensor,struct ccs_reg * regs,size_t num_regs)2332538d322SSakari Ailus int ccs_write_data_regs(struct ccs_sensor *sensor, struct ccs_reg *regs,
2342538d322SSakari Ailus 			size_t num_regs)
2352538d322SSakari Ailus {
2362538d322SSakari Ailus 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
2372538d322SSakari Ailus 	size_t i;
2382538d322SSakari Ailus 
2392538d322SSakari Ailus 	for (i = 0; i < num_regs; i++, regs++) {
2402538d322SSakari Ailus 		unsigned char *regdata = regs->value;
2412538d322SSakari Ailus 		unsigned int j;
24252932211SSakari Ailus 		int len;
2432538d322SSakari Ailus 
24452932211SSakari Ailus 		for (j = 0; j < regs->len; j += len, regdata += len) {
2457a426098SSakari Ailus 			char printbuf[(MAX_WRITE_LEN << 1) +
2467a426098SSakari Ailus 				      1 /* \0 */] = { 0 };
24752932211SSakari Ailus 			unsigned int retries = 10;
2482538d322SSakari Ailus 			int rval;
2492538d322SSakari Ailus 
25052932211SSakari Ailus 			len = min(regs->len - j, MAX_WRITE_LEN);
2512538d322SSakari Ailus 
25252932211SSakari Ailus 			bin2hex(printbuf, regdata, len);
2537a426098SSakari Ailus 			dev_dbg(&client->dev,
2547a426098SSakari Ailus 				"writing msr reg 0x%4.4x value 0x%s\n",
2557a426098SSakari Ailus 				regs->addr + j, printbuf);
2567a426098SSakari Ailus 
25752932211SSakari Ailus 			do {
25852932211SSakari Ailus 				rval = regmap_bulk_write(sensor->regmap,
25952932211SSakari Ailus 							 regs->addr + j,
26052932211SSakari Ailus 							 regdata, len);
26152932211SSakari Ailus 				if (rval)
26252932211SSakari Ailus 					fsleep(1000);
26352932211SSakari Ailus 			} while (rval && --retries);
2647a426098SSakari Ailus 
2652538d322SSakari Ailus 			if (rval) {
2662538d322SSakari Ailus 				dev_err(&client->dev,
2672538d322SSakari Ailus 					"error writing %u octets to address 0x%4.4x\n",
26852932211SSakari Ailus 					len, regs->addr + j);
2692538d322SSakari Ailus 				return rval;
2702538d322SSakari Ailus 			}
2712538d322SSakari Ailus 		}
2722538d322SSakari Ailus 	}
2732538d322SSakari Ailus 
2742538d322SSakari Ailus 	return 0;
2752538d322SSakari Ailus }
276