diff --git a/patch/kernel/sunxi-dev/axp20x-sysfs-interface.patch b/patch/kernel/sunxi-dev/axp20x-sysfs-interface.patch index b273f48a9..b0916b2e2 100644 --- a/patch/kernel/sunxi-dev/axp20x-sysfs-interface.patch +++ b/patch/kernel/sunxi-dev/axp20x-sysfs-interface.patch @@ -1,5 +1,5 @@ diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c -index 9842199..f1e490c 100644 +index 9842199..15166b5 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -26,6 +26,7 @@ @@ -10,39 +10,82 @@ index 9842199..f1e490c 100644 #define AXP20X_OFF 0x80 -@@ -606,6 +607,469 @@ static void axp20x_power_off(void) +@@ -70,6 +71,7 @@ static const struct regmap_range axp20x_volatile_ranges[] = { + regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE), + regmap_reg_range(AXP20X_ACIN_V_ADC_H, AXP20X_IPSOUT_V_HIGH_L), + regmap_reg_range(AXP20X_GPIO20_SS, AXP20X_GPIO3_CTRL), ++ regmap_reg_range(AXP20X_CHRG_CC_31_24, AXP20X_DISCHRG_CC_7_0), + regmap_reg_range(AXP20X_FG_RES, AXP20X_RDC_L), + }; + +@@ -606,6 +608,488 @@ static void axp20x_power_off(void) AXP20X_OFF); } +#define kobj_to_device(x) container_of(x, struct device, kobj) + ++int axp20x_get_adc_freq(struct axp20x_dev *axp) ++{ ++ unsigned int res; ++ int ret, freq = 25; ++ ++ ret = regmap_read(axp->regmap, AXP20X_ADC_RATE, &res); ++ if (ret < 0) { ++ dev_warn(axp->dev, "Unable to read ADC sampling frequency: %d\n", ret); ++ return freq; ++ } ++ res &= 0xc0; ++ switch (res >> 6) { ++ case 0: ++ freq = 25; ++ break; ++ case 1: ++ freq = 50; ++ break; ++ case 2: ++ freq = 100; ++ break; ++ case 3: ++ freq = 200; ++ break; ++ } ++ return freq; ++} ++ +static ssize_t axp20x_read_special(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ -+ int ret; ++ int i, freq, ret = 0; + unsigned int res; -+ s32 lval; -+ u32 lval1 = 0, lval2 = 0; -+ struct axp20x_dev *axp; -+ const char *subsystem; -+ struct device *dev; ++ u32 lval1, lval2; ++ s64 llval; ++ u64 ullval; + -+ subsystem = kobject_name(kobj); -+ dev = kobj_to_device(kobj->parent); -+ axp = dev_get_drvdata(dev); ++ const char *subsystem = kobject_name(kobj); ++ struct device *dev = kobj_to_device(kobj->parent); ++ struct axp20x_dev *axp = dev_get_drvdata(dev); + -+ dev_dbg(axp->dev, "read_cumulative: reading attribute %s of object %s\n", attr->attr.name, subsystem); ++ dev_dbg(axp->dev, "read_special: reading attribute %s of object %s\n", attr->attr.name, subsystem); + + if (strcmp(subsystem, "battery") == 0) { + if (strcmp(attr->attr.name, "power") == 0) { -+ ret = regmap_bulk_read(axp->regmap, AXP20X_PWR_BATT_H, &lval1, 3); -+ lval = 2 * lval1 * 1100 * 500 / 1000 / 1000; ++ lval1 = 0; ++ for (i = 0; i < 3; i++) { ++ ret |= regmap_read(axp->regmap, AXP20X_PWR_BATT_H + i, &res); ++ lval1 |= res << ((2 - i) * 8); ++ } ++ llval = lval1 * 1100 / 1000; + } else if (strcmp(attr->attr.name, "charge") == 0) { -+ ret = regmap_bulk_read(axp->regmap, AXP20X_CHRG_CC_31_24, &lval1, 4); -+ ret = regmap_bulk_read(axp->regmap, AXP20X_DISCHRG_CC_31_24, &lval2, 4); -+ lval = 65536 * 500 * (lval1 - lval2) / 3600 / 100; ++ ret = regmap_raw_read(axp->regmap, AXP20X_CHRG_CC_31_24, &lval1, sizeof(lval1)); ++ ret |= regmap_raw_read(axp->regmap, AXP20X_DISCHRG_CC_31_24, &lval2, sizeof(lval2)); ++ be32_to_cpus(&lval1); ++ be32_to_cpus(&lval2); ++ ullval = abs((s64)lval1 - (s64)lval2) * 65536 * 500; ++ freq = axp20x_get_adc_freq(axp); ++ do_div(ullval, 3600 * freq); ++ llval = (lval1 < lval2) ? -ullval : ullval; + } else if (strcmp(attr->attr.name, "capacity") == 0) { + ret = regmap_read(axp->regmap, AXP20X_FG_RES, &res); -+ lval = res & 0x7f; ++ llval = res & 0x7f; + } else + return -EINVAL; + } else @@ -52,22 +95,19 @@ index 9842199..f1e490c 100644 + dev_warn(axp->dev, "Unable to read parameter: %d\n", ret); + return ret; + } -+ return sprintf(buf, "%d\n", lval); ++ return sprintf(buf, "%lld\n", llval); +} + +static ssize_t axp20x_read_bool(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ -+ int val, ret; -+ unsigned int res, reg, bit; -+ struct device *dev; -+ struct axp20x_dev *axp; -+ const char *subsystem; ++ int val, ret, reg, bit; ++ unsigned int res; + -+ subsystem = kobject_name(kobj); -+ dev = kobj_to_device(kobj->parent); -+ axp = dev_get_drvdata(dev); ++ const char *subsystem = kobject_name(kobj); ++ struct device *dev = kobj_to_device(kobj->parent); ++ struct axp20x_dev *axp = dev_get_drvdata(dev); + -+ dev_dbg(axp->dev, "write_bool: writing attribute %s of object %s\n", attr->attr.name, subsystem); ++ dev_dbg(axp->dev, "read_bool: writing attribute %s of object %s\n", attr->attr.name, subsystem); + + if (strcmp(subsystem, "ac") == 0) { + if (strcmp(attr->attr.name, "connected") == 0) { @@ -100,10 +140,7 @@ index 9842199..f1e490c 100644 + } else + return -EINVAL; + } else if (strcmp(subsystem, "pmu") == 0) { -+ if (strcmp(attr->attr.name, "cold_boot") == 0) { -+ reg = AXP20X_PWR_INPUT_STATUS; -+ bit = 0; -+ } else if (strcmp(attr->attr.name, "overheat") == 0) { ++ if (strcmp(attr->attr.name, "overheat") == 0) { + reg = AXP20X_PWR_OP_MODE; + bit = 7; + } else @@ -143,15 +180,11 @@ index 9842199..f1e490c 100644 + +static ssize_t axp20x_write_bool(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ -+ int var, ret; -+ unsigned int reg, bit; -+ struct device *dev; -+ struct axp20x_dev *axp; -+ const char *subsystem; ++ int var, ret, reg, bit; + -+ subsystem = kobject_name(kobj); -+ dev = kobj_to_device(kobj->parent); -+ axp = dev_get_drvdata(dev); ++ const char *subsystem = kobject_name(kobj); ++ struct device *dev = kobj_to_device(kobj->parent); ++ struct axp20x_dev *axp = dev_get_drvdata(dev); + + dev_dbg(axp->dev, "write_bool: writing attribute %s of object %s", attr->attr.name, subsystem); + @@ -177,8 +210,8 @@ index 9842199..f1e490c 100644 + return count; +} + -+static int axp20x_averaging_helper(struct regmap *reg_map, unsigned int reg_h, -+ unsigned int width) ++static int axp20x_averaging_helper(struct regmap *reg_map, int reg_h, ++ int width) +{ + long acc = 0; + int ret, i; @@ -188,23 +221,18 @@ index 9842199..f1e490c 100644 + if (ret < 0) + return ret; + acc += ret; -+ /* For 100Hz sampling frequency */ -+ msleep(20); ++ msleep(20); /* For 100Hz sampling frequency */ + } + return (int)(acc / 3); +} + +static ssize_t axp20x_read_int(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ -+ int val, ret, scale; -+ unsigned int reg, width = 12, offset = 0; -+ struct device *dev; -+ struct axp20x_dev *axp; -+ const char *subsystem; ++ int val, ret, scale, reg, width = 12, offset = 0; + -+ subsystem = kobject_name(kobj); -+ dev = kobj_to_device(kobj->parent); -+ axp = dev_get_drvdata(dev); ++ const char *subsystem = kobject_name(kobj); ++ struct device *dev = kobj_to_device(kobj->parent); ++ struct axp20x_dev *axp = dev_get_drvdata(dev); + + dev_dbg(axp->dev, "read_int: reading attribute %s of object %s\n", attr->attr.name, subsystem); + @@ -335,13 +363,11 @@ index 9842199..f1e490c 100644 +/* PMU */ +static struct kobj_attribute pmu_temp = __ATTR(temp, S_IRUGO, axp20x_read_int, NULL); +static struct kobj_attribute pmu_voltage = __ATTR(voltage, S_IRUGO, axp20x_read_int, NULL); -+static struct kobj_attribute pmu_cold_boot = __ATTR(cold_boot, S_IRUGO, axp20x_read_bool, NULL); +static struct kobj_attribute pmu_overheat = __ATTR(overheat, S_IRUGO, axp20x_read_bool, NULL); + +static struct attribute *axp20x_attributes_pmu[] = { + &pmu_temp.attr, + &pmu_voltage.attr, -+ &pmu_cold_boot.attr, + &pmu_overheat.attr, + NULL, +}; @@ -434,10 +460,11 @@ index 9842199..f1e490c 100644 + dev_warn(axp->dev, "Unable to set ADC frequency and TS current output: %d", ret); + + /* Enable fuel gauge and charge counter */ -+ ret = regmap_update_bits(axp->regmap, AXP20X_FG_RES, 0x80, 0x80); ++ ret = regmap_update_bits(axp->regmap, AXP20X_FG_RES, 0x80, 0x00); + if (ret) + dev_warn(axp->dev, "Unable to enable battery fuel gauge: %d", ret); -+ ret = regmap_update_bits(axp->regmap, AXP20X_CC_CTRL, 0x80, 0x80); ++ ret = regmap_update_bits(axp->regmap, AXP20X_CC_CTRL, 0xC0, 0x00); ++ ret |= regmap_update_bits(axp->regmap, AXP20X_CC_CTRL, 0xC0, 0x80); + if (ret) + dev_warn(axp->dev, "Unable to enable battery charge counter: %d", ret); + @@ -480,7 +507,7 @@ index 9842199..f1e490c 100644 static int axp20x_match_device(struct axp20x_dev *axp20x, struct device *dev) { const struct acpi_device_id *acpi_id; -@@ -711,6 +1175,10 @@ static int axp20x_i2c_probe(struct i2c_client *i2c, +@@ -711,6 +1195,10 @@ static int axp20x_i2c_probe(struct i2c_client *i2c, pm_power_off = axp20x_power_off; } @@ -491,7 +518,7 @@ index 9842199..f1e490c 100644 dev_info(&i2c->dev, "AXP20X driver loaded\n"); return 0; -@@ -720,6 +1188,10 @@ static int axp20x_i2c_remove(struct i2c_client *i2c) +@@ -720,6 +1208,10 @@ static int axp20x_i2c_remove(struct i2c_client *i2c) { struct axp20x_dev *axp20x = i2c_get_clientdata(i2c);