xref: /linux/drivers/media/i2c/ccs/ccs-reg-access.c (revision fe652254e243a58daf50aa0ddb938885ae2ba565)
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
9b24cc2a1SSakari Ailus  * Contact: Sakari Ailus <sakari.ailus@iki.fi>
10b24cc2a1SSakari Ailus  */
11b24cc2a1SSakari Ailus 
12b24cc2a1SSakari Ailus #include <asm/unaligned.h>
13b24cc2a1SSakari Ailus 
14b24cc2a1SSakari Ailus #include <linux/delay.h>
15b24cc2a1SSakari Ailus #include <linux/i2c.h>
16b24cc2a1SSakari Ailus 
17b24cc2a1SSakari Ailus #include "ccs.h"
18*fe652254SSakari Ailus #include "ccs-limits.h"
19b24cc2a1SSakari Ailus 
20b24cc2a1SSakari Ailus static uint32_t float_to_u32_mul_1000000(struct i2c_client *client,
21b24cc2a1SSakari Ailus 					 uint32_t phloat)
22b24cc2a1SSakari Ailus {
23b24cc2a1SSakari Ailus 	int32_t exp;
24b24cc2a1SSakari Ailus 	uint64_t man;
25b24cc2a1SSakari Ailus 
26b24cc2a1SSakari Ailus 	if (phloat >= 0x80000000) {
27b24cc2a1SSakari Ailus 		dev_err(&client->dev, "this is a negative number\n");
28b24cc2a1SSakari Ailus 		return 0;
29b24cc2a1SSakari Ailus 	}
30b24cc2a1SSakari Ailus 
31b24cc2a1SSakari Ailus 	if (phloat == 0x7f800000)
32b24cc2a1SSakari Ailus 		return ~0; /* Inf. */
33b24cc2a1SSakari Ailus 
34b24cc2a1SSakari Ailus 	if ((phloat & 0x7f800000) == 0x7f800000) {
35b24cc2a1SSakari Ailus 		dev_err(&client->dev, "NaN or other special number\n");
36b24cc2a1SSakari Ailus 		return 0;
37b24cc2a1SSakari Ailus 	}
38b24cc2a1SSakari Ailus 
39b24cc2a1SSakari Ailus 	/* Valid cases begin here */
40b24cc2a1SSakari Ailus 	if (phloat == 0)
41b24cc2a1SSakari Ailus 		return 0; /* Valid zero */
42b24cc2a1SSakari Ailus 
43b24cc2a1SSakari Ailus 	if (phloat > 0x4f800000)
44b24cc2a1SSakari Ailus 		return ~0; /* larger than 4294967295 */
45b24cc2a1SSakari Ailus 
46b24cc2a1SSakari Ailus 	/*
47b24cc2a1SSakari Ailus 	 * Unbias exponent (note how phloat is now guaranteed to
48b24cc2a1SSakari Ailus 	 * have 0 in the high bit)
49b24cc2a1SSakari Ailus 	 */
50b24cc2a1SSakari Ailus 	exp = ((int32_t)phloat >> 23) - 127;
51b24cc2a1SSakari Ailus 
52b24cc2a1SSakari Ailus 	/* Extract mantissa, add missing '1' bit and it's in MHz */
53b24cc2a1SSakari Ailus 	man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL;
54b24cc2a1SSakari Ailus 
55b24cc2a1SSakari Ailus 	if (exp < 0)
56b24cc2a1SSakari Ailus 		man >>= -exp;
57b24cc2a1SSakari Ailus 	else
58b24cc2a1SSakari Ailus 		man <<= exp;
59b24cc2a1SSakari Ailus 
60b24cc2a1SSakari Ailus 	man >>= 23; /* Remove mantissa bias */
61b24cc2a1SSakari Ailus 
62b24cc2a1SSakari Ailus 	return man & 0xffffffff;
63b24cc2a1SSakari Ailus }
64b24cc2a1SSakari Ailus 
65b24cc2a1SSakari Ailus 
66b24cc2a1SSakari Ailus /*
67b24cc2a1SSakari Ailus  * Read a 8/16/32-bit i2c register.  The value is returned in 'val'.
68b24cc2a1SSakari Ailus  * Returns zero if successful, or non-zero otherwise.
69b24cc2a1SSakari Ailus  */
70b24cc2a1SSakari Ailus static int ____ccs_read_addr(struct ccs_sensor *sensor, u16 reg, u16 len,
71b24cc2a1SSakari Ailus 			     u32 *val)
72b24cc2a1SSakari Ailus {
73b24cc2a1SSakari Ailus 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
74b24cc2a1SSakari Ailus 	struct i2c_msg msg;
75b24cc2a1SSakari Ailus 	unsigned char data_buf[sizeof(u32)] = { 0 };
76b24cc2a1SSakari Ailus 	unsigned char offset_buf[sizeof(u16)];
77b24cc2a1SSakari Ailus 	int r;
78b24cc2a1SSakari Ailus 
79b24cc2a1SSakari Ailus 	if (len > sizeof(data_buf))
80b24cc2a1SSakari Ailus 		return -EINVAL;
81b24cc2a1SSakari Ailus 
82b24cc2a1SSakari Ailus 	msg.addr = client->addr;
83b24cc2a1SSakari Ailus 	msg.flags = 0;
84b24cc2a1SSakari Ailus 	msg.len = sizeof(offset_buf);
85b24cc2a1SSakari Ailus 	msg.buf = offset_buf;
86b24cc2a1SSakari Ailus 	put_unaligned_be16(reg, offset_buf);
87b24cc2a1SSakari Ailus 
88b24cc2a1SSakari Ailus 	r = i2c_transfer(client->adapter, &msg, 1);
89b24cc2a1SSakari Ailus 	if (r != 1) {
90b24cc2a1SSakari Ailus 		if (r >= 0)
91b24cc2a1SSakari Ailus 			r = -EBUSY;
92b24cc2a1SSakari Ailus 		goto err;
93b24cc2a1SSakari Ailus 	}
94b24cc2a1SSakari Ailus 
95b24cc2a1SSakari Ailus 	msg.len = len;
96b24cc2a1SSakari Ailus 	msg.flags = I2C_M_RD;
97b24cc2a1SSakari Ailus 	msg.buf = &data_buf[sizeof(data_buf) - len];
98b24cc2a1SSakari Ailus 
99b24cc2a1SSakari Ailus 	r = i2c_transfer(client->adapter, &msg, 1);
100b24cc2a1SSakari Ailus 	if (r != 1) {
101b24cc2a1SSakari Ailus 		if (r >= 0)
102b24cc2a1SSakari Ailus 			r = -EBUSY;
103b24cc2a1SSakari Ailus 		goto err;
104b24cc2a1SSakari Ailus 	}
105b24cc2a1SSakari Ailus 
106b24cc2a1SSakari Ailus 	*val = get_unaligned_be32(data_buf);
107b24cc2a1SSakari Ailus 
108b24cc2a1SSakari Ailus 	return 0;
109b24cc2a1SSakari Ailus 
110b24cc2a1SSakari Ailus err:
111b24cc2a1SSakari Ailus 	dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r);
112b24cc2a1SSakari Ailus 
113b24cc2a1SSakari Ailus 	return r;
114b24cc2a1SSakari Ailus }
115b24cc2a1SSakari Ailus 
116b24cc2a1SSakari Ailus /* Read a register using 8-bit access only. */
117b24cc2a1SSakari Ailus static int ____ccs_read_addr_8only(struct ccs_sensor *sensor, u16 reg,
118b24cc2a1SSakari Ailus 				   u16 len, u32 *val)
119b24cc2a1SSakari Ailus {
120b24cc2a1SSakari Ailus 	unsigned int i;
121b24cc2a1SSakari Ailus 	int rval;
122b24cc2a1SSakari Ailus 
123b24cc2a1SSakari Ailus 	*val = 0;
124b24cc2a1SSakari Ailus 
125b24cc2a1SSakari Ailus 	for (i = 0; i < len; i++) {
126b24cc2a1SSakari Ailus 		u32 val8;
127b24cc2a1SSakari Ailus 
128b24cc2a1SSakari Ailus 		rval = ____ccs_read_addr(sensor, reg + i, 1, &val8);
129b24cc2a1SSakari Ailus 		if (rval < 0)
130b24cc2a1SSakari Ailus 			return rval;
131b24cc2a1SSakari Ailus 		*val |= val8 << ((len - i - 1) << 3);
132b24cc2a1SSakari Ailus 	}
133b24cc2a1SSakari Ailus 
134b24cc2a1SSakari Ailus 	return 0;
135b24cc2a1SSakari Ailus }
136b24cc2a1SSakari Ailus 
137b24cc2a1SSakari Ailus unsigned int ccs_reg_width(u32 reg)
138b24cc2a1SSakari Ailus {
139b24cc2a1SSakari Ailus 	if (reg & CCS_FL_16BIT)
140b24cc2a1SSakari Ailus 		return sizeof(uint16_t);
141b24cc2a1SSakari Ailus 	if (reg & CCS_FL_32BIT)
142b24cc2a1SSakari Ailus 		return sizeof(uint32_t);
143b24cc2a1SSakari Ailus 
144b24cc2a1SSakari Ailus 	return sizeof(uint8_t);
145b24cc2a1SSakari Ailus }
146b24cc2a1SSakari Ailus 
147*fe652254SSakari Ailus static u32 ireal32_to_u32_mul_1000000(struct i2c_client *client, u32 val)
148*fe652254SSakari Ailus {
149*fe652254SSakari Ailus 	if (val >> 10 > U32_MAX / 15625) {
150*fe652254SSakari Ailus 		dev_warn(&client->dev, "value %u overflows!\n", val);
151*fe652254SSakari Ailus 		return U32_MAX;
152*fe652254SSakari Ailus 	}
153*fe652254SSakari Ailus 
154*fe652254SSakari Ailus 	return ((val >> 10) * 15625) +
155*fe652254SSakari Ailus 		(val & GENMASK(9, 0)) * 15625 / 1024;
156*fe652254SSakari Ailus }
157*fe652254SSakari Ailus 
1587d2f8ddaSSakari Ailus u32 ccs_reg_conv(struct ccs_sensor *sensor, u32 reg, u32 val)
1597d2f8ddaSSakari Ailus {
1607d2f8ddaSSakari Ailus 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
1617d2f8ddaSSakari Ailus 
162*fe652254SSakari Ailus 	if (reg & CCS_FL_FLOAT_IREAL) {
163*fe652254SSakari Ailus 		if (CCS_LIM(sensor, CLOCK_CAPA_TYPE_CAPABILITY) &
164*fe652254SSakari Ailus 		    CCS_CLOCK_CAPA_TYPE_CAPABILITY_IREAL)
165*fe652254SSakari Ailus 			val = ireal32_to_u32_mul_1000000(client, val);
166*fe652254SSakari Ailus 		else
1677d2f8ddaSSakari Ailus 			val = float_to_u32_mul_1000000(client, val);
168*fe652254SSakari Ailus 	} else if (reg & CCS_FL_IREAL) {
169*fe652254SSakari Ailus 		val = ireal32_to_u32_mul_1000000(client, val);
170*fe652254SSakari Ailus 	}
1717d2f8ddaSSakari Ailus 
1727d2f8ddaSSakari Ailus 	return val;
1737d2f8ddaSSakari Ailus }
1747d2f8ddaSSakari Ailus 
175b24cc2a1SSakari Ailus /*
176b24cc2a1SSakari Ailus  * Read a 8/16/32-bit i2c register.  The value is returned in 'val'.
177b24cc2a1SSakari Ailus  * Returns zero if successful, or non-zero otherwise.
178b24cc2a1SSakari Ailus  */
179b24cc2a1SSakari Ailus static int __ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val,
1807d2f8ddaSSakari Ailus 			   bool only8, bool conv)
181b24cc2a1SSakari Ailus {
182b24cc2a1SSakari Ailus 	unsigned int len = ccs_reg_width(reg);
183b24cc2a1SSakari Ailus 	int rval;
184b24cc2a1SSakari Ailus 
185b24cc2a1SSakari Ailus 	if (!only8)
186b24cc2a1SSakari Ailus 		rval = ____ccs_read_addr(sensor, CCS_REG_ADDR(reg), len, val);
187b24cc2a1SSakari Ailus 	else
188b24cc2a1SSakari Ailus 		rval = ____ccs_read_addr_8only(sensor, CCS_REG_ADDR(reg), len,
189b24cc2a1SSakari Ailus 					       val);
190b24cc2a1SSakari Ailus 	if (rval < 0)
191b24cc2a1SSakari Ailus 		return rval;
192b24cc2a1SSakari Ailus 
1937d2f8ddaSSakari Ailus 	if (!conv)
1947d2f8ddaSSakari Ailus 		return 0;
1957d2f8ddaSSakari Ailus 
1967d2f8ddaSSakari Ailus 	*val = ccs_reg_conv(sensor, reg, *val);
197b24cc2a1SSakari Ailus 
198b24cc2a1SSakari Ailus 	return 0;
199b24cc2a1SSakari Ailus }
200b24cc2a1SSakari Ailus 
2012989a457SSakari Ailus static int ccs_read_addr_raw(struct ccs_sensor *sensor, u32 reg, u32 *val,
2027d2f8ddaSSakari Ailus 			     bool force8, bool quirk, bool conv)
203b24cc2a1SSakari Ailus {
204b24cc2a1SSakari Ailus 	int rval;
205b24cc2a1SSakari Ailus 
2062989a457SSakari Ailus 	if (quirk) {
207b24cc2a1SSakari Ailus 		*val = 0;
208b24cc2a1SSakari Ailus 		rval = ccs_call_quirk(sensor, reg_access, false, &reg, val);
209b24cc2a1SSakari Ailus 		if (rval == -ENOIOCTLCMD)
210b24cc2a1SSakari Ailus 			return 0;
211b24cc2a1SSakari Ailus 		if (rval < 0)
212b24cc2a1SSakari Ailus 			return rval;
213b24cc2a1SSakari Ailus 
214b24cc2a1SSakari Ailus 		if (force8)
2157d2f8ddaSSakari Ailus 			return __ccs_read_addr(sensor, reg, val, true, conv);
2162989a457SSakari Ailus 	}
217b24cc2a1SSakari Ailus 
2182989a457SSakari Ailus 	return __ccs_read_addr(sensor, reg, val,
2192989a457SSakari Ailus 			       ccs_needs_quirk(sensor,
2207d2f8ddaSSakari Ailus 					       CCS_QUIRK_FLAG_8BIT_READ_ONLY),
2217d2f8ddaSSakari Ailus 			       conv);
222b24cc2a1SSakari Ailus }
223b24cc2a1SSakari Ailus 
224b24cc2a1SSakari Ailus int ccs_read_addr(struct ccs_sensor *sensor, u32 reg, u32 *val)
225b24cc2a1SSakari Ailus {
2267d2f8ddaSSakari Ailus 	return ccs_read_addr_raw(sensor, reg, val, false, true, true);
227b24cc2a1SSakari Ailus }
228b24cc2a1SSakari Ailus 
229b24cc2a1SSakari Ailus int ccs_read_addr_8only(struct ccs_sensor *sensor, u32 reg, u32 *val)
230b24cc2a1SSakari Ailus {
2317d2f8ddaSSakari Ailus 	return ccs_read_addr_raw(sensor, reg, val, true, true, true);
2327d2f8ddaSSakari Ailus }
2337d2f8ddaSSakari Ailus 
2347d2f8ddaSSakari Ailus int ccs_read_addr_noconv(struct ccs_sensor *sensor, u32 reg, u32 *val)
2357d2f8ddaSSakari Ailus {
2367d2f8ddaSSakari Ailus 	return ccs_read_addr_raw(sensor, reg, val, false, true, false);
237b24cc2a1SSakari Ailus }
238b24cc2a1SSakari Ailus 
239b24cc2a1SSakari Ailus int ccs_write_addr_no_quirk(struct ccs_sensor *sensor, u32 reg, u32 val)
240b24cc2a1SSakari Ailus {
241b24cc2a1SSakari Ailus 	struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
242b24cc2a1SSakari Ailus 	struct i2c_msg msg;
243b24cc2a1SSakari Ailus 	unsigned char data[6];
244b24cc2a1SSakari Ailus 	unsigned int retries;
245b24cc2a1SSakari Ailus 	unsigned int len = ccs_reg_width(reg);
246b24cc2a1SSakari Ailus 	int r;
247b24cc2a1SSakari Ailus 
248b24cc2a1SSakari Ailus 	if (len > sizeof(data) - 2)
249b24cc2a1SSakari Ailus 		return -EINVAL;
250b24cc2a1SSakari Ailus 
251b24cc2a1SSakari Ailus 	msg.addr = client->addr;
252b24cc2a1SSakari Ailus 	msg.flags = 0; /* Write */
253b24cc2a1SSakari Ailus 	msg.len = 2 + len;
254b24cc2a1SSakari Ailus 	msg.buf = data;
255b24cc2a1SSakari Ailus 
256b24cc2a1SSakari Ailus 	put_unaligned_be16(CCS_REG_ADDR(reg), data);
257b24cc2a1SSakari Ailus 	put_unaligned_be32(val << (8 * (sizeof(val) - len)), data + 2);
258b24cc2a1SSakari Ailus 
259b24cc2a1SSakari Ailus 	for (retries = 0; retries < 5; retries++) {
260b24cc2a1SSakari Ailus 		/*
261b24cc2a1SSakari Ailus 		 * Due to unknown reason sensor stops responding. This
262b24cc2a1SSakari Ailus 		 * loop is a temporaty solution until the root cause
263b24cc2a1SSakari Ailus 		 * is found.
264b24cc2a1SSakari Ailus 		 */
265b24cc2a1SSakari Ailus 		r = i2c_transfer(client->adapter, &msg, 1);
266b24cc2a1SSakari Ailus 		if (r == 1) {
267b24cc2a1SSakari Ailus 			if (retries)
268b24cc2a1SSakari Ailus 				dev_err(&client->dev,
269b24cc2a1SSakari Ailus 					"sensor i2c stall encountered. retries: %d\n",
270b24cc2a1SSakari Ailus 					retries);
271b24cc2a1SSakari Ailus 			return 0;
272b24cc2a1SSakari Ailus 		}
273b24cc2a1SSakari Ailus 
274b24cc2a1SSakari Ailus 		usleep_range(2000, 2000);
275b24cc2a1SSakari Ailus 	}
276b24cc2a1SSakari Ailus 
277b24cc2a1SSakari Ailus 	dev_err(&client->dev,
278b24cc2a1SSakari Ailus 		"wrote 0x%x to offset 0x%x error %d\n", val,
279b24cc2a1SSakari Ailus 		CCS_REG_ADDR(reg), r);
280b24cc2a1SSakari Ailus 
281b24cc2a1SSakari Ailus 	return r;
282b24cc2a1SSakari Ailus }
283b24cc2a1SSakari Ailus 
284b24cc2a1SSakari Ailus /*
285b24cc2a1SSakari Ailus  * Write to a 8/16-bit register.
286b24cc2a1SSakari Ailus  * Returns zero if successful, or non-zero otherwise.
287b24cc2a1SSakari Ailus  */
288b24cc2a1SSakari Ailus int ccs_write_addr(struct ccs_sensor *sensor, u32 reg, u32 val)
289b24cc2a1SSakari Ailus {
290b24cc2a1SSakari Ailus 	int rval;
291b24cc2a1SSakari Ailus 
292b24cc2a1SSakari Ailus 	rval = ccs_call_quirk(sensor, reg_access, true, &reg, &val);
293b24cc2a1SSakari Ailus 	if (rval == -ENOIOCTLCMD)
294b24cc2a1SSakari Ailus 		return 0;
295b24cc2a1SSakari Ailus 	if (rval < 0)
296b24cc2a1SSakari Ailus 		return rval;
297b24cc2a1SSakari Ailus 
298b24cc2a1SSakari Ailus 	return ccs_write_addr_no_quirk(sensor, reg, val);
299b24cc2a1SSakari Ailus }
300