/* * ======== INA4235.c ======== * INA4235 APIs for initialization and use of the INA4235 peripheral * * DO NOT EDIT - This file is generated by the SysConfig tool for * the TI Sensors in this application. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "ina4235.h" #define maxRegAddress 0x7F #define GET_TEMP_START_DELAY (5 * HZ) #define CURRENT_LSB 500 //500µA static struct kobject *ina_kobj; struct ina4235_device { struct i2c_client *client; struct device *dev; struct regmap *regmap; //struct regmap_field *rmap_fields[F_MAX_FIELDS]; struct mutex lock; /* protect state data */ struct delayed_work ina_work; int CH1_SHUNT_VOLTAGE_μV; int CH1_VBUS_μV; int CH1_CURRENT_μA; int CH1_POWER_mW; int CH1_ENERGY_mJ; int CH2_SHUNT_VOLTAGE_μV; int CH2_VBUS_μV; int CH2_CURRENT_μA; int CH2_POWER_mW; int CH2_ENERGY_mJ; int CH3_SHUNT_VOLTAGE_μV; int CH3_VBUS_μV; int CH3_CURRENT_μA; int CH3_POWER_mW; int CH3_ENERGY_mJ; int CH4_SHUNT_VOLTAGE_μV; int CH4_VBUS_μV; int CH4_CURRENT_μA; int CH4_POWER_mW; int CH4_ENERGY_mJ; //current lsb value for various channels int currentlsb_ch1; int currentlsb_ch2; int currentlsb_ch3; int currentlsb_ch4; }; struct ina4235_device *ina; /* * ======== ina4235_writeReg ======== * Write register */ int ina4235_write_value( unsigned int reg,uint64_t val) { int err; mutex_lock(&ina->lock); err = regmap_write(ina->regmap, reg, val); mutex_unlock(&ina->lock); if (err < 0){ pr_err("[ina4235] ina4235_write_value: regmap_read failed!err is: %d\n",err); return err; } return 0; } /* * ======== ina4235_read_value ======== * Read register */ int ina4235_read_value( unsigned int reg, unsigned int *regval) { int err; mutex_lock(&ina->lock); err = regmap_read(ina->regmap, reg, regval); mutex_unlock(&ina->lock); if (err < 0){ pr_err("[ina4235] ina3221_read_value: regmap_read failed!err is: %d\n",err); return err; } return 0; } /* * ======== ina4235_getVSHUNT_μV ======== * Get VSHUNT value (μV) for each channel */ int ina4235_getVSHUNT_μV(int channel) { int data; unsigned int value; int adcrange; pr_info("[ina4235] ina4235_getVSHUNT_μV() \n"); switch(channel){ case 1: ina4235_read_value(INA4235_SHUNT_VOLTAGE_CH1_REGISTER,&value); adcrange = INA4235_CONFIG2_REGISTER_RANGE_CH1_8192MV; break; case 2: ina4235_read_value(INA4235_SHUNT_VOLTAGE_CH2_REGISTER,&value); adcrange = INA4235_CONFIG2_REGISTER_RANGE_CH2_8192MV; break; case 3: ina4235_read_value(INA4235_SHUNT_VOLTAGE_CH3_REGISTER,&value); adcrange = INA4235_CONFIG2_REGISTER_RANGE_CH3_8192MV; break; case 4: ina4235_read_value(INA4235_SHUNT_VOLTAGE_CH4_REGISTER,&value); adcrange = INA4235_CONFIG2_REGISTER_RANGE_CH4_8192MV; break; } //Convert for 2's compliment and signed value if(value > 0x7FFF) { data = value - 0x10000; } else { data = value; } //Convert to μV if(adcrange) // if ADCRANGE = ±20.48mV { data = (data * 625/1000); } else // if ADCRANGE = ±80.92mV { data = (data * 25/10); } switch(channel){ case 1: ina->CH1_SHUNT_VOLTAGE_μV = data; break; case 2: ina->CH2_SHUNT_VOLTAGE_μV = data; break; case 3: ina->CH3_SHUNT_VOLTAGE_μV = data; break; case 4: ina->CH4_SHUNT_VOLTAGE_μV = data; break; } pr_err("[ina4235] ina4235_getVSHUNT_μV channel is %d, VSHUNT is %dμV\n",channel,data); return data; } /* * ======== ina4235_getVBUS_μV ======== * Get VBUS value (μV) for each channel */ int ina4235_getVBUS_μV(int channel) { int data; unsigned int value; pr_info("[ina4235] ina4235_getVBUS_μV() \n"); switch(channel){ case 1: ina4235_read_value(INA4235_BUS_VOLTAGE_CH1_REGISTER,&value); break; case 2: ina4235_read_value(INA4235_BUS_VOLTAGE_CH2_REGISTER,&value); break; case 3: ina4235_read_value(INA4235_BUS_VOLTAGE_CH3_REGISTER,&value); break; case 4: ina4235_read_value(INA4235_BUS_VOLTAGE_CH4_REGISTER,&value); break; } //Convert for 2's compliment and signed value (though always positive) if(value > 0x7FFF) { data = value - 0x10000; //left for redundancy and error checking, should never get used } else { data = value; } //Convert to uV data = (data * 1600); switch(channel){ case 1: ina->CH1_VBUS_μV = data; break; case 2: ina->CH2_VBUS_μV = data; break; case 3: ina->CH3_VBUS_μV = data; break; case 4: ina->CH4_VBUS_μV = data; break; } pr_err("[ina4235] ina4235_getVBUS_μV channel is %d, VBUS is %dμV\n",channel,data); return data; } /* * ======== ina4235_setCURRENT_LSB ======== * Set the CURRENT_LSB value used for calculations on each channel */ void ina4235_setCURRENT_LSB(int channel) { pr_err("[ina4235] ina4235_setCURRENT_LSB() \n"); switch(channel){ case 1: ina->currentlsb_ch1 = CURRENT_LSB; break; case 2: ina->currentlsb_ch2 = CURRENT_LSB; break; case 3: ina->currentlsb_ch3 = CURRENT_LSB; break; case 4: ina->currentlsb_ch4 = CURRENT_LSB; break; } } /* * ======== ina4235_getCURRENT_signedLSB ======== * Get CURRENT value (signed value in LSBs) for each channel */ int ina4235_getCURRENT_signedLSB(int channel) { int data; unsigned int value; pr_info("[ina4235] ina4235_getCURRENT_signedLSB() \n"); switch(channel){ case 1: ina4235_read_value(INA4235_CURRENT_CH1_REGISTER,&value); break; case 2: ina4235_read_value(INA4235_CURRENT_CH2_REGISTER,&value); break; case 3: ina4235_read_value(INA4235_CURRENT_CH3_REGISTER,&value); break; case 4: ina4235_read_value(INA4235_CURRENT_CH4_REGISTER,&value); break; } //Convert for 2's compliment and signed value if(value > 0x7FFF) { data = value - 0x10000; } else { data = value; } pr_err("[ina4235] ina4235_getCURRENT_signedLSB channel is %d, CURRENT is %dA\n",channel,data); return data; } /* * ======== ina4235_getCURRENT_µA ======== * Get CURRENT value (µA) for each channel */ int ina4235_getCURRENT_µA( int channel) { int data; int currentlsb; pr_info("[ina4235] ina4235_getCURRENT_µA() \n"); data = ina4235_getCURRENT_signedLSB(channel); switch(channel){ case 1: currentlsb = ina->currentlsb_ch1; data = data * currentlsb; ina->CH1_CURRENT_μA = data; break; case 2: currentlsb = ina->currentlsb_ch2; data = data * currentlsb; ina->CH2_CURRENT_μA = data; break; case 3: currentlsb = ina->currentlsb_ch3; data = data * currentlsb; ina->CH3_CURRENT_μA = data; break; case 4: currentlsb = ina->currentlsb_ch4; data = data * currentlsb; ina->CH4_CURRENT_μA = data; break; } pr_err("[ina4235] ina4235_getCURRENT_µA channel is %d, CURRENT is %dµA\n",channel,data); return data; } /* * ======== ian4235_getPOWER_signedLSB ======== * Get POWER value (signed value in LSBs) for each channel */ int ina4235_getPOWER_signedLSB(int channel) { int data; unsigned int value; pr_info("INA4235: ina4235_getPOWER_signedLSB() \n"); switch(channel){ case 1: ina4235_read_value(INA4235_POWER_CH1_REGISTER,&value); break; case 2: ina4235_read_value(INA4235_POWER_CH2_REGISTER,&value); break; case 3: ina4235_read_value(INA4235_POWER_CH3_REGISTER,&value); break; case 4: ina4235_read_value(INA4235_POWER_CH4_REGISTER,&value); break; } data = value; pr_err("[ina4235] ina4235_getPOWER_signedLSB channel is %d, POWER is %dmW\n",channel,data); return data; } /* * ======== ina4235_getPOWER_mW ======== * Get POWER value (mW) for each channel */ int ina4235_getPOWER_mW(int channel) { int data; int currentlsb; pr_info("[ina4235] ina4235_getPOWER_mW() \n"); data = ina4235_getPOWER_signedLSB(channel); switch(channel){ case 1: currentlsb = ina->currentlsb_ch1; data = data * currentlsb * 32; ina->CH1_POWER_mW = data; break; case 2: currentlsb = ina->currentlsb_ch2; data = data * currentlsb * 32; ina->CH2_POWER_mW = data; break; case 3: currentlsb = ina->currentlsb_ch3; data = data * currentlsb * 32; ina->CH3_POWER_mW = data;; break; case 4: currentlsb = ina->currentlsb_ch4; data = data * currentlsb * 32; ina->CH4_POWER_mW = data; break; } pr_err("[ina4235] ina4235_getPOWER_mW channel is %d, POWER is %dmW\n",channel,data); return data; } /* * ======== ina4235_getENERGY_signedLSB ======== * Get ENERGY value (signed value in LSBs) for each channel */ int ina4235_getENERGY_signedLSB(int channel) { int data; unsigned int value; pr_info("[ina4235] ina4235_getENERGY_signedLSB() \n"); switch(channel){ case 1: value = ina4235_read_value(INA4235_ENERGY_CH1_REGISTER,&value); break; case 2: value = ina4235_read_value(INA4235_ENERGY_CH2_REGISTER,&value); break; case 3: value = ina4235_read_value(INA4235_ENERGY_CH3_REGISTER,&value); break; case 4: value = ina4235_read_value(INA4235_ENERGY_CH4_REGISTER,&value); break; } data = value; pr_err("[ina4235] ina4235_getENERGY_signedLSB channel is %d, ENERGY is %dmJ\n",channel,data); return data; } /* * ======== ina4235_getENERGY_mJ ======== * Get ENERGY value (mJ) for each channel */ int ina4235_getENERGY_mJ(int channel) { int data; int currentlsb; data = ina4235_getENERGY_signedLSB(channel); pr_info("[ina4235] ina4235_getENERGY_mJ() \n"); switch(channel){ case 1: currentlsb = ina->currentlsb_ch1; data = data * currentlsb * 32; ina->CH1_ENERGY_mJ = data; break; case 2: currentlsb = ina->currentlsb_ch2; data = data * currentlsb * 32; ina->CH2_ENERGY_mJ = data; break; case 3: currentlsb = ina->currentlsb_ch3; data = data * currentlsb * 32; ina->CH3_ENERGY_mJ = data; break; case 4: currentlsb = ina->currentlsb_ch4; data = data * currentlsb * 32; ina->CH4_ENERGY_mJ = data; break; } pr_err("[ina4235] ina4235_getENERGY_mJ channel is %d, ENERGY is %dmJ\n",channel,data); return data; } static ssize_t CH1_SHUNT_VOLTAGE_μV_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH1_SHUNT_VOLTAGE_μV = %dμV\n", ina->CH1_SHUNT_VOLTAGE_μV); } static struct kobj_attribute CH1_SHUNT_VOLTAGE_μV_attr = __ATTR(CH1_SHUNT_VOLTAGE_μV, 0664, CH1_SHUNT_VOLTAGE_μV_show,NULL); static ssize_t CH1_VBUS_μV_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH1_VBUS_μV = %dμV\n", ina->CH1_VBUS_μV); } static struct kobj_attribute CH1_VBUS_μV_attr = __ATTR(CH1_VBUS_μV, 0664, CH1_VBUS_μV_show,NULL); static ssize_t CH1_CURRENT_μA_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH1_CURRENT_μA = %dμA\n", ina->CH1_CURRENT_μA); } static struct kobj_attribute CH1_CURRENT_μA_attr = __ATTR(CH1_CURRENT_μA, 0664, CH1_CURRENT_μA_show,NULL); static ssize_t CH1_POWER_mW_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH1_POWER_mW = %dmW\n", ina-> CH1_POWER_mW); } static struct kobj_attribute CH1_POWER_mW_attr = __ATTR(CH1_POWER_mW, 0664, CH1_POWER_mW_show,NULL); static ssize_t CH1_ENERGY_mJ_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH1_ENERGY_mJ = %dmJ\n", ina->CH1_ENERGY_mJ); } static struct kobj_attribute CH1_ENERGY_mJ_attr = __ATTR(CH1_ENERGY_mJ, 0664, CH1_ENERGY_mJ_show,NULL); static ssize_t CH2_SHUNT_VOLTAGE_μV_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH2_SHUNT_VOLTAGE_μV = %dμV\n", ina->CH2_SHUNT_VOLTAGE_μV); } static struct kobj_attribute CH2_SHUNT_VOLTAGE_μV_attr = __ATTR(CH2_SHUNT_VOLTAGE_μV, 0664, CH2_SHUNT_VOLTAGE_μV_show,NULL); static ssize_t CH2_VBUS_μV_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH2_VBUS_μV = %dμV\n", ina->CH2_VBUS_μV); } static struct kobj_attribute CH2_VBUS_μV_attr = __ATTR(CH2_VBUS_μV, 0664, CH2_VBUS_μV_show,NULL); static ssize_t CH2_CURRENT_μA_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH2_CURRENT_μA = %d\n", ina->CH2_CURRENT_μA); } static struct kobj_attribute CH2_CURRENT_μA_attr = __ATTR(CH2_CURRENT_μA, 0664, CH2_CURRENT_μA_show,NULL); static ssize_t CH2_POWER_mW_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH2_POWER_mW = %dmW\n", ina-> CH2_POWER_mW); } static struct kobj_attribute CH2_POWER_mW_attr = __ATTR(CH2_POWER_mW, 0664, CH2_POWER_mW_show,NULL); static ssize_t CH2_ENERGY_mJ_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH2_ENERGY_mJ = %dmJ\n", ina->CH2_ENERGY_mJ); } static struct kobj_attribute CH2_ENERGY_mJ_attr = __ATTR(CH2_ENERGY_mJ, 0664, CH2_ENERGY_mJ_show,NULL); static ssize_t CH3_SHUNT_VOLTAGE_μV_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH3_SHUNT_VOLTAGE_μV = %d\n", ina->CH3_SHUNT_VOLTAGE_μV); } static struct kobj_attribute CH3_SHUNT_VOLTAGE_μV_attr = __ATTR(CH3_SHUNT_VOLTAGE_μV, 0664, CH3_SHUNT_VOLTAGE_μV_show,NULL); static ssize_t CH3_VBUS_μV_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH3_VBUS_μV = %dμV\n", ina->CH3_VBUS_μV); } static struct kobj_attribute CH3_VBUS_μV_attr = __ATTR(CH3_VBUS_μV, 0664, CH3_VBUS_μV_show,NULL); static ssize_t CH3_CURRENT_μA_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH3_CURRENT_μA = %dμA\n", ina->CH3_CURRENT_μA); } static struct kobj_attribute CH3_CURRENT_μA_attr = __ATTR(CH3_CURRENT_μA, 0664, CH3_CURRENT_μA_show,NULL); static ssize_t CH3_POWER_mW_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH3_POWER_mW = %dmW\n", ina-> CH3_POWER_mW); } static struct kobj_attribute CH3_POWER_mW_attr = __ATTR( CH3_POWER_mW, 0664, CH3_POWER_mW_show,NULL); static ssize_t CH3_ENERGY_mJ_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH3_ENERGY_mJ = %dmJ\n", ina->CH3_ENERGY_mJ); } static struct kobj_attribute CH3_ENERGY_mJ_attr = __ATTR(CH3_ENERGY_mJ, 0664, CH3_ENERGY_mJ_show,NULL); static ssize_t CH4_SHUNT_VOLTAGE_μV_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH4_SHUNT_VOLTAGE_μV = %d\n", ina->CH4_SHUNT_VOLTAGE_μV); } static struct kobj_attribute CH4_SHUNT_VOLTAGE_μV_attr = __ATTR(CH4_SHUNT_VOLTAGE_μV, 0664, CH4_SHUNT_VOLTAGE_μV_show,NULL); static ssize_t CH4_VBUS_μV_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH4_VBUS_μV = %dμV\n", ina->CH4_VBUS_μV); } static struct kobj_attribute CH4_VBUS_μV_attr = __ATTR(CH4_VBUS_μV, 0664, CH4_VBUS_μV_show,NULL); static ssize_t CH4_CURRENT_μA_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH4_CURRENT_μA = %d\n", ina->CH4_CURRENT_μA); } static struct kobj_attribute CH4_CURRENT_μA_attr = __ATTR(CH4_CURRENT_μA, 0664, CH4_CURRENT_μA_show,NULL); static ssize_t CH4_POWER_mW_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH4_POWER_mW = %dmW\n", ina-> CH4_POWER_mW); } static struct kobj_attribute CH4_POWER_mW_attr = __ATTR(CH4_POWER_mW, 0664, CH4_POWER_mW_show,NULL); static ssize_t CH4_ENERGY_mJ_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "CH4_ENERGY_mJ = %dmJ\n", ina->CH4_ENERGY_mJ); } static struct kobj_attribute CH4_ENERGY_mJ_attr = __ATTR(CH4_ENERGY_mJ, 0664, CH4_ENERGY_mJ_show,NULL); static struct attribute *ina_attrs[] = { &CH1_SHUNT_VOLTAGE_μV_attr.attr, &CH1_VBUS_μV_attr.attr, &CH1_CURRENT_μA_attr.attr, &CH1_POWER_mW_attr.attr, &CH1_ENERGY_mJ_attr.attr, &CH2_SHUNT_VOLTAGE_μV_attr.attr, &CH2_VBUS_μV_attr.attr, &CH2_CURRENT_μA_attr.attr, &CH2_POWER_mW_attr.attr, &CH2_ENERGY_mJ_attr.attr, &CH3_SHUNT_VOLTAGE_μV_attr.attr, &CH3_VBUS_μV_attr.attr, &CH3_CURRENT_μA_attr.attr, &CH3_POWER_mW_attr.attr, &CH3_ENERGY_mJ_attr.attr, &CH4_SHUNT_VOLTAGE_μV_attr.attr, &CH4_VBUS_μV_attr.attr, &CH4_CURRENT_μA_attr.attr, &CH4_POWER_mW_attr.attr, &CH4_ENERGY_mJ_attr.attr, NULL, }; static struct attribute_group ina_group = { .attrs = ina_attrs, }; static int ina4235_get_manufacturer_id(void) { int err; unsigned int regval; err =ina4235_read_value(INA4235_MANUFACTURER_ID_REGISTER, ®val); if (err < 0){ pr_err("[ina4235] ina4235_get_manufacturer_id regmap read failed! err is: %d\n",err); return err; } pr_err("[ina4235] INA4235 manufacturer id is %x\n",regval); return 0; } static int ina4235_get_device_id(void) { int err; unsigned int regval; err =ina4235_read_value(INA4235_DEVICE_ID_REGISTER, ®val); if (err < 0){ pr_err("[ina4235] ina4235_get_device_id regmap read failed! err is: %d\n",err); return err; } pr_err("[ina4235] INA4235 device id is %x\n",regval); return 0; } static int ina4235_get_config(void) { int err; unsigned int regval; err =ina4235_read_value(0x20, ®val); if (err < 0){ pr_err("[ina4235] ina4235_get_config regmap read failed! err is: %d\n",err); return err; } pr_err("[ina4235] INA4235 config1 is %x\n",regval); err =ina4235_read_value(0x21, ®val); if (err < 0){ pr_err("[ina4235] ina4235_get_config regmap read failed! err2 is: %d\n",err); return err; } pr_err("[ina4235] INA4235 config2 is %x\n",regval); return 0; } #if 0 static int ina4235_set_config(void) { int err; err =ina4235_write_value(0x20,0xF127); if (err < 0){ pr_err("[ina4235] ina4235_set_config regmap write failed! err is: %d\n",err); return err; } #if 0 err =ina4235_write_value(0x21, ); if (err < 0){ pr_err("[ina4235] ina4235_set_config regmap write failed! err is: %d\n",err); return err; } #endif ina4235_get_config(); return 0; } #endif static const struct regmap_config ina4235_regmap_config = { .reg_bits = 8, .val_bits = 16, .cache_type = REGCACHE_RBTREE, .use_single_read = true, .use_single_write = true, }; static void ina4235_work(struct work_struct *data) { struct ina4235_device *ina = container_of(data, struct ina4235_device, ina_work.work); ina4235_getVSHUNT_μV(ADC_CHANNEL_1); ina4235_getVBUS_μV(ADC_CHANNEL_1); ina4235_getCURRENT_µA(ADC_CHANNEL_1); ina4235_getPOWER_mW(ADC_CHANNEL_1); ina4235_getENERGY_mJ(ADC_CHANNEL_1); ina4235_getVSHUNT_μV(ADC_CHANNEL_2); ina4235_getVBUS_μV(ADC_CHANNEL_2); ina4235_getCURRENT_µA(ADC_CHANNEL_2); ina4235_getPOWER_mW(ADC_CHANNEL_2); ina4235_getENERGY_mJ(ADC_CHANNEL_2); ina4235_getVSHUNT_μV(ADC_CHANNEL_3); ina4235_getVBUS_μV(ADC_CHANNEL_3); ina4235_getCURRENT_µA(ADC_CHANNEL_3); ina4235_getPOWER_mW(ADC_CHANNEL_3); ina4235_getENERGY_mJ(ADC_CHANNEL_3); ina4235_getVSHUNT_μV(ADC_CHANNEL_1); ina4235_getVBUS_μV(ADC_CHANNEL_4); ina4235_getCURRENT_µA(ADC_CHANNEL_4); ina4235_getPOWER_mW(ADC_CHANNEL_4); ina4235_getENERGY_mJ(ADC_CHANNEL_4); queue_delayed_work(system_power_efficient_wq, &ina->ina_work, GET_TEMP_START_DELAY); return; } static int ina4235_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct device_node *np = client->dev.of_node; int ret = 0; int gpio_num; pr_err("[ina4235] ina4235 probe start!\n"); //Set GPIO88 to output high level to enable ina4235. gpio_num = of_get_named_gpio(np,"mux-sel-gpio", 0); pr_err("[ina4235] gpio_num = %d", gpio_num); if(gpio_is_valid(gpio_num)){ ret = gpio_request(gpio_num, "mux-sel-gpio"); if (ret) { pr_err("[ina4235] Failed requesting gpio_bum = %d, ret=%d\n", gpio_num, ret); gpio_free(gpio_num); } } ret = gpio_direction_output(gpio_num, 1); ina = devm_kzalloc(dev, sizeof(*ina), GFP_KERNEL); if (!ina) return -ENOMEM; ina->client = client; ina->dev = dev; i2c_set_clientdata(client, ina); ina->regmap = devm_regmap_init_i2c(client, &ina4235_regmap_config); if (IS_ERR(ina->regmap)) { pr_err("[ina4235] Unable to allocate register map\n"); return PTR_ERR(ina->regmap); } ina_kobj = kobject_create_and_add("ina4235",NULL); if (!ina_kobj) { goto exit; } ret = sysfs_create_group(ina_kobj,&ina_group); if (ret) { goto sysfs_create_fail; } mutex_init(&ina->lock); INIT_DELAYED_WORK(&ina->ina_work, ina4235_work); queue_delayed_work(system_power_efficient_wq, &ina->ina_work, GET_TEMP_START_DELAY); ina4235_get_config(); ina4235_setCURRENT_LSB(ADC_CHANNEL_1); ina4235_setCURRENT_LSB(ADC_CHANNEL_2); ina4235_setCURRENT_LSB(ADC_CHANNEL_3); ina4235_setCURRENT_LSB(ADC_CHANNEL_4); ina4235_get_device_id(); ina4235_get_manufacturer_id(); exit: return ret; sysfs_create_fail: kobject_put(ina_kobj); return 0; } static int ina4235_suspend(struct device *dev) { return 0; } static int ina4235_resume(struct device *dev) { return 0; } static const struct dev_pm_ops ina4235_pm = { SET_SYSTEM_SLEEP_PM_OPS(ina4235_suspend, ina4235_resume) }; static const struct i2c_device_id ina4235_i2c_ids[] = { { "ina4235", 0 }, {}, }; MODULE_DEVICE_TABLE(i2c, ina4235_i2c_ids); static const struct of_device_id ina4235_of_match[] = { { .compatible = "ti,ina4235", }, { }, }; MODULE_DEVICE_TABLE(of, ina4235_of_match); static struct i2c_driver INA4235_driver = { .driver = { .name = "ina4235", .of_match_table = of_match_ptr(ina4235_of_match), .pm = &ina4235_pm, }, .probe_new = ina4235_probe, }; module_i2c_driver(INA4235_driver); MODULE_DESCRIPTION("INA4235 current monitor driver"); MODULE_LICENSE("GPL");