SM5341MP 的Linux驱动分享
SM5341MP的Linux驱动分享
驱动代码分享
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/printk.h>
#include <linux/io.h>
#include "SM5341-RevA-Registers.h"
#define SM5341_DEVICE_ADDR 0x74
#define MAX_RETRIES 3
#define sm5341mp_INFO(fmt, args...) \
dev_info(&client->dev, "[INFO] " fmt, ##args)
struct sm5341_data {
struct i2c_client *client;
int current_page;
};
static int sm5341_reg_write(struct sm5341_data *data, u16 addr, u8 value, int retry_count)
{
u8 page_addr = (addr >> 8) & 0xff;
u8 reg_addr = addr & 0xff;
u8 buf[2];
int ret;
int retry;
for (retry = 0; retry <= retry_count; retry++) {
if (data->current_page != page_addr) {
buf[0] = 0x01;
buf[1] = page_addr;
ret = i2c_master_send(data->client, buf, 2);
if (ret < 0) {
if (retry == retry_count) {
return ret;
}
msleep(10);
continue;
}
data->current_page = page_addr;
usleep_range(100, 200);
}
buf[0] = reg_addr;
buf[1] = value;
ret = i2c_master_send(data->client, buf, 2);
if (ret >= 0) {
usleep_range(100, 200);
return 0;
}
if (retry == retry_count) {
return ret;
}
msleep(10);
data->current_page = -1;
}
return -EIO;
}
static int sm5341_reg_read(struct sm5341_data *data, u16 addr, u8 *value, int retry_count)
{
u8 page_addr = (addr >> 8) & 0xff;
u8 reg_addr = addr & 0xff;
int ret;
int retry;
for (retry = 0; retry <= retry_count; retry++) {
if (data->current_page != page_addr) {
u8 buf[2] = {0x01, page_addr};
ret = i2c_master_send(data->client, buf, 2);
if (ret < 0) {
if (retry == retry_count) {
return ret;
}
msleep(10);
continue;
}
data->current_page = page_addr;
usleep_range(100, 200);
}
ret = i2c_master_send(data->client, ®_addr, 1);
if (ret < 0) {
if (retry == retry_count) return ret;
msleep(10);
continue;
}
ret = i2c_master_recv(data->client, value, 1);
if (ret >= 0) return 0;
if (retry == retry_count) return ret;
msleep(10);
data->current_page = -1;
}
return -EIO;
}
static int sm5341_check_device(struct i2c_client *client)
{
u8 test_value;
int ret;
struct i2c_msg msg[2];
u8 test_reg = 0x00;
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = 1;
msg[0].buf = &test_reg;
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
msg[1].len = 1;
msg[1].buf = &test_value;
ret = i2c_transfer(client->adapter, msg, 2);
if (ret < 0) {
return -ENODEV;
}
return 0;
}
static int sm5341_reg_config(struct sm5341_data *data)
{
int ret;
u16 reg_index;
int error_count = 0;
struct i2c_client *client = data->client;
for (reg_index = 0; reg_index < SM5341_REVA_REG_CONFIG_NUM_REGS; reg_index++) {
ret = sm5341_reg_write(data,
sm5341_reva_registers[reg_index].address,
sm5341_reva_registers[reg_index].value,
2);
if (ret < 0) {
sm5341mp_INFO("Failed to write register 0x%04x at index %d\n",
sm5341_reva_registers[reg_index].address, reg_index);
error_count++;
if (error_count > 5) {
return ret;
}
data->current_page = -1;
msleep(50);
continue;
}
}
ret = sm5341_reg_write(data,
sm5341_step1_registers.address,
sm5341_step1_registers.value, 3);
if (ret < 0) return ret;
ret = sm5341_reg_write(data,
sm5341_step2_registers.address,
sm5341_step2_registers.value, 3);
if (ret < 0) return ret;
msleep(150);
ret = sm5341_reg_write(data,
sm5341_step3_registers.address,
sm5341_step3_registers.value, 3);
if (ret < 0) return ret;
usleep_range(200, 300);
ret = sm5341_reg_write(data,
sm5341_step4_registers.address,
sm5341_step4_registers.value, 3);
if (ret < 0) return ret;
return 0;
}
static void sm5341_hw_reset(void)
{
void __iomem *addr;
addr = ioremap(0x445818c, 4);
if (addr) {
iowrite32(0x337, addr);
iounmap(addr);
}
}
static int sm5341_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct sm5341_data *data;
int ret;
u8 id_low, id_high;
sm5341_hw_reset();
mdelay(100);
sm5341mp_INFO("SM5341 probe started\n");
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
return -EIO;
}
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->client = client;
data->current_page = -1;
i2c_set_clientdata(client, data);
ret = sm5341_check_device(client);
if (ret < 0) {
sm5341mp_INFO("Device not detected\n");
return -ENODEV;
}
ret = sm5341_reg_config(data);
if (ret < 0) {
sm5341mp_INFO("Register configuration failed\n");
return ret;
}
sm5341_reg_read(data, 0x0002, &id_low, 2);
sm5341_reg_read(data, 0x0003, &id_high, 2);
sm5341mp_INFO("Chip ID = 0x%02x%02x\n", id_high, id_low);
sm5341mp_INFO("Probe done\n");
return 0;
}
static int sm5341_remove(struct i2c_client *client)
{
sm5341mp_INFO("Driver removed\n");
return 0;
}
static const struct i2c_device_id sm5341_id[] = {
{ "sm5341mp", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, sm5341_id);
static const struct of_device_id sm5341_of_match[] = {
{ .compatible = "sm,sm5341mp", },
{ }
};
MODULE_DEVICE_TABLE(of, sm5341_of_match);
static struct i2c_driver sm5341_driver = {
.driver = {
.name = "sm5341",
.of_match_table = sm5341_of_match,
},
.probe = sm5341_probe,
.remove = sm5341_remove,
.id_table = sm5341_id,
};
module_i2c_driver(sm5341_driver);
MODULE_DESCRIPTION("SM5341MP I2C Driver");
MODULE_AUTHOR("Jax");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");
设备树分享
sm5341mp@74 {
compatible = "sm,sm5341mp";
reg = <0x74>; /* I2C 7位地址 */
status = "okay";
};

浙公网安备 33010602011771号