diff options
author | Timo Alho <talho@nvidia.com> | 2013-12-04 13:21:09 +0200 |
---|---|---|
committer | Juha Tukkinen <jtukkinen@nvidia.com> | 2013-12-09 23:40:27 -0800 |
commit | 9a7115eec8af605ea5df9ec089a1fa8f83b420e7 (patch) | |
tree | d47a0bf95f65712048cee3c05692560bdc633fb4 /drivers/edp | |
parent | cf5232f4a8b20f6bda0a653ab88970b3b231271f (diff) |
EDP: introduce ocpeaks table for consumers
ocpeaks table defines the maximum peak power for each state when
hardware overcurrent signal is asserted. The most prominent user for
overcurrent signaling is the modem consumer.
To register sysedp consumer for user space with overcurrent peak
information, following can be written to consumer_register sysfs
entry:
consumer_name a0, a1, a2, ..., an; b0, b1, b2, ..., bn
where ai and bi are nominal and overcurrent peak values for power
state i, respectively
Bug 1416849
Change-Id: I196aa976f8b2b0f300599db6807b94bf1a486f44
Signed-off-by: Timo Alho <talho@nvidia.com>
Reviewed-on: http://git-master/r/338237
Reviewed-by: Juha Tukkinen <jtukkinen@nvidia.com>
Tested-by: Juha Tukkinen <jtukkinen@nvidia.com>
Diffstat (limited to 'drivers/edp')
-rw-r--r-- | drivers/edp/sysedp_sysfs.c | 86 |
1 files changed, 69 insertions, 17 deletions
diff --git a/drivers/edp/sysedp_sysfs.c b/drivers/edp/sysedp_sysfs.c index 98669507820a..f471043d28fb 100644 --- a/drivers/edp/sysedp_sysfs.c +++ b/drivers/edp/sysedp_sysfs.c @@ -46,6 +46,23 @@ static ssize_t states_show(struct sysedp_consumer *c, char *s) return cnt; } +static ssize_t ocpeaks_show(struct sysedp_consumer *c, char *s) +{ + unsigned int i; + int cnt = 0; + unsigned int *p; + const int sz = sizeof(*p) * 3 + 2; + + p = c->ocpeaks ? c->ocpeaks : c->states; + + for (i = 0; i < c->num_states && (cnt + sz) < PAGE_SIZE; i++) + cnt += sprintf(s + cnt, "%s%u", i ? " " : "", p[i]); + + cnt += sprintf(s + cnt, "\n"); + return cnt; +} + + static ssize_t current_show(struct sysedp_consumer *c, char *s) { return sprintf(s, "%u\n", c->states[c->state]); @@ -77,11 +94,13 @@ static struct sysedp_consumer_attribute attr_state = __ATTR(state, 0660, state_show, state_store); static struct sysedp_consumer_attribute attr_states = __ATTR_RO(states); +static struct sysedp_consumer_attribute attr_ocpeaks = __ATTR_RO(ocpeaks); static struct attribute *consumer_attrs[] = { &attr_current.attr, &attr_state.attr, &attr_states.attr, + &attr_ocpeaks.attr, NULL }; @@ -169,9 +188,15 @@ static unsigned int *get_tokenized_data(const char *buf, unsigned int *tokenized_data; int err = -EINVAL; + if (!buf || *buf == 0) + goto err; + cp = buf; - while ((cp = strpbrk(cp + 1, ","))) - ntokens++; + while ((cp = strpbrk(cp + 1, ",;"))) + if (*cp == ';') + break; + else + ntokens++; tokenized_data = kmalloc(ntokens * sizeof(unsigned int), GFP_KERNEL); @@ -185,9 +210,8 @@ static unsigned int *get_tokenized_data(const char *buf, while (i < ntokens) { if (sscanf(cp, "%u", &tokenized_data[i++]) != 1) goto err_kfree; - - cp = strpbrk(cp, ","); - if (!cp) + cp = strpbrk(cp, ",;"); + if (!cp || *cp == ';') break; cp++; } @@ -208,9 +232,13 @@ err: static ssize_t consumer_register_store(const char *s, size_t count) { size_t name_len; - unsigned int *states; + unsigned int *states = 0; + unsigned int *ocpeaks = 0; unsigned int num_states; - struct sysedp_consumer *consumer; + unsigned int num_ocpeaks; + struct sysedp_consumer *consumer = 0; + const char *s2; + int err; name_len = strcspn(s, " \n"); if (name_len > SYSEDP_NAME_LEN-1) @@ -218,27 +246,48 @@ static ssize_t consumer_register_store(const char *s, size_t count) states = get_tokenized_data(s + name_len, &num_states); if (IS_ERR_OR_NULL(states)) - return -EINVAL; + return PTR_ERR(states); + + /* Parse for optional 2nd table (peak values) */ + s2 = strpbrk(s + name_len, ";"); + if (s2) { + ocpeaks = get_tokenized_data(s2 + 1, &num_ocpeaks); + if (IS_ERR_OR_NULL(ocpeaks)) { + err = PTR_ERR(ocpeaks); + ocpeaks = 0; + goto err_kfree; + } + if (num_states != num_ocpeaks) { + err = -EINVAL; + goto err_kfree; + } + + } consumer = kzalloc(sizeof(*consumer), GFP_KERNEL); - if (!consumer) { - kfree(states); - return -ENOMEM; + if (IS_ERR_OR_NULL(consumer)) { + err = PTR_ERR(consumer); + consumer = 0; + goto err_kfree; } memcpy(consumer->name, s, name_len); consumer->name[name_len] = 0; consumer->states = states; + consumer->ocpeaks = ocpeaks; consumer->num_states = num_states; consumer->removable = 1; - if (sysedp_register_consumer(consumer)) { - kfree(states); - kfree(consumer); - return -EINVAL; - } + err = sysedp_register_consumer(consumer); + if (err) + goto err_kfree; return count; +err_kfree: + kfree(states); + kfree(ocpeaks); + kfree(consumer); + return err; } static ssize_t consumer_unregister_store(const char *s, size_t count) @@ -258,8 +307,11 @@ static ssize_t consumer_unregister_store(const char *s, size_t count) if (!consumer->removable) return -EINVAL; + + sysedp_unregister_consumer(consumer); kfree(consumer->states); - sysedp_free_consumer(consumer); + kfree(consumer->ocpeaks); + kfree(consumer); return count; } |