On Sun, 7 Apr 2019 18:52:34 +0200 Sebastian Reichel <sre@xxxxxxxxxx> wrote: > Hi, > > On Sun, Mar 24, 2019 at 03:31:37PM +0000, Jonathan Cameron wrote: > > On Sat, 23 Mar 2019 18:28:09 +0100 > > Artur Rojek <contact@xxxxxxxxxxxxxx> wrote: > > > > > Add a driver for battery present on Ingenic JZ47xx SoCs. > > > > > > Signed-off-by: Artur Rojek <contact@xxxxxxxxxxxxxx> > > The IIO parts look fine to me. > > Reviewed-by: Jonathan Cameron <Jonathan.Cameron@xxxxxxxxxx> > > > > Sebastian, assuming you are happy with this version, > > The driver itself looks ok. I'm a bit unhappy, that we already have > jz4740-battery. This driver is much cleaner, but does not yet seem > to be ready to replace it. Artur Rojek what are your plans regarding > to the existing driver? Is there currently work going on migrating > JZ47xx to DT? > > > do you have any preference for how we handle this series? > > > > Probably needs one of us to do an immutable branch with just this > > in it. I'm happy to do so once all the relevant Acks etc are in > > place, but don't mind if you want to! > > I suppose you could provide an immutable branch with just the first > two patches in it. Then I can pull it and apply the power-supply > patches on top. Done. ib-jz47xx-battery-prereq branch of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git which is based on v5.0 I'll pull that into the togreg branch of iio.git shortly. Thanks, Jonathan > > -- Sebastian > > > Thanks, > > > > Jonathan > > > > > --- > > > > > > Changes: > > > > > > v2: - rework the return logic in ingenic_battery_get_property, > > > - make index offsets point forward in ingenic_battery_set_scale, > > > - fix spacing around scale_raw[best_idx + 1] > > > > > > drivers/power/supply/Kconfig | 11 ++ > > > drivers/power/supply/Makefile | 1 + > > > drivers/power/supply/ingenic-battery.c | 180 +++++++++++++++++++++++++ > > > 3 files changed, 192 insertions(+) > > > create mode 100644 drivers/power/supply/ingenic-battery.c > > > > > > diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig > > > index e901b9879e7e..9bfb1637ec28 100644 > > > --- a/drivers/power/supply/Kconfig > > > +++ b/drivers/power/supply/Kconfig > > > @@ -169,6 +169,17 @@ config BATTERY_COLLIE > > > Say Y to enable support for the battery on the Sharp Zaurus > > > SL-5500 (collie) models. > > > > > > +config BATTERY_INGENIC > > > + tristate "Ingenic JZ47xx SoCs battery driver" > > > + depends on MIPS || COMPILE_TEST > > > + depends on INGENIC_ADC > > > + help > > > + Choose this option if you want to monitor battery status on > > > + Ingenic JZ47xx SoC based devices. > > > + > > > + This driver can also be built as a module. If so, the module will be > > > + called ingenic-battery. > > > + > > > config BATTERY_IPAQ_MICRO > > > tristate "iPAQ Atmel Micro ASIC battery driver" > > > depends on MFD_IPAQ_MICRO > > > diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile > > > index b731c2a9b695..9e2c481d0187 100644 > > > --- a/drivers/power/supply/Makefile > > > +++ b/drivers/power/supply/Makefile > > > @@ -34,6 +34,7 @@ obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o > > > obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o > > > obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o > > > obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o > > > +obj-$(CONFIG_BATTERY_INGENIC) += ingenic-battery.o > > > obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o > > > obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o > > > obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o > > > diff --git a/drivers/power/supply/ingenic-battery.c b/drivers/power/supply/ingenic-battery.c > > > new file mode 100644 > > > index 000000000000..822aee1c7b64 > > > --- /dev/null > > > +++ b/drivers/power/supply/ingenic-battery.c > > > @@ -0,0 +1,180 @@ > > > +// SPDX-License-Identifier: GPL-2.0 > > > +/* > > > + * Battery driver for the Ingenic JZ47xx SoCs > > > + * Copyright (c) 2019 Artur Rojek <contact@xxxxxxxxxxxxxx> > > > + * > > > + * based on drivers/power/supply/jz4740-battery.c > > > + */ > > > + > > > +#include <linux/iio/consumer.h> > > > +#include <linux/module.h> > > > +#include <linux/of.h> > > > +#include <linux/platform_device.h> > > > +#include <linux/power_supply.h> > > > +#include <linux/property.h> > > > + > > > +struct ingenic_battery { > > > + struct device *dev; > > > + struct iio_channel *channel; > > > + struct power_supply_desc desc; > > > + struct power_supply *battery; > > > + struct power_supply_battery_info info; > > > +}; > > > + > > > +static int ingenic_battery_get_property(struct power_supply *psy, > > > + enum power_supply_property psp, > > > + union power_supply_propval *val) > > > +{ > > > + struct ingenic_battery *bat = power_supply_get_drvdata(psy); > > > + struct power_supply_battery_info *info = &bat->info; > > > + int ret; > > > + > > > + switch (psp) { > > > + case POWER_SUPPLY_PROP_HEALTH: > > > + ret = iio_read_channel_processed(bat->channel, &val->intval); > > > + val->intval *= 1000; > > > + if (val->intval < info->voltage_min_design_uv) > > > + val->intval = POWER_SUPPLY_HEALTH_DEAD; > > > + else if (val->intval > info->voltage_max_design_uv) > > > + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; > > > + else > > > + val->intval = POWER_SUPPLY_HEALTH_GOOD; > > > + return ret; > > > + case POWER_SUPPLY_PROP_VOLTAGE_NOW: > > > + ret = iio_read_channel_processed(bat->channel, &val->intval); > > > + val->intval *= 1000; > > > + return ret; > > > + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: > > > + val->intval = info->voltage_min_design_uv; > > > + return 0; > > > + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: > > > + val->intval = info->voltage_max_design_uv; > > > + return 0; > > > + default: > > > + return -EINVAL; > > > + }; > > > +} > > > + > > > +/* Set the most appropriate IIO channel voltage reference scale > > > + * based on the battery's max voltage. > > > + */ > > > +static int ingenic_battery_set_scale(struct ingenic_battery *bat) > > > +{ > > > + const int *scale_raw; > > > + int scale_len, scale_type, best_idx = -1, best_mV, max_raw, i, ret; > > > + u64 max_mV; > > > + > > > + ret = iio_read_max_channel_raw(bat->channel, &max_raw); > > > + if (ret) { > > > + dev_err(bat->dev, "Unable to read max raw channel value\n"); > > > + return ret; > > > + } > > > + > > > + ret = iio_read_avail_channel_attribute(bat->channel, &scale_raw, > > > + &scale_type, &scale_len, > > > + IIO_CHAN_INFO_SCALE); > > > + if (ret < 0) { > > > + dev_err(bat->dev, "Unable to read channel avail scale\n"); > > > + return ret; > > > + } > > > + if (ret != IIO_AVAIL_LIST || scale_type != IIO_VAL_FRACTIONAL_LOG2) > > > + return -EINVAL; > > > + > > > + max_mV = bat->info.voltage_max_design_uv / 1000; > > > + > > > + for (i = 0; i < scale_len; i += 2) { > > > + u64 scale_mV = (max_raw * scale_raw[i]) >> scale_raw[i + 1]; > > > + > > > + if (scale_mV < max_mV) > > > + continue; > > > + > > > + if (best_idx >= 0 && scale_mV > best_mV) > > > + continue; > > > + > > > + best_mV = scale_mV; > > > + best_idx = i; > > > + } > > > + > > > + if (best_idx < 0) { > > > + dev_err(bat->dev, "Unable to find matching voltage scale\n"); > > > + return -EINVAL; > > > + } > > > + > > > + return iio_write_channel_attribute(bat->channel, > > > + scale_raw[best_idx], > > > + scale_raw[best_idx + 1], > > > + IIO_CHAN_INFO_SCALE); > > > +} > > > + > > > +static enum power_supply_property ingenic_battery_properties[] = { > > > + POWER_SUPPLY_PROP_HEALTH, > > > + POWER_SUPPLY_PROP_VOLTAGE_NOW, > > > + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, > > > + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, > > > +}; > > > + > > > +static int ingenic_battery_probe(struct platform_device *pdev) > > > +{ > > > + struct device *dev = &pdev->dev; > > > + struct ingenic_battery *bat; > > > + struct power_supply_config psy_cfg = {}; > > > + struct power_supply_desc *desc; > > > + int ret; > > > + > > > + bat = devm_kzalloc(dev, sizeof(*bat), GFP_KERNEL); > > > + if (!bat) > > > + return -ENOMEM; > > > + > > > + bat->dev = dev; > > > + bat->channel = devm_iio_channel_get(dev, "battery"); > > > + if (IS_ERR(bat->channel)) > > > + return PTR_ERR(bat->channel); > > > + > > > + desc = &bat->desc; > > > + desc->name = "jz-battery"; > > > + desc->type = POWER_SUPPLY_TYPE_BATTERY; > > > + desc->properties = ingenic_battery_properties; > > > + desc->num_properties = ARRAY_SIZE(ingenic_battery_properties); > > > + desc->get_property = ingenic_battery_get_property; > > > + psy_cfg.drv_data = bat; > > > + psy_cfg.of_node = dev->of_node; > > > + > > > + bat->battery = devm_power_supply_register(dev, desc, &psy_cfg); > > > + if (IS_ERR(bat->battery)) { > > > + dev_err(dev, "Unable to register battery\n"); > > > + return PTR_ERR(bat->battery); > > > + } > > > + > > > + ret = power_supply_get_battery_info(bat->battery, &bat->info); > > > + if (ret) { > > > + dev_err(dev, "Unable to get battery info: %d\n", ret); > > > + return ret; > > > + } > > > + if (bat->info.voltage_min_design_uv < 0) { > > > + dev_err(dev, "Unable to get voltage min design\n"); > > > + return bat->info.voltage_min_design_uv; > > > + } > > > + if (bat->info.voltage_max_design_uv < 0) { > > > + dev_err(dev, "Unable to get voltage max design\n"); > > > + return bat->info.voltage_max_design_uv; > > > + } > > > + > > > + return ingenic_battery_set_scale(bat); > > > +} > > > + > > > +#ifdef CONFIG_OF > > > +static const struct of_device_id ingenic_battery_of_match[] = { > > > + { .compatible = "ingenic,jz4740-battery", }, > > > + { }, > > > +}; > > > +MODULE_DEVICE_TABLE(of, ingenic_battery_of_match); > > > +#endif > > > + > > > +static struct platform_driver ingenic_battery_driver = { > > > + .driver = { > > > + .name = "ingenic-battery", > > > + .of_match_table = of_match_ptr(ingenic_battery_of_match), > > > > I guess we can be fairly sure no one will even user this with ACPI > > (magic DT) bindings? That would make this a rare case where the > > of_match_pr protection and ifdef fun is still fine. > > > > > > > + }, > > > + .probe = ingenic_battery_probe, > > > +}; > > > +module_platform_driver(ingenic_battery_driver); > >