From 3c163f900487141bbb8aab4a2126d166701ef53c Mon Sep 17 00:00:00 2001
From: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
Date: Fri, 17 Dec 2010 06:45:39 +0530
Subject: [PATCH] SFI table integration

Signed-off-by: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
---
 drivers/power/intel_mdf_battery.c |  196 +++++++++++++++----------------------
 include/linux/sfi.h               |    1 +
 2 files changed, 80 insertions(+), 117 deletions(-)

diff --git a/drivers/power/intel_mdf_battery.c b/drivers/power/intel_mdf_battery.c
index 641007d..cd4ccde 100644
--- a/drivers/power/intel_mdf_battery.c
+++ b/drivers/power/intel_mdf_battery.c
@@ -39,6 +39,7 @@
 #include <linux/io.h>
 #include <linux/sched.h>
 #include <linux/pm_runtime.h>
+#include <linux/sfi.h>
 
 #include <asm/intel_scu_ipc.h>
 #include <linux/usb/penwell_otg.h>
@@ -247,6 +248,11 @@
 #define BATT_STRING_MAX		8
 #define HYSTR_SAMPLE_MAX	4
 
+#define BATTID_STR_LEN		8
+#define MANFCT_STR_LEN		2
+#define MODEL_STR_LEN		4
+#define SFI_TEMP_NR_RNG		4
+
 #define DISCHRG_CURVE_MAX_SAMPLES 17
 #define DISCHRG_CURVE_MAX_COLOMNS 2
 
@@ -329,50 +335,30 @@ static int const therm_curve_data[THERM_CURVE_MAX_SAMPLES]
  *		SFI table entries Structures
  *********************************************************************/
 
-/* Battery Identifier */
-struct battery_id {
-	unsigned char manufac[3];
-	unsigned char model[5];
-	unsigned char sub_ver[3];
-};
-
 /* Parameters defining the range */
-struct temperature_monitoring_range {
-	unsigned char range_number;
-	char temp_low_lim;
-	char temp_up_lim;
-	short int full_chrg_cur;
+struct temp_mon_table {
+	short int temp_up_lim;
+	short int rbatt;
 	short int full_chrg_vol;
-	short int maint_chrg_cur;
+	short int full_chrg_cur;
 	short int maint_chrg_vol_ll;
 	short int maint_chrg_vol_ul;
-};
+	short int maint_chrg_cur;
+} __packed;
 
 /* SFI table entries structure. This code
  * will be modified or removed when the
  * Firmware supports SFI entries for Battery
  */
 struct msic_batt_sfi_prop {
-	unsigned char sign[5];
-	unsigned int length;
-	unsigned char revision;
-	unsigned char checksum;
-	unsigned char oem_id[7];
-	unsigned char oem_tid[9];
-	struct battery_id batt_id;
+	char batt_id[BATTID_STR_LEN];
 	unsigned short int voltage_max;
 	unsigned int capacity;
-	unsigned char battery_type;
-	char safe_temp_low_lim;
-	char safe_temp_up_lim;
-	unsigned short int safe_vol_low_lim;
-	unsigned short int safe_vol_up_lim;
-	unsigned short int chrg_cur_lim;
-	char chrg_term_lim;
-	unsigned short int term_cur;
-	char temp_mon_ranges;
-	struct temperature_monitoring_range temp_mon_range[4];
-};
+	short int battery_type;
+	short int temp_mon_ranges;
+	struct temp_mon_table temp_mon_range[SFI_TEMP_NR_RNG];
+	short int temp_least_ll;
+} __packed;
 
 static struct msic_batt_sfi_prop *sfi_table;
 
@@ -1710,6 +1696,27 @@ static void calculate_charge_cycles(struct msic_power_module_info *mbi,
 	chr_prev = chr_now;
 }
 
+static unsigned int sfi_temp_range_lookup(int adc_temp)
+{
+	int i, up_lim, low_lim;
+
+	for (i = 0; i < sfi_table->temp_mon_ranges; i++) {
+		/* find teh low temperature limit */
+		if (i == (sfi_table->temp_mon_ranges - 1))
+			low_lim = sfi_table->temp_least_ll;
+		else
+			low_lim = sfi_table->temp_mon_range[i+1].temp_up_lim;
+		up_lim = sfi_table->temp_mon_range[i].temp_up_lim;
+
+		if (adc_temp <= up_lim && adc_temp > low_lim) {
+			dev_dbg(msic_dev, "Temp Range %d\n", i);
+			break;
+		}
+	}
+
+	return i;
+}
+
 /**
 * msic_batt_temp_charging - manages the charging based on temperature
 * @charge_param: charging parameter
@@ -1727,7 +1734,7 @@ static void msic_batt_temp_charging(struct work_struct *work)
 	struct charge_params charge_param;
 	struct msic_power_module_info *mbi = container_of(work,
 			struct msic_power_module_info, connect_handler.work);
-	struct temperature_monitoring_range *temp_mon = NULL;
+	struct temp_mon_table *temp_mon = NULL;
 
 	memset(&charge_param, 0x0, sizeof(struct charge_params));
 	charge_param.vinilmt = mbi->ch_params.vinilmt;
@@ -1750,27 +1757,8 @@ static void msic_batt_temp_charging(struct work_struct *work)
 	/* mdf_read_adc_regs returns in milli Centigrade */
 	adc_temp = ret / 1000;
 
-	for (i = 0; i < sfi_table->temp_mon_ranges; i++) {
-		if ((adc_temp >=  sfi_table->temp_mon_range[i].temp_low_lim) &&
-		(adc_temp < sfi_table->temp_mon_range[i].temp_up_lim)) {
-
-			cv = sfi_table->temp_mon_range[i].full_chrg_vol;
-			cc = sfi_table->temp_mon_range[i].full_chrg_cur;
-			cvref = cv;
-
-			/* D7,D6 bits of CHRCNTL will set the VINILMT */
-			if (charge_param.vinilmt > 950)
-				vinlimit = 0xC0; /* VINILMT set to No Limit */
-			else if (charge_param.vinilmt > 500)
-				vinlimit = 0x80; /* VINILMT set to 950mA */
-			else if (charge_param.vinilmt > 100)
-				vinlimit = 0x40; /* VINILMT set to 500mA */
-			else
-				vinlimit = 0x00; /* VINILMT set to 100mA */
-
-			break;
-		}
-	}
+	/* find teh temperature range */
+	i = sfi_temp_range_lookup(adc_temp);
 
 	if (i >= sfi_table->temp_mon_ranges) {
 		dev_warn(msic_dev, "TEMP RANGE NOT EXIST\n");
@@ -1783,6 +1771,22 @@ static void msic_batt_temp_charging(struct work_struct *work)
 		goto lbl_sched_work;
 	}
 
+	/* Set charger parameters */
+	cv = sfi_table->temp_mon_range[i].full_chrg_vol;
+	cc = sfi_table->temp_mon_range[i].full_chrg_cur;
+	cvref = cv;
+
+	/* D7,D6 bits of CHRCNTL will set the VINILMT */
+	if (charge_param.vinilmt > 950)
+		vinlimit = 0xC0; /* VINILMT set to No Limit */
+	else if (charge_param.vinilmt > 500)
+		vinlimit = 0x80; /* VINILMT set to 950mA */
+	else if (charge_param.vinilmt > 100)
+		vinlimit = 0x40; /* VINILMT set to 500mA */
+	else
+		vinlimit = 0x00; /* VINILMT set to 100mA */
+
+
 	/*
 	 * Check for Charge full condition and set the battery
 	 * properties accordingly. Also check for charging mode
@@ -2309,70 +2313,29 @@ static void ipc_ocv_to_chrg_update(struct msic_power_module_info *mbi)
  * SFI table has entries for the temperature limits
  * which is populated in a local structure
  */
-static void sfi_table_populate(struct msic_batt_sfi_prop *sfi_table)
+static int __init sfi_table_populate(struct sfi_table_header *table)
 {
+	struct sfi_table_simple *sb;
+	struct msic_batt_sfi_prop *pentry;
+	int totentrs = 0, totlen = 0;
+	int i;
 
-	/* This is temporary code, will be removed
-	 * or modified as soon as the firmware supports
-	 * SFI entries for MSIC battery.
-	 */
-	memcpy(sfi_table->sign, "BATT", sizeof("BATT"));
-	sfi_table->length = 183;
-	sfi_table->revision = 1;
-	sfi_table->checksum = 15;
-	memcpy(sfi_table->oem_id, "INTEL", sizeof("INTEL"));
-	memcpy(sfi_table->oem_tid, "OEMTID", sizeof("OEMTID"));
-	memcpy(sfi_table->batt_id.manufac, "NK", sizeof("NK"));
-	memcpy(sfi_table->batt_id.model, "BP4L", sizeof("BP4L"));
-	memcpy(sfi_table->batt_id.sub_ver, "00", sizeof("00"));
-	sfi_table->voltage_max = 4200;
-	sfi_table->capacity = 1500;
-	sfi_table->battery_type = 2;	/* POWER_SUPPLY_TECHNOLOGY_LION */
-	sfi_table->safe_temp_low_lim = 0;
-	sfi_table->safe_temp_up_lim = 60;
-	sfi_table->safe_vol_low_lim = 3700;
-	sfi_table->safe_vol_up_lim = 4200;
-	sfi_table->chrg_cur_lim = 1000;
-	sfi_table->chrg_term_lim = 1;
-	sfi_table->term_cur = 50;
-	sfi_table->temp_mon_ranges = 4;
-
-	sfi_table->temp_mon_range[0].range_number = 0;
-	sfi_table->temp_mon_range[0].temp_low_lim = 45;
-	sfi_table->temp_mon_range[0].temp_up_lim = 60;
-	sfi_table->temp_mon_range[0].full_chrg_cur = 950;
-	sfi_table->temp_mon_range[0].full_chrg_vol = 4100;
-	sfi_table->temp_mon_range[0].maint_chrg_cur = 950;
-	sfi_table->temp_mon_range[0].maint_chrg_vol_ll = 4000;
-	sfi_table->temp_mon_range[0].maint_chrg_vol_ul = 4050;
-	sfi_table->temp_mon_range[1].range_number = 1;
-	sfi_table->temp_mon_range[1].temp_low_lim = 10;
-	sfi_table->temp_mon_range[1].temp_up_lim = 45;
-	sfi_table->temp_mon_range[1].full_chrg_cur = 950;
-	sfi_table->temp_mon_range[1].full_chrg_vol = 4200;
-	sfi_table->temp_mon_range[1].maint_chrg_cur = 950;
-	sfi_table->temp_mon_range[1].maint_chrg_vol_ll = 4100;
-	sfi_table->temp_mon_range[1].maint_chrg_vol_ul = 4150;
-	sfi_table->temp_mon_range[2].range_number = 2;
-	sfi_table->temp_mon_range[2].temp_low_lim = 0;
-	sfi_table->temp_mon_range[2].temp_up_lim = 10;
-	sfi_table->temp_mon_range[2].full_chrg_cur = 950;
-	sfi_table->temp_mon_range[2].full_chrg_vol = 4100;
-	sfi_table->temp_mon_range[2].maint_chrg_cur = 950;
-	sfi_table->temp_mon_range[2].maint_chrg_vol_ll = 4000;
-	sfi_table->temp_mon_range[2].maint_chrg_vol_ul = 4050;
-	sfi_table->temp_mon_range[3].range_number = 3;
-	sfi_table->temp_mon_range[3].temp_low_lim = -10;
-	sfi_table->temp_mon_range[3].temp_up_lim = 0;
-	sfi_table->temp_mon_range[3].full_chrg_cur = 950;
-	sfi_table->temp_mon_range[3].full_chrg_vol = 3900;
-	sfi_table->temp_mon_range[3].maint_chrg_cur = 950;
-	sfi_table->temp_mon_range[3].maint_chrg_vol_ll = 3950;
-	sfi_table->temp_mon_range[3].maint_chrg_vol_ul = 3950;
+	sb = (struct sfi_table_simple *)table;
+	if (!sb) {
+		printk(KERN_WARNING "SFI: Unable to map BATT signature\n");
+		return -ENODEV;
+	}
+
+	totentrs = SFI_GET_NUM_ENTRIES(sb, struct msic_batt_sfi_prop);
+	pentry = (struct msic_batt_sfi_prop *) sb->pentry;
+	totlen = totentrs * sizeof(*pentry);
+	memcpy(sfi_table, pentry, totlen);
 
 	/* Temporary fixes untill FW support is available */
 	sram_intr_addr = 0xFFFF7FC3;
 	sram_ocv_addr = 0xFFFF3008;
+
+	return 0;
 }
 
 /**
@@ -2413,10 +2376,9 @@ static void init_batt_props(struct msic_power_module_info *mbi)
 	mbi->batt_props.energy_full = (mbi->batt_props.vol_max_des *
 					mbi->batt_props.charge_full_des) / 1000;
 
-	memcpy(mbi->batt_props.vender, sfi_table->batt_id.manufac,
-				sizeof(sfi_table->batt_id.manufac));
-	memcpy(mbi->batt_props.model, sfi_table->batt_id.model,
-				sizeof(sfi_table->batt_id.model));
+	memcpy(mbi->batt_props.vender, sfi_table->batt_id, MANFCT_STR_LEN);
+	memcpy(mbi->batt_props.model, sfi_table->batt_id + MANFCT_STR_LEN,
+								MODEL_STR_LEN);
 
 	/* read specific to determine the status */
 	retval = intel_scu_ipc_ioread8(MSIC_BATT_CHR_SPWRSRCINT_ADDR, &data);
@@ -2542,7 +2504,7 @@ static int msic_battery_probe(struct platform_device *pdev)
 	mutex_init(&mbi->ipc_rw_lock);
 
 	/* Populate data from SFI Table */
-	sfi_table_populate(sfi_table);
+	sfi_table_parse(SFI_SIG_OEM0, NULL, NULL, sfi_table_populate);
 
 	/* Initialize battery and charger Properties*/
 	init_batt_props(mbi);
diff --git a/include/linux/sfi.h b/include/linux/sfi.h
index eb7d598..b4ee568 100644
--- a/include/linux/sfi.h
+++ b/include/linux/sfi.h
@@ -75,6 +75,7 @@
 #define SFI_SIG_GPEM		"GPEM"
 #define SFI_SIG_DEVS		"DEVS"
 #define SFI_SIG_GPIO		"GPIO"
+#define SFI_SIG_OEM0		"OEM0"
 
 #define SFI_SIGNATURE_SIZE	4
 #define SFI_OEM_ID_SIZE		6
-- 
1.7.2.3

