123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454 |
- /*
- * Copyright (c) 2024 Wingcool Technology Co., Ltd
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- /**
- * @file
- * @brief SGM832A Timer driver for Actions SoC
- * typec_num: 0 for typec0, input/output; 1 for typec1, input
- */
- #include <errno.h>
- #include <kernel.h>
- #include <string.h>
- //#include <stdbool.h>
- #include <init.h>
- #include <irq.h>
- #include <drivers/adc.h>
- #include <drivers/input/input_dev.h>
- #include <sys/util.h>
- #include <sys/byteorder.h>
- #include <board.h>
- #include <soc_pmu.h>
- #include <logging/log.h>
- #include <device.h>
- #include <drivers/gpio.h>
- #include <soc.h>
- #include <string.h>
- #include <drivers/i2c.h>
- //#include <board_cfg.h>
- #include <drivers/uart.h>
- LOG_MODULE_REGISTER(sgm832a, CONFIG_SYS_LOG_INPUT_DEV_LEVEL);
- #define sgm832_typec0_slaver_addr (0x8A >> 1)
- #define sgm832_typec1_slaver_addr (0x82 >> 1)
- //sgm832 Register Address
- #define CONFIGURATION_REGISTER 0x00
- #define SHUNT_VOLTAGE_REGISTER 0x01
- #define BUS_VOLTAGE_REGISTER 0x02
- #define POWER_REGISTER 0x03
- #define CURRENT_REGISTER 0x04
- #define CALIBRATION_REGISTER 0x05
- #define MASK_ENABLE_REGISTER 0x06
- #define ALERT_LIMIT_REGISTER 0x07
- #define MANUFACTURER_ID_REGISTER 0xFE
- #define DIE_ID_REGISTER 0xFF
- //#ifndef CONFIG_MERGE_WORK_Q
- //#define CONFIG_USED_TP_WORK_QUEUE 0
- //#endif
- #ifdef CONFIG_USED_TP_WORK_QUEUE
- #define CONFIG_TIMER_WORK_Q_STACK_SIZE 1280
- struct k_work_q timer_drv_q;
- K_THREAD_STACK_DEFINE(timer_work_q_stack, CONFIG_TIMER_WORK_Q_STACK_SIZE);
- #endif
- struct acts_sgm_data {
- input_notify_t notify;
- const struct device *i2c_dev;
- const struct device *gpio_dev;
- const struct device *this_dev;
- struct gpio_callback key_gpio_cb;
- struct k_work init_timer;
- bool inited;
- #ifdef CONFIG_PM_DEVICE
- uint32_t pm_state;
- #endif
- };
- uint16_t sgm_crc[2] __attribute((used)) = {0};
- float f_ShuntVoltage[2] = {0.0}, f_BusVoltage[2] = {0.0}, f_Power[2] = {0.0}, f_Current[2] = {0.0};
- static struct acts_sgm_data sgm_acts_ddata;
- static void sgm832_typec_get_data(const struct device *i2c_dev, uint16_t sgm832_typec_slaver_addr, uint8_t typec_num);
- //static void sgm832_typec1_get_data(const struct device *i2c_dev);
- extern void uart2_poll_out_ch(int c);
- #include <drivers/hrtimer.h>
- #if 1
- static struct hrtimer g_sgm_ht_read;
- static void sgm832_acts_handler(struct k_work *work)
- {
- static struct acts_sgm_data *power_consumption = &sgm_acts_ddata;
- sgm832_typec_get_data(power_consumption->i2c_dev, sgm832_typec0_slaver_addr, 0); //不在ISR中完成,防止中断嵌套
- sgm832_typec_get_data(power_consumption->i2c_dev, sgm832_typec1_slaver_addr, 1); //不在ISR中完成,防止中断嵌套
- //sgm832_typec1_get_data(power_consumption->i2c_dev); //不在ISR中完成,防止中断嵌套
- }
- K_WORK_DEFINE(sgm832_acts, sgm832_acts_handler);
- static void htimer_fun(struct hrtimer *ttimer, void *expiry_fn_arg)
- {
- //static int t;
- //printk("%d ---htimer--\n", t++);
- k_work_submit(&sgm832_acts); //向系统工作队列提交一个工作项,让工作队列的线程将执行该工作
- }
- static void htimer_read(unsigned int ms)
- {
- hrtimer_init(&g_sgm_ht_read, htimer_fun, NULL);
- hrtimer_start(&g_sgm_ht_read, 1000*ms, 1000*ms);
- }
- #endif
- static void sgm832_typec_get_data(const struct device *i2c_dev, uint16_t sgm832_typec_slaver_addr, uint8_t typec_num)
- {
- #if 1
- //uint8_t i;
- //float f_ShuntVoltage = 0.0, f_BusVoltage = 0.0, f_Power = 0.0, f_Current = 0.0;
- //uint16_t u16_ShuntVoltage;
- static uint8_t write_cmd[10] = {CONFIGURATION_REGISTER, SHUNT_VOLTAGE_REGISTER,
- BUS_VOLTAGE_REGISTER, POWER_REGISTER,
- CURRENT_REGISTER, CALIBRATION_REGISTER,
- MASK_ENABLE_REGISTER, ALERT_LIMIT_REGISTER,
- MANUFACTURER_ID_REGISTER, DIE_ID_REGISTER};
- static uint16_t read_data[1] = {0};
- int ret = 0;
- //printk("sgm832 typec%d get data\n", typec_num);
- //00H Configuartion Register
- ret = i2c_write_read(i2c_dev, sgm832_typec_slaver_addr, write_cmd, 1, read_data, 2);
- if (ret != 0)
- {
- printk("sgm832 typec%d i2c_write_read Configuartion Register ERR\n", typec_num);
- }
-
- read_data[0] = ((read_data[0] & 0xFF00) >> 8) + ((read_data[0] & 0x00FF) << 8);
- //printk("ConfigReg: 0x%04x\n", read_data[0]);
- //01H Shunt Voltage Register
- ret = i2c_write_read(i2c_dev, sgm832_typec_slaver_addr, &write_cmd[1], 1, read_data, 2);
- if (ret == 0)
- {
- read_data[0] = ((read_data[0] & 0xFF00) >> 8) + ((read_data[0] & 0x00FF) << 8);
- if (read_data[0] & 0x8000) {
- // Sign-extend for negative ShuntVoltage
- read_data[0] = ~read_data[0] + 1;
- }
- f_ShuntVoltage[typec_num] = read_data[0] * 2.5 * 0.001;
- }
- else
- {
- printk("sgm832 typec%d i2c_write_read Shunt_Voltage ERR\n", typec_num);
- }
- //printk("Shunt_Voltage: %.4f mV\n", f_ShuntVoltage[typec_num]);
- //printk("ConfigReg: 0x%04x, ShuntVoltage: %.4f mV, BusVoltage: %.3f V, Power: 0x%04x, Current: 0x%04x, Calibration: 0x%04x, MaskEnable: 0x%04x, AlertLimit: 0x%04x\n",
- // read_data[0], f_ShuntVoltage, f_BusVoltage, read_data[3], read_data[4], read_data[5], read_data[6], read_data[7]);
- //02H Bus Voltage Register
- ret = i2c_write_read(i2c_dev, sgm832_typec_slaver_addr, &write_cmd[2], 1, read_data, 2);
- if (ret != 0)
- {
- printk("sgm832 typec%d i2c_write_read Bus Voltage Register ERR\n", typec_num);
- }
- read_data[0] = ((read_data[0] & 0xFF00) >> 8) + ((read_data[0] & 0x00FF) << 8);
- f_BusVoltage[typec_num] = (float)read_data[0] * 1.25 * 0.001;
- //printk("Bus_Voltage: %.3f V\n", f_BusVoltage[typec_num]);
- //03H Power Register
- ret = i2c_write_read(i2c_dev, sgm832_typec_slaver_addr, &write_cmd[3], 1, read_data, 2);
- if (ret != 0)
- {
- printk("sgm832 typec%d i2c_write_read Power Register ERR\n", typec_num);
- }
- read_data[0] = ((read_data[0] & 0xFF00) >> 8) + ((read_data[0] & 0x00FF) << 8);
- f_Power[typec_num] = (float)read_data[0] * 25 * 0.001; //W
- //printk("Power: %.3f mW\n", f_Power[typec_num]);
- //04H Current Register
- ret = i2c_write_read(i2c_dev, sgm832_typec_slaver_addr, &write_cmd[4], 1, read_data, 2);
- if (ret == 0)
- {
- read_data[0] = ((read_data[0] & 0xFF00) >> 8) + ((read_data[0] & 0x00FF) << 8);
- if (read_data[0] & 0x8000) {
- // Sign-extend for negative Current
- read_data[0] = ~read_data[0] + 1;
- }
- f_Current[typec_num] = read_data[0] * 0.001; //A
- }
- else
- {
- printk("sgm832 typec%d i2c_write_read Current Register ERR\n", typec_num);
- }
- //printk("Current: %.3f mA\n", f_Current[typec_num]);
- //05H Calibration Register
- ret = i2c_write_read(i2c_dev, sgm832_typec_slaver_addr, &write_cmd[5], 1, read_data, 2);
- if (ret != 0)
- {
- printk("sgm832 typec%d i2c_write_read Calibration Register ERR\n", typec_num);
- }
- read_data[0] = ((read_data[0] & 0xFF00) >> 8) + ((read_data[0] & 0x00FF) << 8);
- //printk("Calibration: 0x%04x\n", read_data[0]);
- //06H Mask/Enable Register
- ret = i2c_write_read(i2c_dev, sgm832_typec_slaver_addr, &write_cmd[6], 1, read_data, 2);
- if (ret != 0)
- {
- printk("sgm832 typec%d i2c_write_read Mask/Enable Register ERR\n", typec_num);
- }
- read_data[0] = ((read_data[0] & 0xFF00) >> 8) + ((read_data[0] & 0x00FF) << 8);
- //printk("Mask/Enable: 0x%04x\n", read_data[0]);
- //07H AlertLimit Register
- ret = i2c_write_read(i2c_dev, sgm832_typec_slaver_addr, &write_cmd[7], 1, read_data, 2);
- if (ret != 0)
- {
- printk("sgm832 typec%d i2c_write_read AlertLimit Register ERR\n", typec_num);
- }
- read_data[0] = ((read_data[0] & 0xFF00) >> 8) + ((read_data[0] & 0x00FF) << 8);
- //printk("AlertLimit: 0x%04x\n", read_data[0]);
- //FEH Manufacturer ID Register
- ret = i2c_write_read(i2c_dev, sgm832_typec_slaver_addr, &write_cmd[8], 1, read_data, 2);
- if (ret != 0)
- {
- printk("sgm832 typec%d i2c_write_read Manufacturer ID Register ERR\n", typec_num);
- }
- read_data[0] = ((read_data[0] & 0xFF00) >> 8) + ((read_data[0] & 0x00FF) << 8);
- //printk("Manufacturer_ID: 0x%04x\n", read_data[0]);
- //FFH Die ID Register
- ret = i2c_write_read(i2c_dev, sgm832_typec_slaver_addr, &write_cmd[9], 1, read_data, 2);
- if (ret != 0)
- {
- printk("sgm832 typec%d i2c_write_read Die ID Register ERR\n", typec_num);
- }
- read_data[0] = ((read_data[0] & 0xFF00) >> 8) + ((read_data[0] & 0x00FF) << 8);
- //printk("Die_ID: 0x%04x\n", read_data[0]);
- #endif
- }
- #if 0
- static void sgm832_typec1_get_shuntvoltage(const struct device *i2c_dev)
- {
- #if 1
- //uint8_t i;
- float f_ShuntVoltage = 0.0, f_BusVoltage = 0.0;
- //uint16_t u16_ShuntVoltage;
- static uint8_t write_cmd[2] = {CONFIGURATION_REGISTER, MANUFACTURER_ID_REGISTER};
- static uint16_t read_data[8] = {0};
- int ret = 0;
- printk("sgm832 typec1 get data\n");
- ret = i2c_write_read(i2c_dev, sgm832_typec1_slaver_addr, write_cmd, 1, read_data, sizeof(read_data));
- //ret = i2c_burst_read(i2c_dev, sgm832_typec1_slaver_addr, CONFIGURATION_REGISTER, read_data, sizeof(read_data));
- //ret = i2c_read(i2c_dev, read_data, 7, sgm832_typec1_slaver_addr);
- if (ret == 0)
- {
- if (read_data[1] & 0x8000) {
- // Sign-extend for negative ShuntVoltage
- read_data[1] = ~read_data[1] + 1;
- //printf( "ShuntVoltage: 0x%04x\n", u16_ShuntVoltage);
- f_ShuntVoltage = read_data[1] * 2.5 * 0.001;
- }
- else {
- f_ShuntVoltage = read_data[1] * 2.5 * 0.001;
- }
-
- //read_data[2] = ((read_data[2] & 0xFF00) >> 8) + ((read_data[2] & 0x00FF) << 8);
- f_BusVoltage = (float)read_data[2] * 1.25 * 0.001;
-
- //uart2_poll_out_ch(read_data[i]); //uart2 send data
- }
- else
- {
- printk("sgm832 typec1 i2c_write_read ERR\n");
- }
- printk("ConfigReg: 0x%04x, ShuntVoltage: %.4f mV, BusVoltage: %.3f V, Power: 0x%04x, Current: 0x%04x, Calibration: 0x%04x, MaskEnable: 0x%04x, AlertLimit: 0x%04x\n",
- read_data[0], f_ShuntVoltage, f_BusVoltage, read_data[3], read_data[4], read_data[5], read_data[6], read_data[7]);
- ret = i2c_write_read(i2c_dev, sgm832_typec1_slaver_addr, &write_cmd[1], 1, read_data, 4);
- //ret = i2c_burst_read(i2c_dev, sgm832_typec1_slaver_addr, CONFIGURATION_REGISTER, read_data, sizeof(read_data));
- //ret = i2c_read(i2c_dev, read_data, 7, sgm832_typec1_slaver_addr);
- if (ret == 0)
- {
-
- }
- else
- {
- printk("sgm832 typec1 i2c_write_read ERR\n");
- }
- printk("ManufacturerID: 0x%04x, DieID: 0x%04x\n",
- read_data[0], read_data[1]);
- #endif
- }
- #endif
- static void sgm832_typec_calibration(const struct device *i2c_dev, uint16_t sgm832_typec_slaver_addr, uint8_t typec_num)
- {
- //static uint8_t configurate_write_data[3] = {CONFIGURATION_REGISTER, 0x47, 0x6F};
- static uint8_t calibrate_write_data0[3] = {CALIBRATION_REGISTER, 0x00, 0xD0}; //typec0, input/output
- static uint8_t calibrate_write_data1[3] = {CALIBRATION_REGISTER, 0x00, 0xF2}; //typec1, input
- int ret = 0;
- //ret = i2c_write(i2c_dev, configurate_write_data, 3, sgm832_typec_slaver_addr);
- //if (ret != 0)
- //{
- // printk("i2c write sgm832_typec%d Configuration Register ERR\n", typec_num);
- // return;
- //}
- switch(typec_num)
- {
- case 0:
- ret = i2c_write(i2c_dev, calibrate_write_data0, 3, sgm832_typec_slaver_addr);
- break;
- case 1:
- ret = i2c_write(i2c_dev, calibrate_write_data1, 3, sgm832_typec_slaver_addr);
- break;
- default:
- break;
- }
- if (ret != 0)
- {
- printk("i2c write sgm832_typec%d Calibration Register ERR\n", typec_num);
- }
- }
- static void _sgm832a_init_work(struct k_work *work)
- {
- struct acts_sgm_data *power_consumption = &sgm_acts_ddata;
-
- printk("sgm832a init work\n");
- power_consumption->inited = true;
- //write Calibration Register
- sgm832_typec_calibration(power_consumption->i2c_dev, sgm832_typec0_slaver_addr, 0);
- sgm832_typec_calibration(power_consumption->i2c_dev, sgm832_typec1_slaver_addr, 1);
-
- htimer_read(500); //1000ms = 1s
- }
- static int _sgm832a_acts_init(const struct device *dev)
- {
- struct acts_sgm_data *power_consumption = dev->data;
- printk("sgm832a acts init\n");
- #if 1
- power_consumption->this_dev = (struct device *)dev;
- power_consumption->i2c_dev = (struct device *)device_get_binding(CONFIG_SGM832A_I2C_NAME);
- if (!power_consumption->i2c_dev) {
- printk("can not access right i2c device\n");
- return -1;
- }
- power_consumption->inited = false;
- k_work_init(&power_consumption->init_timer, _sgm832a_init_work);
- #ifdef CONFIG_USED_TP_WORK_QUEUE
- k_work_queue_start(&timer_drv_q, timer_work_q_stack, K_THREAD_STACK_SIZEOF(timer_work_q_stack), 7, NULL);
- k_work_submit_to_queue(&timer_drv_q, &power_consumption->init_timer);
- #else
- k_work_submit(&power_consumption->init_timer);
- #endif
- #endif
- printk("sgm832a acts init exit\n");
- return 0;
- }
- #ifdef CONFIG_PM_DEVICE
- static void _sgm832a_suspend(const struct device *dev)
- {
- //struct acts_sgm_data *power_consumption = (struct acts_sgm_data *)dev->data;
- printk("sgm832a suspend\n");
- hrtimer_stop(&g_sgm_ht_read);
- }
- static void _sgm832a_resume(const struct device *dev)
- {
- struct acts_sgm_data *power_consumption = (struct acts_sgm_data *)dev->data;
- power_consumption->i2c_dev = (struct device *)device_get_binding(CONFIG_SGM832A_I2C_NAME);
- if (!power_consumption->i2c_dev) {
- printk("can not access right i2c device\n");
- return;
- }
- power_consumption->inited = false;
- k_work_init(&power_consumption->init_timer, _sgm832a_init_work);
- printk("sgm832a resume\n");
- #ifdef CONFIG_USED_TP_WORK_QUEUE
- k_work_submit_to_queue(&tp_drv_q, &power_consumption->init_timer);
- #else
- k_work_submit(&power_consumption->init_timer);
- #endif
- }
- static int _sgm832a_pm_control(const struct device *dev, enum pm_device_action action)
- {
- int ret = 0;
-
- //printk("sgm832a pm control\n");
- switch (action) {
- case PM_DEVICE_ACTION_SUSPEND:
- break;
- case PM_DEVICE_ACTION_RESUME:
- break;
- case PM_DEVICE_ACTION_EARLY_SUSPEND:
- _sgm832a_suspend(dev);
- break;
- case PM_DEVICE_ACTION_LATE_RESUME:
- _sgm832a_resume(dev);
- break;
- default:
- break;
- }
- return ret;
- }
- #else /* CONFIG_PM_DEVICE */
- static int _sgm832a_pm_control(const struct device *dev, uint32_t ctrl_command,
- void *context, device_pm_cb cb, void *arg)
- {
- }
- #endif
- #if IS_ENABLED(CONFIG_SGM832A)
- DEVICE_DEFINE(sgm832a, CONFIG_SGM832A_DEV_NAME, _sgm832a_acts_init,
- _sgm832a_pm_control, &sgm_acts_ddata, NULL, POST_KERNEL,
- 50, NULL);
- #endif
|