推广网站怎样做广州seo服务
sh366006.c
/* 谁愿压抑心中怒愤冲动咒骂这虚与伪与假从没信要屈膝面对生命纵没有别人帮一生只靠我双手让我放声疯狂叫囔今天的他 呼风可改雨不可一世太嚣张 --《不可一世》Beyond
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/workqueue.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/sizes.h>#define SHFG_ENABLE_LOG 1#define SH_PROPERTIES "sh366006-bat"#define SHFG_NAME "sh366006"#define sh_printk(fmt, arg...) \{ \if (SHFG_ENABLE_LOG) \printk(KERN_INFO "SH366006 : %s-%d : " fmt, __FUNCTION__ ,__LINE__,##arg); \else {} \}#define queue_delayed_work_time 1000
#define queue_start_work_time 50#define SH366006_SMBUS_ADDR 0x16
#define SH366006_MANUFACTURER_DATA 0x07static const uint8_t crc8_table[256] ={0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d,0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d,0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd,0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea,0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a,0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a,0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4,0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44,0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63,0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13,0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3};/* 完整的SBS Command Codes (0x00-0x3F) */
enum sh366006_commands {MANUFACTURER_ACCESS = 0x00, // 制造商访问DEVICE_TYPE = 0x01, // 设备类型REMAINING_CAPACITY = 0x0F, // 剩余容量(mAh)VOLTAGE = 0x09, // 电池电压(mV)CURRENT = 0x0A, // 实时电流(mA)AVERAGE_CURRENT = 0x0B, // 平均电流(mA)RELATIVE_SOC = 0x0D, // 相对电量百分比(%)ABSOLUTE_SOC = 0x0E, // 绝对电量百分比(%)HEALTHY_SOC = 0x4F, // 电池健康度TEMPERATURE = 0x08, // 温度(0.1K)FULL_CHARGE_CAPACITY = 0x10, // 满电容量BATTERY_STATUS = 0x16, // 电池状态字CYCLE_COUNT = 0x17, // 循环次数DESIGN_CAPACITY = 0x18, // 设计容量(mAh)DESIGN_VOLTAGE = 0x19, // 标称电压(mV)SPECIFICATION_INFO = 0x1A, // 规格信息MANUFACTURE_DATE = 0x1B, // 生产日期SERIAL_NUMBER = 0x1C, // 序列号CELL_VOLTAGE_1 = 0x3C, // 第1节电压(mV)CELL_VOLTAGE_2 = 0x3D, // 第2节电压(mV)CELL_VOLTAGE_3 = 0x3E, // 第3节电压(mV)CELL_VOLTAGE_4 = 0x3F, // 第4节电压(mV)// 安全扩展命令(0x20-0x2F)SAFETY_STATUS = 0x20, // 安全状态寄存器SAFETY_ALERT = 0x21, // 安全警报阈值SAFETY_STATUS_EXT = 0x22, // 扩展安全状态CHG_VOLTAGE = 0x30, // 充电电压设置(mV)CHG_CURRENT = 0x31, // 充电电流设置(mA)DISCHG_CURRENT = 0x39, // 放电电流限制(mA)// 制造商专用命令(0x40-0x5F)QMAX_UPDATE = 0x41, // Qmax校准命令BALANCE_CONTROL = 0x42, // 电池均衡控制JEITA_CONTROL = 0x43, // JEITA温度补偿SHA1_AUTH = 0x44, // SHA-1认证CELL_TEMP_1 = 0x50, // 第1节温度CELL_TEMP_2 = 0x51, // 第2节温度// 时间预测命令REMAINING_TIME = 0x11, // 剩余使用时间(min)AVG_TIME_TO_EMPTY = 0x12, // 平均耗尽时间AVG_TIME_TO_FULL = 0x13, // 平均充满时间
};struct sh36606_chip {struct i2c_client *client;struct workqueue_struct *shfg_workqueue;struct delayed_work monitor_work;#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)struct power_supply sh_bat;
#elsestruct power_supply *sh_bat;
#endifint battery_temp;int voltage;int soc;int battery_current;int cycle_count;int battery_healthy;int status;
};static int sh_read_reg(struct i2c_client *client, u8 reg, u8 *buf, int len)
{struct i2c_msg msgs[2] = {{.addr = client->addr,.flags = 0,.len = 1,.buf = ®,},{.addr = client->addr,.flags = I2C_M_RD,.len = len,.buf = buf,},};if (i2c_transfer(client->adapter, msgs, 2) != 2) {dev_err(&client->dev, "I2C read error\n");return -EIO;}return 0;
}static int sh_write_reg(struct i2c_client *client, u8 reg, u8 val)
{u8 buf[2] = {reg, val};struct i2c_msg msg = {.addr = client->addr,.flags = 0,.len = 2,.buf = buf,};if (i2c_transfer(client->adapter, &msg, 1) != 1) {dev_err(&client->dev, "I2C write error\n");return -EIO;}return 0;
}uint8_t crc8_check(uint8_t *data , uint16_t len)
{uint16_t i = 0;uint8_t fcs = 0;for(i=0 ; i<(len) ; i++){fcs = crc8_table[(uint8_t)fcs ^ (*data)];data++;}return fcs;
}/*读SBS命令,返回两个字节数据
ID :SBS命令号,只能是返回两个字节的子命令
value:返回的两字节数据组成的16bit数据*/
int SH366100_Read_SBS_Word(struct i2c_client *client, uint8_t reg, uint16_t* val)
{uint8_t address = 0x16;uint8_t recieve_data[6] = {0x00};uint8_t crc_check = 0x00;recieve_data[0] = address;recieve_data[1] = reg;recieve_data[2] = address | 0x01;if(0 != sh_read_reg( client, reg, recieve_data+3, 3) ){*val = 0;return -1;}else{crc_check = crc8_check(recieve_data , 5);if(crc_check == recieve_data[5] ){*val = recieve_data[3] + (((uint16_t)recieve_data[4])<<8);return 0;}else{*val = 0;return -1;}}
}static int sh366006_get_voltage(struct sh36606_chip *sh_chip)
{int ret;uint16_t reg_val[2] = {0, 0};unsigned int voltage;ret = SH366100_Read_SBS_Word(sh_chip->client, VOLTAGE, reg_val);if(ret <0 ) {sh_chip->voltage = 3000;return ret;}voltage = reg_val[0];sh_chip->voltage = voltage;return 0;
}static int sh366006_get_cycle_count(struct sh36606_chip *sh_chip)
{int ret;uint16_t reg_val[2] = {0, 0};unsigned int cycle_count;ret = SH366100_Read_SBS_Word(sh_chip->client, CYCLE_COUNT, reg_val);if(ret <0 ) {sh_chip->cycle_count = 1;return ret;}cycle_count = reg_val[0];sh_chip->cycle_count = cycle_count;return 0;
}static int sh366006_get_current(struct sh36606_chip *sh_chip)
{int ret;uint16_t reg_val[2] = {0, 0};unsigned int battery_current;ret = SH366100_Read_SBS_Word(sh_chip->client, AVERAGE_CURRENT, reg_val);if(ret <0 ) {sh_chip->battery_current = 65284;return ret;}battery_current = reg_val[0];sh_chip->battery_current = battery_current;return 0;
}static int sh366006_get_soc(struct sh36606_chip *sh_chip)
{int ret;uint16_t reg_val[2] = {0, 0};unsigned int soc;ret = SH366100_Read_SBS_Word(sh_chip->client, RELATIVE_SOC, reg_val);if(ret <0 ) {sh_chip->soc = 1;return ret;}soc = reg_val[0] ;sh_chip->soc = soc;return 0;
}static int sh366006_get_temperature(struct sh36606_chip *sh_chip)
{int ret;unsigned char reg_val[2] = {0, 0};unsigned int temperature;ret = SH366100_Read_SBS_Word(sh_chip->client, TEMPERATURE, reg_val);if(ret <0 ) {sh_chip->battery_temp = 26;return ret;}temperature = reg_val[0] ;sh_chip->battery_temp = temperature;return 0;
}static int sh366006_get_battery_healthy(struct sh36606_chip *sh_chip)
{int ret;unsigned char reg_val[2] = {0, 0};unsigned int healthy;ret = SH366100_Read_SBS_Word(sh_chip->client, HEALTHY_SOC, reg_val);if(ret <0 ) {sh_chip->battery_healthy = 2;return ret;}healthy = reg_val[0] ;sh_chip->battery_healthy = healthy;return 0;
}static int sh_init_data(struct sh36606_chip *sh_chip)
{int ret = 0;u16 device_type;/* 验证芯片ID */ret = SH366100_Read_SBS_Word(sh_chip->client, DEVICE_TYPE, &device_type);if (ret != 0 || device_type != 410) {dev_err(&sh_chip->client->dev, "Invalid chip ID: 0x%02X\n", device_type);sh_chip->battery_temp = 26;sh_chip->voltage = 3000;sh_chip->soc = 50;sh_chip->battery_current = 65284;sh_chip->cycle_count = 1;sh_chip->battery_healthy = 2;sh_chip->status = POWER_SUPPLY_STATUS_CHARGING;return -1;} else {sh_printk("check ok\r\n");}ret += sh366006_get_voltage(sh_chip);ret += sh366006_get_current(sh_chip);ret += sh366006_get_soc(sh_chip);ret += sh366006_get_temperature(sh_chip);ret += sh366006_get_cycle_count(sh_chip);ret += sh366006_get_battery_healthy(sh_chip);sh_chip->status = POWER_SUPPLY_STATUS_DISCHARGING;sh_printk("voltage : %d, current : %d, soc : %d, temperature : %d, cycle_count:%d, battery_healthy:%d ,ret : %d \n",\sh_chip->voltage, sh_chip->battery_current, sh_chip->soc, sh_chip->battery_temp, sh_chip->cycle_count, sh_chip->battery_healthy, ret);return ret;
}/*
定期循环的工作队列
*/
static void sh366006_monitor_work(struct work_struct *work)
{struct delayed_work *delay_work;struct sh36606_chip *sh_chip;int ret;delay_work = container_of(work, struct delayed_work, work);sh_chip = container_of(delay_work, struct sh36606_chip, monitor_work);ret += sh366006_get_voltage(sh_chip);ret += sh366006_get_current(sh_chip);ret += sh366006_get_soc(sh_chip);ret += sh366006_get_temperature(sh_chip);ret += sh366006_get_cycle_count(sh_chip);ret += sh366006_get_battery_healthy(sh_chip);sh_printk("voltage : %d, current : %d, soc : %d, temperature : %d, cycle_count:%d, battery_healthy:%d ,ret : %d \n",\sh_chip->voltage, sh_chip->battery_current, sh_chip->soc, sh_chip->battery_temp, sh_chip->cycle_count, sh_chip->battery_healthy, ret);//向Android系统上报电池参数
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)power_supply_changed(&sh_chip->sh_bat);
#elsepower_supply_changed(sh_chip->sh_bat);
#endifqueue_delayed_work(sh_chip->shfg_workqueue, &sh_chip->monitor_work, msecs_to_jiffies(queue_delayed_work_time));
}static int sh_battery_set_property(struct power_supply *psy,enum power_supply_property psp,const union power_supply_propval *val)
{int ret = 0;#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)struct sh36606_chip *sh_bat;sh_bat = container_of(psy, struct sh36606_chip, sh_bat); #elsestruct sh36606_chip *sh_bat = power_supply_get_drvdata(psy); #endifswitch(psp) {default:ret = -EINVAL; break; }return ret;
}static int sh_get_capacity_level(struct sh36606_chip *sh_bat)
{if (sh_bat->soc < 1)return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;else if (sh_bat->soc <= 20)return POWER_SUPPLY_CAPACITY_LEVEL_LOW;else if (sh_bat->soc <= 70)return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;else if (sh_bat->soc <= 90)return POWER_SUPPLY_CAPACITY_LEVEL_HIGH;elsereturn POWER_SUPPLY_CAPACITY_LEVEL_FULL;
}static int sh_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val)
{int ret = 0;#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)struct sh36606_chip *sh_bat;sh_bat = container_of(psy, struct sh36606_chip, sh_bat);
#elsestruct sh36606_chip *sh_bat = power_supply_get_drvdata(psy);
#endif switch(psp) {case POWER_SUPPLY_PROP_CYCLE_COUNT:val->intval = sh_bat->cycle_count;break;case POWER_SUPPLY_PROP_CAPACITY:val->intval = sh_bat->soc;break;case POWER_SUPPLY_PROP_PRESENT:val->intval = sh_bat->voltage <= 0 ? 0 : 1;break; case POWER_SUPPLY_PROP_VOLTAGE_NOW:val->intval = sh_bat->voltage;break;case POWER_SUPPLY_PROP_CURRENT_NOW:val->intval = sh_bat->battery_current;break;case POWER_SUPPLY_PROP_TEMP: val->intval = 250;break;case POWER_SUPPLY_PROP_HEALTH: val->intval = POWER_SUPPLY_HEALTH_GOOD;break;case POWER_SUPPLY_PROP_TECHNOLOGY:val->intval = POWER_SUPPLY_TECHNOLOGY_LION;break;case POWER_SUPPLY_PROP_CAPACITY_LEVEL:val->intval = sh_get_capacity_level(sh_bat);break;case POWER_SUPPLY_PROP_STATUS:val->intval = sh_bat->status;break;default:ret = -EINVAL; break;} return ret;
}static enum power_supply_property sh_battery_properties[] = {POWER_SUPPLY_PROP_CYCLE_COUNT,POWER_SUPPLY_PROP_TEMP,POWER_SUPPLY_PROP_CAPACITY,POWER_SUPPLY_PROP_PRESENT,POWER_SUPPLY_PROP_VOLTAGE_NOW,POWER_SUPPLY_PROP_CURRENT_NOW,POWER_SUPPLY_PROP_HEALTH,POWER_SUPPLY_PROP_TECHNOLOGY,POWER_SUPPLY_PROP_CAPACITY_LEVEL,POWER_SUPPLY_PROP_STATUS,
};static int sh366006_probe(struct i2c_client *client, const struct i2c_device_id *id)
{int ret;static struct sh36606_chip *sh_bat;struct power_supply_desc *psy_desc;struct power_supply_config psy_cfg = {0};sh_printk("\n");sh_bat = devm_kzalloc(&client->dev, sizeof(*sh_bat), GFP_KERNEL);if (!sh_bat) {sh_printk("%s : sh_bat create fail!\n", __func__);return -ENOMEM;}// sh_printk("fuck 1\n");i2c_set_clientdata(client, sh_bat);sh_bat->client = client;// sh_printk("fuck 2.5\n");ret = sh_init_data(sh_bat);if (ret < 0) {sh_printk(" sh_init_data fail!\n");// return ret;}#ifdef SH_PROPERTIES
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)sh_bat->sh_bat.name = SH_PROPERTIES;sh_bat->sh_bat.type = POWER_SUPPLY_TYPE_BATTERY;sh_bat->sh_bat.properties = sh_battery_properties;sh_bat->sh_bat.num_properties = ARRAY_SIZE(sh_battery_properties);sh_bat->sh_bat.get_property = sh_battery_get_property;sh_bat->sh_bat.set_property = sh_battery_set_property;ret = power_supply_register(&client->dev, &sh_bat->sh_bat);if (ret < 0) {power_supply_unregister(&sh_bat->sh_bat);sh_printk("failed to register battery: %d\n", ret);return ret;}// sh_printk("fuck 2.6\n");
#elsepsy_desc = devm_kzalloc(&client->dev, sizeof(*psy_desc), GFP_KERNEL);if (!psy_desc)return -ENOMEM;psy_cfg.drv_data = sh_bat;psy_desc->name = SH_PROPERTIES;psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;psy_desc->properties = sh_battery_properties;psy_desc->num_properties = ARRAY_SIZE(sh_battery_properties);psy_desc->get_property = sh_battery_get_property;psy_desc->set_property = sh_battery_set_property;sh_bat->sh_bat = power_supply_register(&client->dev, psy_desc, &psy_cfg);if (IS_ERR(sh_bat->sh_bat)) {ret = PTR_ERR(sh_bat->sh_bat);sh_printk("failed to register battery: %d\n", ret);return ret;}// sh_printk("fuck 2.7\n");
#endif
#endif
// sh_printk("fuck 3\n");sh_bat->shfg_workqueue = create_singlethread_workqueue("shfg_gauge");INIT_DELAYED_WORK(&sh_bat->monitor_work, sh366006_monitor_work);queue_delayed_work(sh_bat->shfg_workqueue, &sh_bat->monitor_work , msecs_to_jiffies(queue_start_work_time));// sh_printk("fuck 4\n");sh_printk("sh366006 driver probe success!\n");return 0;
}static int sh366006_remove(struct i2c_client *client)
{sh_printk("\n");return 0;
}static const struct i2c_device_id sh366006_id_table[] = {{ SHFG_NAME, 0 },{ }
};static struct of_device_id sh366006_match_table[] = {{ .compatible = "shunwei,sh366006", },{ },
};static struct i2c_driver sh366006_driver = {.driver = {.name = SHFG_NAME,.owner = THIS_MODULE,.of_match_table = sh366006_match_table,},.probe = sh366006_probe,.remove = sh366006_remove,.id_table = sh366006_id_table,
};static int __init sh366006_init(void)
{sh_printk("\n");i2c_add_driver(&sh366006_driver);return 0;
}static void __exit sh366006_exit(void)
{i2c_del_driver(&sh366006_driver);
}module_init(sh366006_init);
module_exit(sh366006_exit);MODULE_AUTHOR("SRED Cole");
MODULE_DESCRIPTION("SH366006 Device Driver V0.1");
MODULE_LICENSE("GPL");
设备树
sh366006@0b {status = "okay";compatible = "shunwei,sh366006";reg = <0x0b>;};