cregit-Linux how code gets into the kernel

Release 4.11 drivers/staging/nvec/nvec_power.c

/*
 * nvec_power: power supply driver for a NVIDIA compliant embedded controller
 *
 * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.launchpad.net>
 *
 * Authors:  Ilya Petrov <ilya.muromec@gmail.com>
 *           Marc Dietrich <marvin24@gmx.de>
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 */

#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/delay.h>

#include "nvec.h"


#define GET_SYSTEM_STATUS 0x00


struct nvec_power {
	
struct notifier_block notifier;
	
struct delayed_work poller;
	
struct nvec_chip *nvec;
	
int on;
	
int bat_present;
	
int bat_status;
	
int bat_voltage_now;
	
int bat_current_now;
	
int bat_current_avg;
	
int time_remain;
	
int charge_full_design;
	
int charge_last_full;
	
int critical_capacity;
	
int capacity_remain;
	
int bat_temperature;
	
int bat_cap;
	
int bat_type_enum;
	
char bat_manu[30];
	
char bat_model[30];
	
char bat_type[30];
};

enum {
	
SLOT_STATUS,
	
VOLTAGE,
	
TIME_REMAINING,
	
CURRENT,
	
AVERAGE_CURRENT,
	
AVERAGING_TIME_INTERVAL,
	
CAPACITY_REMAINING,
	
LAST_FULL_CHARGE_CAPACITY,
	
DESIGN_CAPACITY,
	
CRITICAL_CAPACITY,
	
TEMPERATURE,
	
MANUFACTURER,
	
MODEL,
	
TYPE,
};

enum {
	
AC,
	
BAT,
};


struct bat_response {
	
u8 event_type;
	
u8 length;
	
u8 sub_type;
	
u8 status;
	/* payload */
	union {
		
char plc[30];
		
u16 plu;
		
s16 pls;
	};
};


static struct power_supply *nvec_bat_psy;

static struct power_supply *nvec_psy;


static int nvec_power_notifier(struct notifier_block *nb, unsigned long event_type, void *data) { struct nvec_power *power = container_of(nb, struct nvec_power, notifier); struct bat_response *res = data; if (event_type != NVEC_SYS) return NOTIFY_DONE; if (res->sub_type == 0) { if (power->on != res->plu) { power->on = res->plu; power_supply_changed(nvec_psy); } return NOTIFY_STOP; } return NOTIFY_OK; }

Contributors

PersonTokensPropCommitsCommitProp
Marc Dietrich91100.00%1100.00%
Total91100.00%1100.00%

static const int bat_init[] = { LAST_FULL_CHARGE_CAPACITY, DESIGN_CAPACITY, CRITICAL_CAPACITY, MANUFACTURER, MODEL, TYPE, };
static void get_bat_mfg_data(struct nvec_power *power) { int i; char buf[] = { NVEC_BAT, SLOT_STATUS }; for (i = 0; i < ARRAY_SIZE(bat_init); i++) { buf[1] = bat_init[i]; nvec_write_async(power->nvec, buf, 2); } }

Contributors

PersonTokensPropCommitsCommitProp
Marc Dietrich63100.00%2100.00%
Total63100.00%2100.00%


static int nvec_power_bat_notifier(struct notifier_block *nb, unsigned long event_type, void *data) { struct nvec_power *power = container_of(nb, struct nvec_power, notifier); struct bat_response *res = data; int status_changed = 0; if (event_type != NVEC_BAT) return NOTIFY_DONE; switch (res->sub_type) { case SLOT_STATUS: if (res->plc[0] & 1) { if (power->bat_present == 0) { status_changed = 1; get_bat_mfg_data(power); } power->bat_present = 1; switch ((res->plc[0] >> 1) & 3) { case 0: power->bat_status = POWER_SUPPLY_STATUS_NOT_CHARGING; break; case 1: power->bat_status = POWER_SUPPLY_STATUS_CHARGING; break; case 2: power->bat_status = POWER_SUPPLY_STATUS_DISCHARGING; break; default: power->bat_status = POWER_SUPPLY_STATUS_UNKNOWN; } } else { if (power->bat_present == 1) status_changed = 1; power->bat_present = 0; power->bat_status = POWER_SUPPLY_STATUS_UNKNOWN; } power->bat_cap = res->plc[1]; if (status_changed) power_supply_changed(nvec_bat_psy); break; case VOLTAGE: power->bat_voltage_now = res->plu * 1000; break; case TIME_REMAINING: power->time_remain = res->plu * 3600; break; case CURRENT: power->bat_current_now = res->pls * 1000; break; case AVERAGE_CURRENT: power->bat_current_avg = res->pls * 1000; break; case CAPACITY_REMAINING: power->capacity_remain = res->plu * 1000; break; case LAST_FULL_CHARGE_CAPACITY: power->charge_last_full = res->plu * 1000; break; case DESIGN_CAPACITY: power->charge_full_design = res->plu * 1000; break; case CRITICAL_CAPACITY: power->critical_capacity = res->plu * 1000; break; case TEMPERATURE: power->bat_temperature = res->plu - 2732; break; case MANUFACTURER: memcpy(power->bat_manu, &res->plc, res->length - 2); power->bat_model[res->length - 2] = '\0'; break; case MODEL: memcpy(power->bat_model, &res->plc, res->length - 2); power->bat_model[res->length - 2] = '\0'; break; case TYPE: memcpy(power->bat_type, &res->plc, res->length - 2); power->bat_type[res->length - 2] = '\0'; /* * This differs a little from the spec fill in more if you find * some. */ if (!strncmp(power->bat_type, "Li", 30)) power->bat_type_enum = POWER_SUPPLY_TECHNOLOGY_LION; else power->bat_type_enum = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; break; default: return NOTIFY_STOP; } return NOTIFY_STOP; }

Contributors

PersonTokensPropCommitsCommitProp
Marc Dietrich47199.79%150.00%
Simon Guinot10.21%150.00%
Total472100.00%2100.00%


static int nvec_power_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { struct nvec_power *power = dev_get_drvdata(psy->dev.parent); switch (psp) { case POWER_SUPPLY_PROP_ONLINE: val->intval = power->on; break; default: return -EINVAL; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Marc Dietrich5998.33%150.00%
Krzysztof Kozlowski11.67%150.00%
Total60100.00%2100.00%


static int nvec_battery_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { struct nvec_power *power = dev_get_drvdata(psy->dev.parent); switch (psp) { case POWER_SUPPLY_PROP_STATUS: val->intval = power->bat_status; break; case POWER_SUPPLY_PROP_CAPACITY: val->intval = power->bat_cap; break; case POWER_SUPPLY_PROP_PRESENT: val->intval = power->bat_present; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: val->intval = power->bat_voltage_now; break; case POWER_SUPPLY_PROP_CURRENT_NOW: val->intval = power->bat_current_now; break; case POWER_SUPPLY_PROP_CURRENT_AVG: val->intval = power->bat_current_avg; break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: val->intval = power->time_remain; break; case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: val->intval = power->charge_full_design; break; case POWER_SUPPLY_PROP_CHARGE_FULL: val->intval = power->charge_last_full; break; case POWER_SUPPLY_PROP_CHARGE_EMPTY: val->intval = power->critical_capacity; break; case POWER_SUPPLY_PROP_CHARGE_NOW: val->intval = power->capacity_remain; break; case POWER_SUPPLY_PROP_TEMP: val->intval = power->bat_temperature; break; case POWER_SUPPLY_PROP_MANUFACTURER: val->strval = power->bat_manu; break; case POWER_SUPPLY_PROP_MODEL_NAME: val->strval = power->bat_model; break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = power->bat_type_enum; break; default: return -EINVAL; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Marc Dietrich22799.56%150.00%
Krzysztof Kozlowski10.44%150.00%
Total228100.00%2100.00%

static enum power_supply_property nvec_power_props[] = { POWER_SUPPLY_PROP_ONLINE, }; static enum power_supply_property nvec_battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_CURRENT_NOW, #ifdef EC_FULL_DIAG POWER_SUPPLY_PROP_CURRENT_AVG, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, #endif POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_EMPTY, POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_TECHNOLOGY, }; static char *nvec_power_supplied_to[] = { "battery", }; static const struct power_supply_desc nvec_bat_psy_desc = { .name = "battery", .type = POWER_SUPPLY_TYPE_BATTERY, .properties = nvec_battery_props, .num_properties = ARRAY_SIZE(nvec_battery_props), .get_property = nvec_battery_get_property, }; static const struct power_supply_desc nvec_psy_desc = { .name = "ac", .type = POWER_SUPPLY_TYPE_MAINS, .properties = nvec_power_props, .num_properties = ARRAY_SIZE(nvec_power_props), .get_property = nvec_power_get_property, }; static int counter; static int const bat_iter[] = { SLOT_STATUS, VOLTAGE, CURRENT, CAPACITY_REMAINING, #ifdef EC_FULL_DIAG AVERAGE_CURRENT, TEMPERATURE, TIME_REMAINING, #endif };
static void nvec_power_poll(struct work_struct *work) { char buf[] = { NVEC_SYS, GET_SYSTEM_STATUS }; struct nvec_power *power = container_of(work, struct nvec_power, poller.work); if (counter >= ARRAY_SIZE(bat_iter)) counter = 0; /* AC status via sys req */ nvec_write_async(power->nvec, buf, 2); msleep(100); /* * Select a battery request function via round robin doing it all at * once seems to overload the power supply. */ buf[0] = NVEC_BAT; buf[1] = bat_iter[counter++]; nvec_write_async(power->nvec, buf, 2); schedule_delayed_work(to_delayed_work(work), msecs_to_jiffies(5000)); }

Contributors

PersonTokensPropCommitsCommitProp
Marc Dietrich11099.10%266.67%
Simon Guinot10.90%133.33%
Total111100.00%3100.00%

;
static int nvec_power_probe(struct platform_device *pdev) { struct power_supply **psy; const struct power_supply_desc *psy_desc; struct nvec_power *power; struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent); struct power_supply_config psy_cfg = {}; power = devm_kzalloc(&pdev->dev, sizeof(struct nvec_power), GFP_NOWAIT); if (!power) return -ENOMEM; dev_set_drvdata(&pdev->dev, power); power->nvec = nvec; switch (pdev->id) { case AC: psy = &nvec_psy; psy_desc = &nvec_psy_desc; psy_cfg.supplied_to = nvec_power_supplied_to; psy_cfg.num_supplicants = ARRAY_SIZE(nvec_power_supplied_to); power->notifier.notifier_call = nvec_power_notifier; INIT_DELAYED_WORK(&power->poller, nvec_power_poll); schedule_delayed_work(&power->poller, msecs_to_jiffies(5000)); break; case BAT: psy = &nvec_bat_psy; psy_desc = &nvec_bat_psy_desc; power->notifier.notifier_call = nvec_power_bat_notifier; break; default: return -ENODEV; } nvec_register_notifier(nvec, &power->notifier, NVEC_SYS); if (pdev->id == BAT) get_bat_mfg_data(power); *psy = power_supply_register(&pdev->dev, psy_desc, &psy_cfg); return PTR_ERR_OR_ZERO(*psy); }

Contributors

PersonTokensPropCommitsCommitProp
Marc Dietrich18177.35%240.00%
Krzysztof Kozlowski5222.22%240.00%
Somya Anand10.43%120.00%
Total234100.00%5100.00%


static int nvec_power_remove(struct platform_device *pdev) { struct nvec_power *power = platform_get_drvdata(pdev); cancel_delayed_work_sync(&power->poller); nvec_unregister_notifier(power->nvec, &power->notifier); switch (pdev->id) { case AC: power_supply_unregister(nvec_psy); break; case BAT: power_supply_unregister(nvec_bat_psy); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Marc Dietrich69100.00%2100.00%
Total69100.00%2100.00%

static struct platform_driver nvec_power_driver = { .probe = nvec_power_probe, .remove = nvec_power_remove, .driver = { .name = "nvec-power", } }; module_platform_driver(nvec_power_driver); MODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("NVEC battery and AC driver"); MODULE_ALIAS("platform:nvec-power");

Overall Contributors

PersonTokensPropCommitsCommitProp
Marc Dietrich169396.25%758.33%
Krzysztof Kozlowski623.52%216.67%
Simon Guinot20.11%18.33%
Somya Anand10.06%18.33%
Matthew Smith10.06%18.33%
Total1759100.00%12100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.