1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2025-08-04 15:30:24 +00:00
Files
physwizz 99537be4e2 first
2024-03-11 06:53:12 +11:00

461 lines
7.9 KiB
C

// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 MediaTek Inc.
#include <linux/i2c.h>
#include <linux/slab.h>
#include "adaptor-i2c.h"
#define MAX_BUF_SIZE 255
#define MAX_MSG_NUM_U8 (MAX_BUF_SIZE / 3)
#define MAX_MSG_NUM_U16 (MAX_BUF_SIZE / 4)
#define MAX_VAL_NUM_U8 (MAX_BUF_SIZE - 2)
#define MAX_VAL_NUM_U16 ((MAX_BUF_SIZE - 2) >> 1)
struct cache_wr_regs_u8 {
u8 buf[MAX_BUF_SIZE];
struct i2c_msg msg[MAX_MSG_NUM_U8];
};
struct cache_wr_regs_u16 {
u8 buf[MAX_BUF_SIZE];
struct i2c_msg msg[MAX_MSG_NUM_U16];
};
int adaptor_i2c_rd_u8(struct i2c_client *i2c_client,
u16 addr, u16 reg, u8 *val)
{
int ret;
u8 buf[2];
struct i2c_msg msg[2];
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
msg[0].addr = addr;
msg[0].flags = i2c_client->flags;
msg[0].buf = buf;
msg[0].len = sizeof(buf);
msg[1].addr = addr;
msg[1].flags = i2c_client->flags | I2C_M_RD;
msg[1].buf = buf;
msg[1].len = 1;
ret = i2c_transfer(i2c_client->adapter, msg, 2);
if (ret < 0) {
dev_info(&i2c_client->dev, "i2c transfer failed (%d)\n", ret);
return ret;
}
*val = buf[0];
return 0;
}
int adaptor_i2c_rd_u16(struct i2c_client *i2c_client,
u16 addr, u16 reg, u16 *val)
{
int ret;
u8 buf[2];
struct i2c_msg msg[2];
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
msg[0].addr = addr;
msg[0].flags = i2c_client->flags;
msg[0].buf = buf;
msg[0].len = sizeof(buf);
msg[1].addr = addr;
msg[1].flags = i2c_client->flags | I2C_M_RD;
msg[1].buf = buf;
msg[1].len = 2;
ret = i2c_transfer(i2c_client->adapter, msg, 2);
if (ret < 0) {
dev_info(&i2c_client->dev, "i2c transfer failed (%d)\n", ret);
return ret;
}
*val = ((u16)buf[0] << 8) | buf[1];
return 0;
}
int adaptor_i2c_rd_p8(struct i2c_client *i2c_client,
u16 addr, u16 reg, u8 *p_vals, u32 n_vals)
{
int ret, cnt, total, recv, reg_b;
u8 buf[2];
struct i2c_msg msg[2];
u8 *pbuf;
recv = 0;
total = n_vals;
pbuf = p_vals;
reg_b = reg;
msg[0].addr = addr;
msg[0].flags = i2c_client->flags;
msg[0].buf = buf;
msg[0].len = sizeof(buf);
msg[1].addr = addr;
msg[1].flags = i2c_client->flags | I2C_M_RD;
while (recv < total) {
cnt = total - recv;
if (cnt > MAX_VAL_NUM_U8)
cnt = MAX_VAL_NUM_U8;
buf[0] = reg_b >> 8;
buf[1] = reg_b & 0xff;
msg[1].buf = pbuf;
msg[1].len = cnt;
ret = i2c_transfer(i2c_client->adapter, msg, 2);
if (ret < 0) {
dev_info(&i2c_client->dev,
"i2c transfer failed (%d)\n", ret);
return -EIO;
}
pbuf += cnt;
recv += cnt;
reg_b += cnt;
}
return ret;
}
int adaptor_i2c_wr_u8(struct i2c_client *i2c_client,
u16 addr, u16 reg, u8 val)
{
int ret;
u8 buf[3];
struct i2c_msg msg;
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
buf[2] = val;
msg.addr = addr;
msg.flags = i2c_client->flags;
msg.buf = buf;
msg.len = sizeof(buf);
ret = i2c_transfer(i2c_client->adapter, &msg, 1);
if (ret < 0)
dev_info(&i2c_client->dev, "i2c transfer failed (%d)\n", ret);
return ret;
}
int adaptor_i2c_wr_u16(struct i2c_client *i2c_client,
u16 addr, u16 reg, u16 val)
{
int ret;
u8 buf[4];
struct i2c_msg msg;
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
buf[2] = val >> 8;
buf[3] = val & 0xff;
msg.addr = addr;
msg.flags = i2c_client->flags;
msg.buf = buf;
msg.len = sizeof(buf);
ret = i2c_transfer(i2c_client->adapter, &msg, 1);
if (ret < 0)
dev_info(&i2c_client->dev, "i2c transfer failed (%d)\n", ret);
return ret;
}
int adaptor_i2c_wr_p8(struct i2c_client *i2c_client,
u16 addr, u16 reg, u8 *p_vals, u32 n_vals)
{
u8 *buf, *pbuf, *pdata;
struct i2c_msg msg;
int ret, sent, total, cnt;
buf = kmalloc(MAX_BUF_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
sent = 0;
total = n_vals;
pdata = p_vals;
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
msg.addr = addr;
msg.flags = i2c_client->flags;
msg.buf = buf;
while (sent < total) {
cnt = total - sent;
if (cnt > MAX_VAL_NUM_U8)
cnt = MAX_VAL_NUM_U8;
pbuf = buf + 2;
memcpy(pbuf, pdata, cnt);
msg.len = 2 + cnt;
ret = i2c_transfer(i2c_client->adapter, &msg, 1);
if (ret < 0) {
dev_info(&i2c_client->dev,
"i2c transfer failed (%d)\n", ret);
kfree(buf);
return -EIO;
}
sent += cnt;
pdata += cnt;
}
kfree(buf);
return 0;
}
int adaptor_i2c_wr_p16(struct i2c_client *i2c_client,
u16 addr, u16 reg, u16 *p_vals, u32 n_vals)
{
u8 *buf, *pbuf;
u16 *pdata;
struct i2c_msg msg;
int i, ret, sent, total, cnt;
buf = kmalloc(MAX_BUF_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
sent = 0;
total = n_vals;
pdata = p_vals;
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
msg.addr = addr;
msg.flags = i2c_client->flags;
msg.buf = buf;
while (sent < total) {
cnt = total - sent;
if (cnt > MAX_VAL_NUM_U16)
cnt = MAX_VAL_NUM_U16;
pbuf = buf + 2;
for (i = 0; i < cnt; i++) {
pbuf[0] = pdata[0] >> 8;
pbuf[1] = pdata[0] & 0xff;
pdata++;
pbuf += 2;
}
msg.len = 2 + (cnt << 1);
ret = i2c_transfer(i2c_client->adapter, &msg, 1);
if (ret < 0) {
dev_info(&i2c_client->dev,
"i2c transfer failed (%d)\n", ret);
kfree(buf);
return -EIO;
}
sent += cnt;
}
kfree(buf);
return 0;
}
int adaptor_i2c_wr_seq_p8(struct i2c_client *i2c_client,
u16 addr, u16 reg, u8 *p_vals, u32 n_vals)
{
u8 *buf, *pbuf, *pdata;
struct i2c_msg msg;
int ret, sent, total, cnt;
buf = kmalloc(MAX_BUF_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
sent = 0;
total = n_vals;
pdata = p_vals;
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
msg.addr = addr;
msg.flags = i2c_client->flags;
msg.buf = buf;
while (sent < total) {
cnt = total - sent;
if (cnt > MAX_VAL_NUM_U8)
cnt = MAX_VAL_NUM_U8;
buf[0] = reg >> 8;
buf[1] = reg & 0xff;
pbuf = buf + 2;
memcpy(pbuf, pdata, cnt);
msg.len = 2 + cnt;
ret = i2c_transfer(i2c_client->adapter, &msg, 1);
if (ret < 0) {
dev_info(&i2c_client->dev,
"i2c transfer failed (%d)\n", ret);
kfree(buf);
return -EIO;
}
sent += cnt;
pdata += cnt;
reg += cnt;
}
kfree(buf);
return 0;
}
int adaptor_i2c_wr_regs_u8(struct i2c_client *i2c_client,
u16 addr, u16 *list, u32 len)
{
struct cache_wr_regs_u8 *pmem;
struct i2c_msg *pmsg;
u8 *pbuf;
u16 *plist;
int i, ret, sent, total, cnt;
pmem = kmalloc(sizeof(*pmem), GFP_KERNEL);
if (!pmem)
return -ENOMEM;
/* each msg contains 3 bytes: addr(u16) + val(u8) */
sent = 0;
total = len >> 1;
plist = list;
while (sent < total) {
cnt = total - sent;
if (cnt > ARRAY_SIZE(pmem->msg))
cnt = ARRAY_SIZE(pmem->msg);
pbuf = pmem->buf;
pmsg = pmem->msg;
for (i = 0; i < cnt; i++) {
pbuf[0] = plist[0] >> 8;
pbuf[1] = plist[0] & 0xff;
pbuf[2] = plist[1] & 0xff;
pmsg->addr = addr;
pmsg->flags = i2c_client->flags;
pmsg->len = 3;
pmsg->buf = pbuf;
plist += 2;
pbuf += 3;
pmsg++;
}
ret = i2c_transfer(i2c_client->adapter, pmem->msg, cnt);
if (ret != cnt) {
dev_info(&i2c_client->dev,
"i2c transfer failed (%d)\n", ret);
kfree(pmem);
return -EIO;
}
sent += cnt;
}
kfree(pmem);
return 0;
}
int adaptor_i2c_wr_regs_u16(struct i2c_client *i2c_client,
u16 addr, u16 *list, u32 len)
{
struct cache_wr_regs_u16 *pmem;
struct i2c_msg *pmsg;
u8 *pbuf;
u16 *plist;
int i, ret, sent, total, cnt;
pmem = kmalloc(sizeof(*pmem), GFP_KERNEL);
if (!pmem)
return -ENOMEM;
/* each msg contains 4 bytes: addr(u16) + val(u16) */
sent = 0;
total = len >> 1;
plist = list;
while (sent < total) {
cnt = total - sent;
if (cnt > ARRAY_SIZE(pmem->msg))
cnt = ARRAY_SIZE(pmem->msg);
pbuf = pmem->buf;
pmsg = pmem->msg;
for (i = 0; i < cnt; i++) {
pbuf[0] = plist[0] >> 8;
pbuf[1] = plist[0] & 0xff;
pbuf[2] = plist[1] >> 8;
pbuf[3] = plist[1] & 0xff;
pmsg->addr = addr;
pmsg->flags = i2c_client->flags;
pmsg->len = 4;
pmsg->buf = pbuf;
plist += 2;
pbuf += 4;
pmsg++;
}
ret = i2c_transfer(i2c_client->adapter, pmem->msg, cnt);
if (ret != cnt) {
dev_info(&i2c_client->dev,
"i2c transfer failed (%d)\n", ret);
kfree(pmem);
return -EIO;
}
sent += cnt;
}
kfree(pmem);
return 0;
}