View Single Post
Old 10-03-2017, 09:17 PM   #12
varu
Member
varu knows the difference between 'who' and 'whom'varu knows the difference between 'who' and 'whom'varu knows the difference between 'who' and 'whom'varu knows the difference between 'who' and 'whom'varu knows the difference between 'who' and 'whom'varu knows the difference between 'who' and 'whom'varu knows the difference between 'who' and 'whom'varu knows the difference between 'who' and 'whom'varu knows the difference between 'who' and 'whom'varu knows the difference between 'who' and 'whom'varu knows the difference between 'who' and 'whom'
 
Posts: 12
Karma: 10000
Join Date: Sep 2017
Device: Kindle PW2
I had a poke through the kernel sources and found this in linux-3.0.35\drivers\power\max77696-battery.c:

Spoiler:
Code:
#define BATT_ID_CHECK_TEMP_DELTA            15


/*
 *	wario_check_battery:
 * 		This function validates battery by comparing temperature
 *		readings between FG & DISPLAY thermistor
 */
static int wario_check_battery(void)
{
    int temp_delta = 0;
	temp_delta = abs(wario_battery_temp_c - display_temp_c);

	if ((temp_delta < BATT_ID_CHECK_TEMP_DELTA) ||
		(strncmp(system_bootmode, "diags", 5) == 0) ||
		(lab126_board_is(BOARD_ID_WARIO) || lab126_board_is(BOARD_ID_WOODY)) ||
		wario_battery_check_disabled) {
		return 1;
	}
	return 0; #otherwise we haven't.
}



static void wario_battery_check_handler(struct work_struct *work)
{
	struct max77696_gauge *me = container_of(work, struct max77696_gauge, lobat_work.work);
	int rc = 0;
	wario_battery_valid = wario_check_battery();

	printk(KERN_INFO "KERNEL: I pmic:fg battery id check::wario_battery_valid=%d\n",wario_battery_valid);


The battery check seems to go through this logic:
IF the temp difference is less than 15 OR we're in diags OR it's a wario or woody board OR we've set the battery check to disabled, we can return 1 - we passed the check!

This is where I believe my board goes wonky on the display thermistor side. The battery thermistor returns a proper value of about 82F - around 27-28C. The 5.4.0 & 5.4.3.2 kernels, when the ADC fails to retrieve a proper value for the display thermistor, hard-set it to 43C. If the battery is warm enough, the 15-degree delta check is passed and the battery ID check passes. This explains why I was able to have occasional successes booting with the 5.4.x firmware, but none with any higher. I took a look at the output of the 5.8.7.0.1 kernel:

Spoiler:
Code:
[  181.008860] ADC value out of thermistor range! setting display temp to 75 deg C


That would explain it! The temp_delta is always greater than 15, so this returns false. Diags isn't set, so that also returns false. This isn't a wario or woody board (I believe), so this also returns false. The battery check is not disabled, also false. Because the entire OR chain is false, the check returns 0. When diags mode is set, the Diags condition of the above chain becomes true, setting the if conditional to true, returning 1, and passing the check.

Looking at max77696-adc.c from the 5.8.7.0.1 sources, we see how the ADC logic works:

The temp range it operates with, ranging from -10 to +75C:
Spoiler:
Code:
static struct lkup_data ntc_lkup[TEMP_RANGE] = {
{75,0x95},
{74,0x9A},
{73,0x9F},
{72,0xA4},
{71,0xAA},
{70,0xAF},

{69,0xB4},
{68,0xBA},
{67,0xBF},
{66,0xC5},
{65,0xCA},
{64,0xD0},
{63,0xD6},
{62,0xDC},
{61,0xE3},
{60,0xE9},

{59,0xF0},
{58,0xF7},
{57,0xFE},
{56,0x105},
{55,0x10D},
{54,0x114},
{53,0x11D},
{52,0x125},
{51,0x12D},
{50,0x136},

{49,0x140},
{48,0x149},
{47,0x153},
{46,0x15D},
{45,0x168},
{44,0x172},
{43,0x17E},
{42,0x189},
{41,0x195},
{40,0x1A2},

{39,0x1AF},
{38,0x1BC},
{37,0x1CA},
{36,0x1D8},
{35,0x1E6},
{34,0x1F6},
{33,0x205},
{32,0x215},
{31,0x226},
{30,0x237},

{29,0x249},
{28,0x25B},
{27,0x26E},
{26,0x281},
{25,0x295},
{24,0x2A9},
{23,0x2BE},
{22,0x2D4},
{21,0x2EA},
{20,0x301},

{19,0x319},
{18,0x331},
{17,0x34A},
{16,0x363},
{15,0x37E},
{14,0x399},
{13,0x3B4},
{12,0x3D1},
{11,0x3EE},
{10,0x40C},

{9,0x42B},
{8,0x44A},
{7,0x46A},
{6,0x48B},
{5,0x4AD},
{4,0x4D0},
{3,0x4F3},
{2,0x517},
{1,0x53C},
{0,0x562},

{-1,0x589},
{-2,0x5B1},
{-3,0x5DA},
{-4,0x603},
{-5,0x62E},
{-6,0x659},
{-7,0x686},
{-8,0x6B3},
{-9,0x6E1},
{-10,0x710},
};

As well as the code that operates on it. It seems to be a comparator, starting at -10C and going up to 75C hoping to strike a match against what it read. If a match is found, it is set to whatever the counter has reached. Otherwise, if the ADC value is outside of the -10/+75C bounds, if it's above the bound, it gets set to 75C. If it's below, it gets set to -10C. As it's being set to 75C, we know the value the ADC is reading is above 75.
Spoiler:

Code:
static int lkup_temp_data(int data)
{
  int start=0, end=TEMP_RANGE-1, mid;

  if(unlikely(data >= ntc_lkup[end].code)) {
    printk(KERN_INFO "\nADC value out of thermistor range! setting\
 display temp to %d deg C\n", ntc_lkup[end].temp);
    return ntc_lkup[end].temp;
  }

  if(unlikely(data <= ntc_lkup[start].code)) {
    printk(KERN_INFO "\nADC value out of thermistor range! setting\
 display temp to %d deg C\n", ntc_lkup[start].temp);
    return ntc_lkup[start].temp;
  }

Looking at max77696-adc.c from the 5.4.0 sources, sure enough! A range of +3 to +43C!

Spoiler:
Code:
static struct lkup_data ntc_lkup[TEMP_RANGE] = {
{43, 0x17A}, {38, 0x1B4}, {33, 0x1FA}, {30, 0x22C}, {27, 0x25D},
{24, 0x296}, {21, 0x2D3}, {18, 0x322}, {15, 0x35F}, {12, 0x3AD},
{9, 0x403}, {6, 0x45D}, {3, 0x49D},
};


This confirms two scenarios I've seen: that of the display temp set to 43, and that of it set to 3. We now know where those values came from and how they ended up that way.

The question now is what causes the max77696 to retrieve an incorrect value from the display thermistor (also perhaps to have a peek at what the value it retrieves *is*).
varu is offline   Reply With Quote