Hey Olliver, For mainline I wrote a driver for the power supply part some time ago and posted it here (it's referenced from the mainlining page on the WIKI).
It covers ACIN, BATTERY and VBUS power supplies with both current and voltage measurements. For battery it could also provide temperature information though converting the voltage reading into a temperature is still missing (I have no board with battery temperature sensor) I will review which parts it depends on already hit mainline since then and post an updated series, probably sometime next weekend. Bruno On Sun, 12 October 2014 Olliver Schinagl <[email protected]> wrote: > Hey Siarhei, > > this driver only works on 3.4 right? I think we have the axp20x driver > in mainline too do we not? > > Anyway, I think in a few weeks time from now, I will run some > temperature calibration tests on various Lime's and will generate a lot > of temperature data. It won't be a huge problem to also generate voltage > (fixed at 5.00V) and current data based on different workloads (gpu, cpu > (no vpu)) if that is helpfull at all. > > Let me know what you think. > > Olliver > > On 04/01/2014 08:36 PM, Siarhei Siamashka wrote: > > As long as somebody is regularly accessing axp20x hwmon sysfs entries, > > maintain a work queue for 25Hz periodic sampling of ACIN voltage/current > > information. And calculate moving average using this data. This periodic > > sampling stops after ~1 minute from the last access to axp20x hwmon sysfs. > > > > Comparison of the current draw (in mA) for different workloads, measured > > by the axp20x hwmon averaged stats (on the left side) and with a multimeter > > (on the right side). The following sunxi based hardware has been tested > > (without anything extra connected to USB/SATA): > > > > Olinuxino-Lime (Allwinner A10): > > 300 315 > > 555 590 > > 990 1060 > > > > Cubietruck (Allwinner A20): > > 215 240 > > 310 345 > > 730 800 > > > > Cubieboard2 (Allwinner A20): > > 80 245 > > 180 415 > > 325 610 > > 490 820 > > > > Mele A2000 (Allwinner A10): > > 180 450 > > 280 560 > > 450 770 > > > > AXP209 on Olinuxino-Lime and Cubietruck reports reasonably accurate > > results. But not so much for the other devices. > > > > v2: The decision whether to run periodic sampling is now fully > > automatic. No configuration is needed. And no parasitic background > > activity is expected when nobody is interested in axp20x hwmon > > sysfs data. > > > > Signed-off-by: Siarhei Siamashka <[email protected]> > > --- > > drivers/power/axp_power/axp-mfd.c | 4 +++ > > drivers/power/axp_power/axp20-mfd.h | 68 > > +++++++++++++++++++++++++++++++++---- > > include/linux/mfd/axp-mfd.h | 3 ++ > > 3 files changed, 69 insertions(+), 6 deletions(-) > > > > diff --git a/drivers/power/axp_power/axp-mfd.c > > b/drivers/power/axp_power/axp-mfd.c > > index cfa894a..6fd1264 100644 > > --- a/drivers/power/axp_power/axp-mfd.c > > +++ b/drivers/power/axp_power/axp-mfd.c > > @@ -365,6 +365,10 @@ static int __devexit axp_mfd_remove(struct i2c_client > > *client) > > > > #ifdef CONFIG_AXP_HWMON > > if (chip->itm_enabled == 1) { > > + cancel_delayed_work(&axp_hwmon_work); > > + flush_workqueue(wq); > > + destroy_workqueue(wq); > > + > > hwmon_device_unregister(chip->hwmon_dev); > > sysfs_remove_group(&client->dev.kobj, &axp20_group); > > } > > diff --git a/drivers/power/axp_power/axp20-mfd.h > > b/drivers/power/axp_power/axp20-mfd.h > > index 4244d49..fe7aeb1 100644 > > --- a/drivers/power/axp_power/axp20-mfd.h > > +++ b/drivers/power/axp_power/axp20-mfd.h > > @@ -28,13 +28,14 @@ > > #include <linux/hwmon.h> > > #include <linux/err.h> > > > > -static struct axp_mfd_chip *axp20_update_device(struct device *dev); > > +static struct > > +axp_mfd_chip *axp20_update_device(struct device *dev, int from_wq); > > > > static ssize_t > > show_temp(struct device *dev, struct device_attribute *devattr, char *buf) > > { > > struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); > > - struct axp_mfd_chip *data = axp20_update_device(dev); > > + struct axp_mfd_chip *data = axp20_update_device(dev, 0); > > if (attr->index == 1) > > return sprintf(buf, "264800\n"); > > if (attr->index == 2) > > @@ -49,9 +50,11 @@ show_acin_voltage(struct device *dev, struct > > device_attribute *devattr, > > char *buf) > > { > > struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); > > - struct axp_mfd_chip *data = axp20_update_device(dev); > > + struct axp_mfd_chip *data = axp20_update_device(dev, 0); > > if (attr->index == 3) > > return sprintf(buf, "ACIN voltage\n"); > > + if (attr->index == 4) > > + return sprintf(buf, "%d\n", data->acin_avg_voltage / 64); > > return sprintf(buf, "%d\n", data->acin_voltage); > > } > > > > @@ -60,9 +63,11 @@ show_acin_current(struct device *dev, struct > > device_attribute *devattr, > > char *buf) > > { > > struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); > > - struct axp_mfd_chip *data = axp20_update_device(dev); > > + struct axp_mfd_chip *data = axp20_update_device(dev, 0); > > if (attr->index == 3) > > return sprintf(buf, "ACIN current\n"); > > + if (attr->index == 4) > > + return sprintf(buf, "%d\n", data->acin_avg_current / 64); > > return sprintf(buf, "%d\n", data->acin_current); > > } > > > > @@ -70,9 +75,11 @@ static ssize_t > > show_acin_power(struct device *dev, struct device_attribute *devattr, > > char *buf) > > { > > struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); > > - struct axp_mfd_chip *data = axp20_update_device(dev); > > + struct axp_mfd_chip *data = axp20_update_device(dev, 0); > > if (attr->index == 3) > > return sprintf(buf, "ACIN power\n"); > > + if (attr->index == 4) > > + return sprintf(buf, "%d\n", data->acin_avg_power / 64); > > return sprintf(buf, "%d\n", data->acin_power); > > } > > > > @@ -82,10 +89,13 @@ static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, > > show_temp, NULL, 2); > > static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_temp, NULL, 3); > > static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_acin_voltage, NULL, 0); > > static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_acin_voltage, NULL, 3); > > +static SENSOR_DEVICE_ATTR(in0_average, S_IRUGO, show_acin_voltage, NULL, > > 4); > > static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, show_acin_current, NULL, > > 0); > > static SENSOR_DEVICE_ATTR(curr1_label, S_IRUGO, show_acin_current, NULL, > > 3); > > +static SENSOR_DEVICE_ATTR(curr1_average, S_IRUGO, show_acin_current, NULL, > > 4); > > static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, show_acin_power, NULL, > > 0); > > static SENSOR_DEVICE_ATTR(power1_label, S_IRUGO, show_acin_power, NULL, > > 3); > > +static SENSOR_DEVICE_ATTR(power1_average, S_IRUGO, show_acin_power, NULL, > > 4); > > > > static struct attribute *axp20_attributes[] = { > > &sensor_dev_attr_temp1_input.dev_attr.attr, > > @@ -94,10 +104,13 @@ static struct attribute *axp20_attributes[] = { > > &sensor_dev_attr_temp1_label.dev_attr.attr, > > &sensor_dev_attr_in0_input.dev_attr.attr, > > &sensor_dev_attr_in0_label.dev_attr.attr, > > + &sensor_dev_attr_in0_average.dev_attr.attr, > > &sensor_dev_attr_curr1_input.dev_attr.attr, > > &sensor_dev_attr_curr1_label.dev_attr.attr, > > + &sensor_dev_attr_curr1_average.dev_attr.attr, > > &sensor_dev_attr_power1_input.dev_attr.attr, > > &sensor_dev_attr_power1_label.dev_attr.attr, > > + &sensor_dev_attr_power1_average.dev_attr.attr, > > NULL > > }; > > > > @@ -125,10 +138,23 @@ static int axp_read_adc(struct device *dev, struct > > i2c_client *client, int reg) > > return (high << 4) + (low & 0x0F); > > } > > > > +static int axp_hwmon_wq_counter; > > + > > +static void axp_hwmon_work_handler(struct work_struct *w); > > +static struct workqueue_struct *wq; > > +static DECLARE_DELAYED_WORK(axp_hwmon_work, axp_hwmon_work_handler); > > + > > +static struct device *wq_dev_arg; > > + > > +static void axp_hwmon_work_handler(struct work_struct *w) > > +{ > > + axp20_update_device(wq_dev_arg, 1); > > +} > > + > > /* > > * * function that update the status of the chips (temperature) > > * */ > > -static struct axp_mfd_chip *axp20_update_device(struct device *dev) > > +static struct axp_mfd_chip *axp20_update_device(struct device *dev, int > > from_wq) > > { > > struct i2c_client *client = to_i2c_client(dev); > > struct axp_mfd_chip *data = i2c_get_clientdata(client); > > @@ -155,10 +181,38 @@ static struct axp_mfd_chip > > *axp20_update_device(struct device *dev) > > > > data->acin_power = data->acin_voltage * data->acin_current; > > > > + if (!axp_hwmon_wq_counter || !data->valid) { > > + data->acin_avg_power = 0; > > + data->acin_avg_voltage = 0; > > + data->acin_avg_current = 0; > > + } else { > > + /* Calculate running moving average for N=64 */ > > + data->acin_avg_power -= data->acin_avg_power / 64; > > + data->acin_avg_power += data->acin_voltage * > > + data->acin_current; > > + > > + data->acin_avg_voltage -= data->acin_avg_voltage / 64; > > + data->acin_avg_voltage += data->acin_voltage; > > + > > + data->acin_avg_current -= data->acin_avg_current / 64; > > + data->acin_avg_current += data->acin_current; > > + } > > + > > data->last_updated = jiffies; > > data->valid = 1; > > } > > > > + if (from_wq) { > > + if (axp_hwmon_wq_counter > 0) { > > + queue_delayed_work(wq, &axp_hwmon_work, HZ / 25); > > + axp_hwmon_wq_counter--; > > + } > > + } else { > > + /* Keep running for at least 1 minute from now */ > > + axp_hwmon_wq_counter = 61 * 25; > > + queue_delayed_work(wq, &axp_hwmon_work, HZ / 25); > > + } > > + > > mutex_unlock(&data->lock); > > return data; > > } > > @@ -217,6 +271,8 @@ static int __devinit axp20_init_chip(struct > > axp_mfd_chip *chip) > > err = PTR_ERR(chip->hwmon_dev); > > goto exit_remove_files; > > } > > + wq_dev_arg = chip->dev; > > + wq = create_singlethread_workqueue("axp_hwmon_wq"); > > } else { > > dev_info(chip->dev, "AXP internal temperature monitoring > > disabled\n"); > > /* TODO enable it ?*/ > > diff --git a/include/linux/mfd/axp-mfd.h b/include/linux/mfd/axp-mfd.h > > index 1226d17..f6beb5b 100644 > > --- a/include/linux/mfd/axp-mfd.h > > +++ b/include/linux/mfd/axp-mfd.h > > @@ -136,6 +136,9 @@ struct axp_mfd_chip { > > s16 acin_voltage; /* range from 0 to 6962 mV */ > > s16 acin_current; /* range from 0 to 2559 mA */ > > s32 acin_power; > > + s32 acin_avg_voltage; > > + s32 acin_avg_current; > > + s32 acin_avg_power; > > unsigned long last_updated; /* in jiffies */ > > char valid; /* zero until following fields are valid */ > > struct device *hwmon_dev; > > > -- You received this message because you are subscribed to the Google Groups "linux-sunxi" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
