141 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2021-2023 Digiteq Automotive4 * author: Martin Tuma <martin.tuma@digiteqautomotive.com>5 *6 * The i2c module unifies the I2C access to the serializes/deserializes. The I2C7 * chips on the GMSL module use 16b addressing, the FPDL3 chips use standard8 * 8b addressing.9 */10 11#include "mgb4_i2c.h"12 13static 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 else40 return 0;41}42 43static 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 else69 return 0;70}71 72int 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 84void mgb4_i2c_free(struct mgb4_i2c_client *client)85{86 i2c_unregister_device(client->client);87}88 89s32 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 104s32 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 else109 return write_r16(client->client, reg, &val, 1);110}111 112s32 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 126int 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