1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2021-2023 Digiteq Automotive 4 * author: Martin Tuma <martin.tuma@digiteqautomotive.com> 5 * 6 * The i2c module unifies the I2C access to the serializes/deserializes. The I2C 7 * chips on the GMSL module use 16b addressing, the FPDL3 chips use standard 8 * 8b addressing. 9 */ 10 11 #include "mgb4_i2c.h" 12 13 static int read_r16(struct i2c_client *client, u16 reg, u8 *val, int len) 14 { 15 int ret; 16 u8 buf[2]; 17 struct i2c_msg msg[2] = { 18 { 19 .addr = client->addr, 20 .flags = 0, 21 .len = 2, 22 .buf = buf, 23 }, { 24 .addr = client->addr, 25 .flags = I2C_M_RD, 26 .len = len, 27 .buf = val, 28 } 29 }; 30 31 buf[0] = (reg >> 8) & 0xff; 32 buf[1] = (reg >> 0) & 0xff; 33 34 ret = i2c_transfer(client->adapter, msg, 2); 35 if (ret < 0) 36 return ret; 37 else if (ret != 2) 38 return -EREMOTEIO; 39 else 40 return 0; 41 } 42 43 static int write_r16(struct i2c_client *client, u16 reg, const u8 *val, int len) 44 { 45 int ret; 46 u8 buf[4]; 47 struct i2c_msg msg[1] = { 48 { 49 .addr = client->addr, 50 .flags = 0, 51 .len = 2 + len, 52 .buf = buf, 53 } 54 }; 55 56 if (2 + len > sizeof(buf)) 57 return -EINVAL; 58 59 buf[0] = (reg >> 8) & 0xff; 60 buf[1] = (reg >> 0) & 0xff; 61 memcpy(&buf[2], val, len); 62 63 ret = i2c_transfer(client->adapter, msg, 1); 64 if (ret < 0) 65 return ret; 66 else if (ret != 1) 67 return -EREMOTEIO; 68 else 69 return 0; 70 } 71 72 int mgb4_i2c_init(struct mgb4_i2c_client *client, struct i2c_adapter *adap, 73 struct i2c_board_info const *info, int addr_size) 74 { 75 client->client = i2c_new_client_device(adap, info); 76 if (IS_ERR(client->client)) 77 return PTR_ERR(client->client); 78 79 client->addr_size = addr_size; 80 81 return 0; 82 } 83 84 void mgb4_i2c_free(struct mgb4_i2c_client *client) 85 { 86 i2c_unregister_device(client->client); 87 } 88 89 s32 mgb4_i2c_read_byte(struct mgb4_i2c_client *client, u16 reg) 90 { 91 int ret; 92 u8 b; 93 94 if (client->addr_size == 8) 95 return i2c_smbus_read_byte_data(client->client, reg); 96 97 ret = read_r16(client->client, reg, &b, 1); 98 if (ret < 0) 99 return ret; 100 101 return (s32)b; 102 } 103 104 s32 mgb4_i2c_write_byte(struct mgb4_i2c_client *client, u16 reg, u8 val) 105 { 106 if (client->addr_size == 8) 107 return i2c_smbus_write_byte_data(client->client, reg, val); 108 else 109 return write_r16(client->client, reg, &val, 1); 110 } 111 112 s32 mgb4_i2c_mask_byte(struct mgb4_i2c_client *client, u16 reg, u8 mask, u8 val) 113 { 114 s32 ret; 115 116 if (mask != 0xFF) { 117 ret = mgb4_i2c_read_byte(client, reg); 118 if (ret < 0) 119 return ret; 120 val |= (u8)ret & ~mask; 121 } 122 123 return mgb4_i2c_write_byte(client, reg, val); 124 } 125 126 int mgb4_i2c_configure(struct mgb4_i2c_client *client, 127 const struct mgb4_i2c_kv *values, size_t count) 128 { 129 size_t i; 130 s32 res; 131 132 for (i = 0; i < count; i++) { 133 res = mgb4_i2c_mask_byte(client, values[i].reg, values[i].mask, 134 values[i].val); 135 if (res < 0) 136 return res; 137 } 138 139 return 0; 140 } 141