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, &reg_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";
};
posted @ 2026-05-19 17:55  Jax_Supersong  阅读(8)  评论(0)    收藏  举报