* [PATCH 3/5] charger-manager: Add support sysfs entry for charger
@ 2012-08-21 8:06 Chanwoo Choi
2012-09-21 5:12 ` Anton Vorontsov
0 siblings, 1 reply; 3+ messages in thread
From: Chanwoo Choi @ 2012-08-21 8:06 UTC (permalink / raw)
To: anton.vorontsov
Cc: cbouatmailru, jenny.tc, ramakrishna.pallala, myungjoo.ham,
kyungmin.park, linux-kernel, Chanwoo Choi
This patch add support sysfs entry for each charger(regulator).
Charger-manager use one or more chargers for charging battery but
some charger isn't necessary on specific scenario. So, if some charger
isn't needed, can disable specific charger through 'externally_control'
entry while system is on state and confirm the information(name, state)
of charger.
the list of added sysfs entry
- /sys/class/power_supply/battery/chargers/charger.[index]/name
: show name of charger(regulator)
- /sys/class/power_supply/battery/chargers/charger.[index]/state
: show either enabled or disabled state of charger
- /sys/class/power_supply/battery/chargers/charger.[index]/externally_control
If 'externally_control' of specific charger is 1, Charger-manager cannot enable
regulator for charging when charger cable is attached and charger must be
maintained with disabled state. If 'externally_control' is zero, Charger-manager
usually can control to enable/disable regulator.
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Myungjoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
drivers/power/charger-manager.c | 172 +++++++++++++++++++++++++++++++++
include/linux/power/charger-manager.h | 19 ++++
2 files changed, 191 insertions(+), 0 deletions(-)
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index bee010e..33cc3f6 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -22,6 +22,7 @@
#include <linux/platform_device.h>
#include <linux/power/charger-manager.h>
#include <linux/regulator/consumer.h>
+#include <linux/sysfs.h>
static const char * const default_event_names[] = {
[CM_EVENT_UNKNOWN] = "Unknown",
@@ -272,6 +273,9 @@ static int try_charger_enable(struct charger_manager *cm, bool enable)
if (cm->emergency_stop)
return -EAGAIN;
for (i = 0 ; i < desc->num_charger_regulators ; i++) {
+ if (desc->charger_regulators[i].externally_control)
+ continue;
+
err = regulator_enable(
desc->charger_regulators[i].consumer);
if (err < 0) {
@@ -282,6 +286,9 @@ static int try_charger_enable(struct charger_manager *cm, bool enable)
}
} else {
for (i = 0 ; i < desc->num_charger_regulators ; i++) {
+ if (desc->charger_regulators[i].externally_control)
+ continue;
+
err = regulator_disable(
desc->charger_regulators[i].consumer);
if (err < 0) {
@@ -1088,12 +1095,101 @@ static int charger_extcon_init(struct charger_manager *cm,
return ret;
}
+/* help function of sysfs node to control charger(regulator) */
+static ssize_t charger_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct charger_regulator *charger
+ = container_of(attr, struct charger_regulator, attr_name);
+ return sprintf(buf, "%s\n", charger->regulator_name);
+}
+
+static ssize_t charger_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct charger_regulator *charger
+ = container_of(attr, struct charger_regulator, attr_state);
+ int state = 1;
+
+ if (charger->externally_control)
+ state = 0;
+ else
+ state = regulator_is_enabled(charger->consumer);
+
+ return sprintf(buf, "%s\n", state ? "enabled" : "disabled");
+}
+
+static ssize_t charger_externally_control_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct charger_regulator *charger = container_of(attr,
+ struct charger_regulator, attr_externally_control);
+ return sprintf(buf, "%d\n", charger->externally_control);
+}
+
+static ssize_t charger_externally_control_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct charger_regulator *charger
+ = container_of(attr, struct charger_regulator,
+ attr_externally_control);
+ struct charger_manager *cm = charger->cm;
+ struct charger_desc *desc = cm->desc;
+ int i, ret;
+ int externally_control;
+
+ ret = sscanf(buf, "%d", &externally_control);
+ if (ret == 0) {
+ ret = -EINVAL;
+ return ret;
+ }
+
+ if (externally_control) {
+ int chargers_externally_control = 1;
+
+ for (i = 0 ; i < desc->num_charger_regulators ; i++) {
+ if ((&desc->charger_regulators[i] != charger)
+ && !desc->charger_regulators[i].externally_control) {
+ /*
+ * At least, one charger is controlled by
+ * charger-manager
+ */
+ chargers_externally_control = 0;
+ break;
+ }
+ }
+
+ if (!chargers_externally_control) {
+ if (cm->charger_enabled) {
+ try_charger_enable(charger->cm, false);
+ charger->externally_control
+ = externally_control;
+ try_charger_enable(charger->cm, true);
+ } else
+ charger->externally_control
+ = externally_control;
+
+ } else {
+ dev_warn(cm->dev,
+ "\'%s\' regulator should be controlled "
+ "in charger-manager because charger-manager "
+ "must need at least one charger for charging\n",
+ charger->regulator_name);
+ }
+ } else
+ charger->externally_control = externally_control;
+
+ return count;
+}
+
static int charger_manager_probe(struct platform_device *pdev)
{
struct charger_desc *desc = dev_get_platdata(&pdev->dev);
struct charger_manager *cm;
int ret = 0, i = 0;
int j = 0;
+ int chargers_externally_control = 1;
union power_supply_propval val;
if (g_desc && !rtc_dev && g_desc->rtc_name) {
@@ -1265,6 +1361,8 @@ static int charger_manager_probe(struct platform_device *pdev)
for (i = 0 ; i < desc->num_charger_regulators ; i++) {
struct charger_regulator *charger
= &desc->charger_regulators[i];
+ char buf[11];
+ char *str;
charger->consumer = regulator_get(&pdev->dev,
charger->regulator_name);
@@ -1274,6 +1372,7 @@ static int charger_manager_probe(struct platform_device *pdev)
ret = -EINVAL;
goto err_chg_get;
}
+ charger->cm = cm;
for (j = 0 ; j < charger->num_cables ; j++) {
struct charger_cable *cable = &charger->cables[j];
@@ -1287,6 +1386,71 @@ static int charger_manager_probe(struct platform_device *pdev)
cable->charger = charger;
cable->cm = cm;
}
+
+ /* Create sysfs entry to control charger(regulator) */
+ snprintf(buf, 10, "charger.%d", i);
+ str = kzalloc(sizeof(char) * (strlen(buf) + 1), GFP_KERNEL);
+ if (!str) {
+ for (i--; i >= 0; i--) {
+ charger = &desc->charger_regulators[i];
+ kfree(charger->attr_g.name);
+ }
+ ret = -ENOMEM;
+
+ goto err_extcon;
+ }
+ strcpy(str, buf);
+
+ charger->attrs[0] = &charger->attr_name.attr;
+ charger->attrs[1] = &charger->attr_state.attr;
+ charger->attrs[2] = &charger->attr_externally_control.attr;
+ charger->attrs[3] = NULL;
+ charger->attr_g.name = str;
+ charger->attr_g.attrs = charger->attrs;
+
+ sysfs_attr_init(&cable->attr_name.attr);
+ charger->attr_name.attr.name = "name";
+ charger->attr_name.attr.mode = 0444;
+ charger->attr_name.show = charger_name_show;
+
+ sysfs_attr_init(&cable->attr_state.attr);
+ charger->attr_state.attr.name = "state";
+ charger->attr_state.attr.mode = 0444;
+ charger->attr_state.show = charger_state_show;
+
+ sysfs_attr_init(&cable->attr_externally_control.attr);
+ charger->attr_externally_control.attr.name
+ = "externally_control";
+ charger->attr_externally_control.attr.mode = 0644;
+ charger->attr_externally_control.show
+ = charger_externally_control_show;
+ charger->attr_externally_control.store
+ = charger_externally_control_store;
+
+ if (!desc->charger_regulators[i].externally_control
+ || !chargers_externally_control) {
+ chargers_externally_control = 0;
+ }
+ dev_info(&pdev->dev, "\'%s\' regulator's externally_control"
+ "is %d\n", charger->regulator_name,
+ charger->externally_control);
+
+ ret = sysfs_create_group(&cm->charger_psy.dev->kobj,
+ &charger->attr_g);
+ if (ret < 0) {
+ dev_info(&pdev->dev, "Cannot create sysfs entry"
+ "of %s regulator\n",
+ charger->regulator_name);
+ }
+ }
+
+ if (chargers_externally_control) {
+ dev_err(&pdev->dev, "Cannot register regulator because "
+ "charger-manager must need at least "
+ "one charger for charging battery\n");
+
+ ret = -EINVAL;
+ goto err_chg_enable;
}
ret = try_charger_enable(cm, true);
@@ -1312,6 +1476,14 @@ static int charger_manager_probe(struct platform_device *pdev)
return 0;
err_chg_enable:
+ for (i = 0 ; i < desc->num_charger_regulators ; i++) {
+ struct charger_regulator *charger
+ = &desc->charger_regulators[i];
+ charger = &desc->charger_regulators[i];
+ sysfs_remove_group(&cm->charger_psy.dev->kobj,
+ &charger->attr_g);
+ kfree(charger->attr_g.name);
+ }
err_extcon:
for (i = 0 ; i < desc->num_charger_regulators ; i++) {
struct charger_regulator *charger
diff --git a/include/linux/power/charger-manager.h b/include/linux/power/charger-manager.h
index 7d7b90f..afeff17 100644
--- a/include/linux/power/charger-manager.h
+++ b/include/linux/power/charger-manager.h
@@ -109,24 +109,43 @@ struct charger_cable {
* struct charger_regulator
* @regulator_name: the name of regulator for using charger.
* @consumer: the regulator consumer for the charger.
+ * @externally_control:
+ * Set if the charger-manager cannot control charger,
+ * the charger will be maintained with disabled state.
* @cables:
* the array of charger cables to enable/disable charger
* and set current limit according to constratint data of
* struct charger_cable if only charger cable included
* in the array of charger cables is attached/detached.
* @num_cables: the number of charger cables.
+ * @attr_g: Attribute group for the charger(regulator)
+ * @attr_name: "name" sysfs entry
+ * @attr_state: "state" sysfs entry
+ * @attr_externally_control: "externally_control" sysfs entry
+ * @attrs: Arrays pointing to attr_name/state/externally_control for attr_g
*/
struct charger_regulator {
/* The name of regulator for charging */
const char *regulator_name;
struct regulator *consumer;
+ /* charger never on when system is on */
+ int externally_control;
+
/*
* Store constraint information related to current limit,
* each cable have different condition for charging.
*/
struct charger_cable *cables;
int num_cables;
+
+ struct attribute_group attr_g;
+ struct device_attribute attr_name;
+ struct device_attribute attr_state;
+ struct device_attribute attr_externally_control;
+ struct attribute *attrs[4];
+
+ struct charger_manager *cm;
};
/**
--
1.7.0.4
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH 3/5] charger-manager: Add support sysfs entry for charger
2012-08-21 8:06 [PATCH 3/5] charger-manager: Add support sysfs entry for charger Chanwoo Choi
@ 2012-09-21 5:12 ` Anton Vorontsov
2012-09-21 7:25 ` Chanwoo Choi
0 siblings, 1 reply; 3+ messages in thread
From: Anton Vorontsov @ 2012-09-21 5:12 UTC (permalink / raw)
To: Chanwoo Choi
Cc: jenny.tc, ramakrishna.pallala, myungjoo.ham, kyungmin.park,
linux-kernel
On Tue, Aug 21, 2012 at 05:06:49PM +0900, Chanwoo Choi wrote:
> This patch add support sysfs entry for each charger(regulator).
> Charger-manager use one or more chargers for charging battery but
> some charger isn't necessary on specific scenario. So, if some charger
> isn't needed, can disable specific charger through 'externally_control'
> entry while system is on state and confirm the information(name, state)
> of charger.
>
> the list of added sysfs entry
> - /sys/class/power_supply/battery/chargers/charger.[index]/name
> : show name of charger(regulator)
> - /sys/class/power_supply/battery/chargers/charger.[index]/state
> : show either enabled or disabled state of charger
> - /sys/class/power_supply/battery/chargers/charger.[index]/externally_control
The API looks sane.
For the future, you might want to get rid of the 'name', and instead
just point to a regulator device (via a sysfs symlink). I.e.
/sys/class/power_supply/battery/chargers/charger.[index]/device
would be a symlink to the regulator device.
But for the time being, I guess it's OK as is (although I wouldn't
mind if it'll use the symlink from the start. :-)
[...]
> for (j = 0 ; j < charger->num_cables ; j++) {
> struct charger_cable *cable = &charger->cables[j];
> @@ -1287,6 +1386,71 @@ static int charger_manager_probe(struct platform_device *pdev)
> cable->charger = charger;
> cable->cm = cm;
> }
> +
[...]
> + charger->attr_g.attrs = charger->attrs;
> +
> + sysfs_attr_init(&cable->attr_name.attr);
Notice that 'cable' is declared in the 'for' loop above,
so this doesn't compile for me:
CHECK drivers/power/charger-manager.c
drivers/power/charger-manager.c:1559:17: error: undefined identifier 'cable'
drivers/power/charger-manager.c:1564:17: error: undefined identifier 'cable'
drivers/power/charger-manager.c:1569:17: error: undefined identifier 'cable'
CC drivers/power/charger-manager.o
drivers/power/charger-manager.c: In function ‘charger_manager_probe’:
drivers/power/charger-manager.c:1559:3: error: ‘cable’ undeclared (first use in this function)
drivers/power/charger-manager.c:1559:3: note: each undeclared identifier is reported only once for each function it appears in
make[1]: *** [drivers/power/charger-manager.o] Error 1
Also:
- Please adhere to the codingstyle, there should be no spaces
before ';' in the for loop statement.
- If possible, please consider splitting _probe routine, it is more
than 300 lines long nowadays.
Thanks,
Anton.
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH 3/5] charger-manager: Add support sysfs entry for charger
2012-09-21 5:12 ` Anton Vorontsov
@ 2012-09-21 7:25 ` Chanwoo Choi
0 siblings, 0 replies; 3+ messages in thread
From: Chanwoo Choi @ 2012-09-21 7:25 UTC (permalink / raw)
To: Anton Vorontsov
Cc: jenny.tc, ramakrishna.pallala, myungjoo.ham, kyungmin.park,
linux-kernel
On 09/21/2012 02:12 PM, Anton Vorontsov wrote:
> On Tue, Aug 21, 2012 at 05:06:49PM +0900, Chanwoo Choi wrote:
>> This patch add support sysfs entry for each charger(regulator).
>> Charger-manager use one or more chargers for charging battery but
>> some charger isn't necessary on specific scenario. So, if some charger
>> isn't needed, can disable specific charger through 'externally_control'
>> entry while system is on state and confirm the information(name, state)
>> of charger.
>>
>> the list of added sysfs entry
>> - /sys/class/power_supply/battery/chargers/charger.[index]/name
>> : show name of charger(regulator)
>> - /sys/class/power_supply/battery/chargers/charger.[index]/state
>> : show either enabled or disabled state of charger
>> - /sys/class/power_supply/battery/chargers/charger.[index]/externally_control
>
> The API looks sane.
>
> For the future, you might want to get rid of the 'name', and instead
> just point to a regulator device (via a sysfs symlink). I.e.
>
> /sys/class/power_supply/battery/chargers/charger.[index]/device
> would be a symlink to the regulator device.
>
> But for the time being, I guess it's OK as is (although I wouldn't
> mind if it'll use the symlink from the start. :-)
OK, as your said, I will modify sysfs entry for charger(regulator) by
linking sysfs
of regulator device.
>
> [...]
>> for (j = 0 ; j < charger->num_cables ; j++) {
>> struct charger_cable *cable = &charger->cables[j];
>> @@ -1287,6 +1386,71 @@ static int charger_manager_probe(struct platform_device *pdev)
>> cable->charger = charger;
>> cable->cm = cm;
>> }
>> +
> [...]
>> + charger->attr_g.attrs = charger->attrs;
>> +
>> + sysfs_attr_init(&cable->attr_name.attr);
>
> Notice that 'cable' is declared in the 'for' loop above,
> so this doesn't compile for me:
>
> CHECK drivers/power/charger-manager.c
> drivers/power/charger-manager.c:1559:17: error: undefined identifier 'cable'
> drivers/power/charger-manager.c:1564:17: error: undefined identifier 'cable'
> drivers/power/charger-manager.c:1569:17: error: undefined identifier 'cable'
> CC drivers/power/charger-manager.o
> drivers/power/charger-manager.c: In function ‘charger_manager_probe’:
> drivers/power/charger-manager.c:1559:3: error: ‘cable’ undeclared (first use in this function)
> drivers/power/charger-manager.c:1559:3: note: each undeclared identifier is reported only once for each function it appears in
> make[1]: *** [drivers/power/charger-manager.o] Error 1
>
I will fix it.
> Also:
> - Please adhere to the codingstyle, there should be no spaces
> before ';' in the for loop statement.
> - If possible, please consider splitting _probe routine, it is more
> than 300 lines long nowadays.
>
I resend soon patch which fix build break. As you said, I will modify
sysfs entry
for charger(regulator) by linking sysfs of regulator device and split _probe
routine.
Thanks for your comment.
Best Regards,
Chanwoo Choi
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2012-09-21 7:25 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-21 8:06 [PATCH 3/5] charger-manager: Add support sysfs entry for charger Chanwoo Choi
2012-09-21 5:12 ` Anton Vorontsov
2012-09-21 7:25 ` Chanwoo Choi
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.