Re: [PATCH v2 2/3] acpi: dptf_power: Add DPTF power participant

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Jun 23, 2016 at 5:42 AM, Srinivas Pandruvada
<srinivas.pandruvada@xxxxxxxxxxxxxxx> wrote:
> This driver adds support for Dynamic Platform and Thermal Framework
> (DPTF) Platform Power Participant device support.
> This participant is responsible for exposing platform telemetry such as
> platform Power, battery Information such as state of Charge, estimated
> maximum sustainable power (PMax), SMART battery spec information.
>
> This driver is implemented as a platform driver for INT3407 and presented
> as power_supply device. Since this has common features with the ACPI
> battery, existing interface provide by battery_common driver are reused
> to present as a battery power supply device.
>
> Since this driver will also register a battery power supply device,this
> driver will exit if CONFIG_ACPI_BATTERY is defined.
>
> There are two types of objects in INT3407:
> - Same as ACPI Battery objects: _BST and _BIX. These are exposed as
> standard power supply attributes.
> - Specific to INT3407, which are related to platform power
> There are some objects, for which it doesn't make sense to enhance
> power_supply class and add attributes there. They are represented as
> sysfs attribute under acpi device.

The below part of the changelog should really go to a doc under Documentation/.

> Here the bid for INT3407 is TPWR
> in the following example.
> /sys/class/power_supply/TPWR
> ├── alarm
> ├── capacity
> ├── capacity_level
> ├── cycle_count
> ├── device -> ../../../INT3407:00
> │   ├── dptf_power
> │   │   ├── adapter_rating
> │   │   ├── battery_steady_power
> │   │   ├── charger_type
> │   │   ├── max_platform_power
> │   │   ├── platform_power_source
> │   │   ├── power_sampling_period
>
> For example representing AC/adapter properties as a power_supply
> properties will not make sense for a battery device. In some case
> when there is an existing property, the meaning is different.
> For example charger_type has a equivalent power_supply property,
> which has different symantics than INT3407.
>
> ACPI methods description used in this driver:
> PSOC: Platform Battery State Of Charge as a percentage.
> PMAX: Maximum platform power that can be supported by the battery in mW.
> PSRC: System charge source,
>         0x00 = DC
>         0x01 = AC
>         0x02 = USB
>         0x03 = Wireless Charger
> ARTG: Adapter rating in mW (Maximum Adapter power) Must be 0 if no AC
>         Adaptor is plugged in.
> CTYP: Charger Type,
>         Traditional : 0x01
>         Hybrid: 0x02
>         NVDC: 0x03
> PBSS: Returns max sustained power for battery in milliWatts.
> DPSP: Sets the polling interval in 10ths of seconds. A value of 0 tells
>         the driver to use event notification for PMAX and PBSS
>
> Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@xxxxxxxxxxxxxxx>
> ---
>  drivers/acpi/Kconfig      |  17 +++++
>  drivers/acpi/Makefile     |   1 +
>  drivers/acpi/dptf_power.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 202 insertions(+)
>  create mode 100644 drivers/acpi/dptf_power.c
>
> diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
> index 27ae351..03a34b4 100644
> --- a/drivers/acpi/Kconfig
> +++ b/drivers/acpi/Kconfig
> @@ -526,4 +526,21 @@ config XPOWER_PMIC_OPREGION
>
>  endif
>
> +config DPTF_POWER
> +       tristate "DPTF Platform Power Participant"
> +       depends on X86
> +       select ACPI_BATTERY_COMMON
> +       select POWER_SUPPLY
> +       default y
> +       help
> +         This driver adds support for Dynamic Platform and Thermal Framework
> +         (DPTF) Platform Power Participant device support.
> +         This participant is responsible for exposing platform telemetry such
> +         as platform Power, battery Information such as state of Charge,
> +         estimated maximum sustainable power (PMax), SMART battery spec
> +         information.
> +
> +         To compile this driver as a module, choose M here:
> +         the module will be called dptf_power.
> +
>  endif  # ACPI
> diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
> index 950bf8e..1c76715 100644
> --- a/drivers/acpi/Makefile
> +++ b/drivers/acpi/Makefile
> @@ -75,6 +75,7 @@ obj-$(CONFIG_ACPI)            += acpi_memhotplug.o
>  obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o
>  obj-$(CONFIG_ACPI_BATTERY_COMMON) += battery_common.o
>  obj-$(CONFIG_ACPI_BATTERY)     += battery.o
> +obj-$(CONFIG_DPTF_POWER)       += dptf_power.o

Now that I think about it, maybe it would be better to put that into
drivers/platform/x86?

>  obj-$(CONFIG_ACPI_SBS)         += sbshc.o
>  obj-$(CONFIG_ACPI_SBS)         += sbs.o
>  obj-$(CONFIG_ACPI_HED)         += hed.o
> diff --git a/drivers/acpi/dptf_power.c b/drivers/acpi/dptf_power.c
> new file mode 100644
> index 0000000..013b7f3
> --- /dev/null
> +++ b/drivers/acpi/dptf_power.c
> @@ -0,0 +1,184 @@
> +/*
> + * dptf_power:  DPTF platform power driver
> + * Copyright (c) 2016, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/acpi.h>
> +#include <linux/platform_device.h>
> +#include "battery.h"
> +
> +#define DPTF_POWER_SHOW(name, object) \
> +static ssize_t name##_show(struct device *dev,\
> +                          struct device_attribute *attr,\
> +                          char *buf)\
> +{\
> +       struct acpi_device *acpi_dev = to_acpi_device(dev);\
> +       unsigned long long val;\
> +       acpi_status status;\
> +\
> +       status = acpi_evaluate_integer(acpi_dev->handle, #object,\
> +                                      NULL, &val);\
> +       if (ACPI_SUCCESS(status))\
> +               return sprintf(buf, "%llu\n", val);\
> +       else\
> +               return -EINVAL;\
> +}
> +
> +DPTF_POWER_SHOW(max_platform_power, PMAX)
> +DPTF_POWER_SHOW(platform_power_source, PSRC)
> +DPTF_POWER_SHOW(adapter_rating, ARTG)
> +DPTF_POWER_SHOW(charger_type, CTYP)
> +DPTF_POWER_SHOW(battery_steady_power, PBSS)
> +DPTF_POWER_SHOW(power_sampling_period, DPSP)
> +
> +
> +static DEVICE_ATTR_RO(max_platform_power);
> +static DEVICE_ATTR_RO(platform_power_source);
> +static DEVICE_ATTR_RO(adapter_rating);
> +static DEVICE_ATTR_RO(battery_steady_power);
> +static DEVICE_ATTR_RO(power_sampling_period);
> +static DEVICE_ATTR_RO(charger_type);
> +
> +static struct attribute *dptf_power_attrs[] = {
> +       &dev_attr_max_platform_power.attr,
> +       &dev_attr_platform_power_source.attr,
> +       &dev_attr_adapter_rating.attr,
> +       &dev_attr_charger_type.attr,
> +       &dev_attr_battery_steady_power.attr,
> +       &dev_attr_power_sampling_period.attr,
> +       NULL
> +};
> +
> +static struct attribute_group dptf_power_attribute_group = {
> +       .attrs = dptf_power_attrs,
> +       .name = "dptf_power"
> +};
> +
> +struct platform_device *dptf_power_pdev;
> +
> +static void dptf_power_notify(acpi_handle handle, u32 event, void *data)
> +{
> +       struct acpi_device *device = data;
> +
> +       acpi_battery_common_notify(device, event);
> +}
> +
> +static int dptf_power_init(struct platform_device *pdev)
> +{
> +       struct acpi_device *acpi_dev;
> +       acpi_status status;
> +       unsigned long long ptype;
> +       int result;
> +
> +       acpi_dev = ACPI_COMPANION(&(pdev->dev));
> +       if (!acpi_dev)
> +               return -ENODEV;

Since acpi_battery is an ACPI driver, it will bind to acpi_dev
directly, so I guess this should check if there's a driver bound to
acpi_dev and bail out if so, shouldn't it?

> +
> +       status = acpi_evaluate_integer(acpi_dev->handle, "PTYP", NULL, &ptype);
> +       if (ACPI_FAILURE(status))
> +               return -ENODEV;
> +
> +       if (ptype != 0x11)
> +               return -ENODEV;
> +
> +
> +       result = acpi_battery_common_add(acpi_dev);
> +       if (result)
> +               return result;
> +
> +       result = sysfs_create_group(&acpi_dev->dev.kobj,
> +                                   &dptf_power_attribute_group);
> +       if (result)
> +               goto error_remove_battery;
> +
> +       result = acpi_install_notify_handler(acpi_dev->handle,
> +                                            ACPI_DEVICE_NOTIFY,
> +                                            dptf_power_notify,
> +                                            (void *)acpi_dev);
> +       if (result)
> +               goto error_remove_sysfs;
> +
> +       platform_set_drvdata(pdev, acpi_dev);
> +
> +       return 0;
> +
> +error_remove_sysfs:
> +       sysfs_remove_group(&acpi_dev->dev.kobj, &dptf_power_attribute_group);
> +error_remove_battery:
> +       acpi_battery_common_remove(acpi_dev);
> +
> +       return result;
> +}
> +
> +static void dptf_power_init_work_fn(struct work_struct *work)
> +{
> +       if (!battery_registered)
> +               dptf_power_init(dptf_power_pdev);
> +}
> +
> +static DECLARE_DELAYED_WORK(dptf_power_init_work, dptf_power_init_work_fn);
> +
> +static int dptf_power_add(struct platform_device *pdev)
> +{
> +       int ret = 0;
> +
> +#if IS_ENABLED(CONFIG_ACPI_BATTERY)
> +       /* Wait for battery driver to initialize and register for 100ms */

Do we really need to wait?  It looks like acpi_battery would be a
fallback driver for this one, so why wait?

> +       dptf_power_pdev = pdev;
> +       schedule_delayed_work(&dptf_power_init_work, msecs_to_jiffies(100));
> +#else
> +       ret = dptf_power_init(pdev);
> +#endif
> +       return ret;
> +}
> +
> +static int dptf_power_remove(struct platform_device *pdev)
> +{
> +       struct acpi_device *acpi_dev = platform_get_drvdata(pdev);
> +
> +#if defined(CONFIG_ACPI_BATTERY)
> +       cancel_delayed_work_sync(&dptf_power_init_work);
> +#endif
> +       if (!acpi_dev)
> +               return 0;
> +
> +       acpi_remove_notify_handler(acpi_dev->handle, ACPI_DEVICE_NOTIFY,
> +                                  dptf_power_notify);
> +       sysfs_remove_group(&acpi_dev->dev.kobj, &dptf_power_attribute_group);
> +       acpi_battery_common_remove(acpi_dev);
> +
> +       return 0;
> +}
> +
> +static const struct acpi_device_id int3407_device_ids[] = {
> +       {"INT3407", 0},
> +       {"", 0},
> +};
> +MODULE_DEVICE_TABLE(acpi, int3407_device_ids);
> +
> +static struct platform_driver dptf_power_driver = {
> +       .probe = dptf_power_add,
> +       .remove = dptf_power_remove,
> +       .driver = {
> +               .name = "DPTF Platform Power",
> +               .acpi_match_table = int3407_device_ids,
> +       },
> +};
> +
> +module_platform_driver(dptf_power_driver);
> +
> +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@xxxxxxxxxxxxxxx>");
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("ACPI DPTF platform power driver");
> --
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux