Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: v4l2-cci: Add support for little-endian encoded registers

Some sensors, e.g. Sony IMX290, are using little-endian registers. Add
support for those by encoding the endianness into Bit 20 of the register
address.

Fixes: af73323b9770 ("media: imx290: Convert to new CCI register access helpers")
Cc: stable@vger.kernel.org
Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
[Sakari Ailus: Fixed commit message.]
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>

authored by

Alexander Stein and committed by
Hans Verkuil
d92e7a01 1545c2b9

+41 -8
+36 -8
drivers/media/v4l2-core/v4l2-cci.c
··· 18 18 19 19 int cci_read(struct regmap *map, u32 reg, u64 *val, int *err) 20 20 { 21 + bool little_endian; 21 22 unsigned int len; 22 23 u8 buf[8]; 23 24 int ret; ··· 26 25 if (err && *err) 27 26 return *err; 28 27 28 + little_endian = reg & CCI_REG_LE; 29 29 len = CCI_REG_WIDTH_BYTES(reg); 30 30 reg = CCI_REG_ADDR(reg); 31 31 ··· 42 40 *val = buf[0]; 43 41 break; 44 42 case 2: 45 - *val = get_unaligned_be16(buf); 43 + if (little_endian) 44 + *val = get_unaligned_le16(buf); 45 + else 46 + *val = get_unaligned_be16(buf); 46 47 break; 47 48 case 3: 48 - *val = get_unaligned_be24(buf); 49 + if (little_endian) 50 + *val = get_unaligned_le24(buf); 51 + else 52 + *val = get_unaligned_be24(buf); 49 53 break; 50 54 case 4: 51 - *val = get_unaligned_be32(buf); 55 + if (little_endian) 56 + *val = get_unaligned_le32(buf); 57 + else 58 + *val = get_unaligned_be32(buf); 52 59 break; 53 60 case 8: 54 - *val = get_unaligned_be64(buf); 61 + if (little_endian) 62 + *val = get_unaligned_le64(buf); 63 + else 64 + *val = get_unaligned_be64(buf); 55 65 break; 56 66 default: 57 67 dev_err(regmap_get_device(map), "Error invalid reg-width %u for reg 0x%04x\n", ··· 82 68 83 69 int cci_write(struct regmap *map, u32 reg, u64 val, int *err) 84 70 { 71 + bool little_endian; 85 72 unsigned int len; 86 73 u8 buf[8]; 87 74 int ret; ··· 90 75 if (err && *err) 91 76 return *err; 92 77 78 + little_endian = reg & CCI_REG_LE; 93 79 len = CCI_REG_WIDTH_BYTES(reg); 94 80 reg = CCI_REG_ADDR(reg); 95 81 ··· 99 83 buf[0] = val; 100 84 break; 101 85 case 2: 102 - put_unaligned_be16(val, buf); 86 + if (little_endian) 87 + put_unaligned_le16(val, buf); 88 + else 89 + put_unaligned_be16(val, buf); 103 90 break; 104 91 case 3: 105 - put_unaligned_be24(val, buf); 92 + if (little_endian) 93 + put_unaligned_le24(val, buf); 94 + else 95 + put_unaligned_be24(val, buf); 106 96 break; 107 97 case 4: 108 - put_unaligned_be32(val, buf); 98 + if (little_endian) 99 + put_unaligned_le32(val, buf); 100 + else 101 + put_unaligned_be32(val, buf); 109 102 break; 110 103 case 8: 111 - put_unaligned_be64(val, buf); 104 + if (little_endian) 105 + put_unaligned_le64(val, buf); 106 + else 107 + put_unaligned_be64(val, buf); 112 108 break; 113 109 default: 114 110 dev_err(regmap_get_device(map), "Error invalid reg-width %u for reg 0x%04x\n",
+5
include/media/v4l2-cci.h
··· 43 43 #define CCI_REG_WIDTH_BYTES(x) FIELD_GET(CCI_REG_WIDTH_MASK, x) 44 44 #define CCI_REG_WIDTH(x) (CCI_REG_WIDTH_BYTES(x) << 3) 45 45 #define CCI_REG_ADDR(x) FIELD_GET(CCI_REG_ADDR_MASK, x) 46 + #define CCI_REG_LE BIT(20) 46 47 47 48 #define CCI_REG8(x) ((1 << CCI_REG_WIDTH_SHIFT) | (x)) 48 49 #define CCI_REG16(x) ((2 << CCI_REG_WIDTH_SHIFT) | (x)) 49 50 #define CCI_REG24(x) ((3 << CCI_REG_WIDTH_SHIFT) | (x)) 50 51 #define CCI_REG32(x) ((4 << CCI_REG_WIDTH_SHIFT) | (x)) 51 52 #define CCI_REG64(x) ((8 << CCI_REG_WIDTH_SHIFT) | (x)) 53 + #define CCI_REG16_LE(x) (CCI_REG_LE | (2U << CCI_REG_WIDTH_SHIFT) | (x)) 54 + #define CCI_REG24_LE(x) (CCI_REG_LE | (3U << CCI_REG_WIDTH_SHIFT) | (x)) 55 + #define CCI_REG32_LE(x) (CCI_REG_LE | (4U << CCI_REG_WIDTH_SHIFT) | (x)) 56 + #define CCI_REG64_LE(x) (CCI_REG_LE | (8U << CCI_REG_WIDTH_SHIFT) | (x)) 52 57 53 58 /** 54 59 * cci_read() - Read a value from a single CCI register