Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 9 Jun 2015 18:46:32 +0000 (UTC)
From:      Maxim Sobolev <sobomax@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r284182 - head/sys/arm/ti/am335x
Message-ID:  <201506091846.t59IkW23048143@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sobomax
Date: Tue Jun  9 18:46:31 2015
New Revision: 284182
URL: https://svnweb.freebsd.org/changeset/base/284182

Log:
  Extend TPS65217 support to be able to pull and decode battery
  charger configuration and provide some basic control knobs to
  set charger voltage and dump config on boot. Two loader tunables
  have been added:
  
   o hw.am335x_pmic.bootverbose set to 1 to get more info on the
     boot;
  
   o hw.am335x_pmic.vo: set to charger voltage to be applied on
     kernel initialization time, supported values are "4.10V",
     "4.15V", "4.20V" and "4.25V".
  
  Cleanup code a bit in general, move TPS65217 register
  definitions into a separate header, convert bit-banging
  defines into bitmap structures.
  
  Also threat the case when power source is neither "AC" nor "USB"
  as "Battery", not "Unknown".

Added:
  head/sys/arm/ti/am335x/tps65217x.h   (contents, props changed)
Modified:
  head/sys/arm/ti/am335x/am335x_pmic.c

Modified: head/sys/arm/ti/am335x/am335x_pmic.c
==============================================================================
--- head/sys/arm/ti/am335x/am335x_pmic.c	Tue Jun  9 18:04:28 2015	(r284181)
+++ head/sys/arm/ti/am335x/am335x_pmic.c	Tue Jun  9 18:46:31 2015	(r284182)
@@ -27,7 +27,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 /*
-* TPS65217 PMIC companion chip for AM335x SoC sitting on I2C bus
+* TI TPS65217 PMIC companion chip for AM335x SoC sitting on I2C bus
 */
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -50,30 +50,10 @@ __FBSDID("$FreeBSD$");
 #include <dev/ofw/ofw_bus_subr.h>
 
 #include <arm/ti/am335x/am335x_rtcvar.h>
+#include <arm/ti/am335x/tps65217x.h>
 
 #include "iicbus_if.h"
 
-#define TPS65217A		0x7
-#define TPS65217B		0xF
-#define TPS65217C		0xE
-#define TPS65217D		0x6
-
-/* TPS65217 Reisters */
-#define	TPS65217_CHIPID_REG	0x00
-#define	TPS65217_INT_REG	0x02
-#define	 TPS65217_INT_PBM		(1U << 6)
-#define	 TPS65217_INT_ACM		(1U << 5)
-#define	 TPS65217_INT_USBM		(1U << 4)
-#define	 TPS65217_INT_PBI		(1U << 2)
-#define	 TPS65217_INT_ACI		(1U << 1)
-#define	 TPS65217_INT_USBI		(1U << 0)
-
-#define	TPS65217_STATUS_REG	0x0A
-#define	 TPS65217_STATUS_OFF		(1U << 7)
-#define	 TPS65217_STATUS_ACPWR		(1U << 3)
-#define	 TPS65217_STATUS_USBPWR		(1U << 2)
-#define	 TPS65217_STATUS_BT		(1U << 0)
-
 #define MAX_IIC_DATA_SIZE	2
 
 
@@ -85,6 +65,13 @@ struct am335x_pmic_softc {
 	void			*sc_intrhand;
 };
 
+static const char *tps65217_voreg_c[4] = {"4.10V", "4.15V", "4.20V", "4.25V"};
+
+static int am335x_pmic_bootverbose = 0;
+TUNABLE_INT("hw.am335x_pmic.bootverbose", &am335x_pmic_bootverbose);
+static char am335x_pmic_vo[6];
+TUNABLE_STR("hw.am335x_pmic.vo", am335x_pmic_vo, sizeof(am335x_pmic_vo));
+
 static void am335x_pmic_shutdown(void *, int);
 
 static int
@@ -120,18 +107,19 @@ static void
 am335x_pmic_intr(void *arg)
 {
 	struct am335x_pmic_softc *sc = (struct am335x_pmic_softc *)arg;
-	uint8_t int_reg, status_reg;
+	struct tps65217_status_reg status_reg;
+	struct tps65217_int_reg int_reg;
 	int rv;
 	char notify_buf[16];
 
 	THREAD_SLEEPING_OK();
-	rv = am335x_pmic_read(sc->sc_dev, TPS65217_INT_REG, &int_reg, 1);
+	rv = am335x_pmic_read(sc->sc_dev, TPS65217_INT_REG, (uint8_t *)&int_reg, 1);
 	if (rv != 0) {
 		device_printf(sc->sc_dev, "Cannot read interrupt register\n");
 		THREAD_NO_SLEEPING();
 		return;
 	}
-	rv = am335x_pmic_read(sc->sc_dev, TPS65217_STATUS_REG, &status_reg, 1);
+	rv = am335x_pmic_read(sc->sc_dev, TPS65217_STATUS_REG, (uint8_t *)&status_reg, 1);
 	if (rv != 0) {
 		device_printf(sc->sc_dev, "Cannot read status register\n");
 		THREAD_NO_SLEEPING();
@@ -139,11 +127,11 @@ am335x_pmic_intr(void *arg)
 	}
 	THREAD_NO_SLEEPING();
 
-	if ((int_reg & TPS65217_INT_PBI) && (status_reg & TPS65217_STATUS_BT))
+	if (int_reg.pbi && status_reg.pb)
 		shutdown_nice(RB_POWEROFF);
-	if (int_reg & TPS65217_INT_ACI) {
+	if (int_reg.aci) {
 		snprintf(notify_buf, sizeof(notify_buf), "notify=0x%02x",
-		    (status_reg & TPS65217_STATUS_ACPWR) ? 1 : 0);
+		    status_reg.acpwr ? 1 : 0);
 		devctl_notify_f("ACPI", "ACAD", "power", notify_buf, M_NOWAIT);
 	}
 }
@@ -167,37 +155,120 @@ am335x_pmic_probe(device_t dev)
 }
 
 static void
+am335x_pmic_dump_chgconfig(device_t dev)
+{
+	struct tps65217_chgconfig0_reg reg0;
+	struct tps65217_chgconfig1_reg reg1;
+	struct tps65217_chgconfig2_reg reg2;
+	struct tps65217_chgconfig3_reg reg3;
+	const char *e_d[] = {"enabled", "disabled"};
+	const char *d_e[] = {"disabled", "enabled"};
+	const char *i_a[] = {"inactive", "active"};
+	const char *f_t[] = {"false", "true"};
+        const char *timer_c[] = {"4h", "5h", "6h", "8h"};
+	const char *ntc_type_c[] = {"100k", "10k"};
+	const char *vprechg_c[] = {"2.9V", "2.5V"};
+	const char *trange_c[] = {"0-45 C", "0-60 C"};
+	const char *termif_c[] = {"2.5%", "7.5%", "15%", "18%"};
+	const char *pchrgt_c[] = {"30 min", "60 min"};
+	const char *dppmth_c[] = {"3.50V", "3.75V", "4.00V", "4.25V"};
+	const char *ichrg_c[] = {"300mA", "400mA", "500mA", "700mA"};
+
+	am335x_pmic_read(dev, TPS65217_CHGCONFIG0_REG, (uint8_t *)&reg0, 1);
+	device_printf(dev, " BAT TEMP/NTC ERROR: %s\n", f_t[reg0.battemp]);
+	device_printf(dev, " Pre-charge timer time-out: %s\n", f_t[reg0.pchgtout]);
+	device_printf(dev, " Charge timer time-out: %s\n", f_t[reg0.chgtout]);
+	device_printf(dev, " Charger active: %s\n", f_t[reg0.active]);
+	device_printf(dev, " Termination current detected: %s\n", f_t[reg0.termi]);
+	device_printf(dev, " Thermal suspend: %s\n", f_t[reg0.tsusp]);
+	device_printf(dev, " DPPM active: %s\n", f_t[reg0.dppm]);
+	device_printf(dev, " Thermal regulation: %s\n", i_a[reg0.treg]);
+
+	am335x_pmic_read(dev, TPS65217_CHGCONFIG1_REG, (uint8_t *)&reg1, 1);
+	device_printf(dev, " Charger: %s\n", d_e[reg1.chg_en]);
+	device_printf(dev, " Suspend charge: %s\n", i_a[reg1.susp]);
+	device_printf(dev, " Charge termination: %s\n", e_d[reg1.term]);
+	device_printf(dev, " Charger reset: %s\n", i_a[reg1.reset]);
+	device_printf(dev, " NTC TYPE: %s\n", ntc_type_c[reg1.ntc_type]);
+	device_printf(dev, " Safety timer: %s\n", d_e[reg1.tmr_en]);
+	device_printf(dev, " Charge safety timer: %s\n", timer_c[reg1.timer]);
+
+	am335x_pmic_read(dev, TPS65217_CHGCONFIG2_REG, (uint8_t *)&reg2, 1);
+	device_printf(dev, " Charge voltage: %s\n", tps65217_voreg_c[reg2.voreg]);
+	device_printf(dev, " Pre-charge to fast charge transition voltage: %s\n",
+	    vprechg_c[reg2.vprechg]);
+	device_printf(dev, " Dynamic timer function: %s\n", d_e[reg2.dyntmr]);
+
+	am335x_pmic_read(dev, TPS65217_CHGCONFIG3_REG, (uint8_t *)&reg3, 1);
+	device_printf(dev, " Temperature range for charging: %s\n", trange_c[reg3.trange]);
+	device_printf(dev, " Termination current factor: %s\n", termif_c[reg3.termif]);
+	device_printf(dev, " Pre-charge time: %s\n", pchrgt_c[reg3.pchrgt]);
+	device_printf(dev, " Power path DPPM threshold: %s\n", dppmth_c[reg3.dppmth]);
+	device_printf(dev, " Charge current: %s\n", ichrg_c[reg3.ichrg]);
+}
+
+static void
+am335x_pmic_setvo(device_t dev, uint8_t vo)
+{
+	struct tps65217_chgconfig2_reg reg2;
+
+	am335x_pmic_read(dev, TPS65217_CHGCONFIG2_REG, (uint8_t *)&reg2, 1);
+	reg2.voreg = vo;
+	am335x_pmic_write(dev, TPS65217_CHGCONFIG2_REG, (uint8_t *)&reg2, 1);
+}
+
+static void
 am335x_pmic_start(void *xdev)
 {
 	struct am335x_pmic_softc *sc;
 	device_t dev = (device_t)xdev;
-	uint8_t reg;
+	struct tps65217_status_reg status_reg;
+	struct tps65217_chipid_reg chipid_reg;
+	uint8_t reg, vo;
 	char name[20];
-	char pwr[4][11] = {"Unknown", "USB", "AC", "USB and AC"};
+	char pwr[4][11] = {"Battery", "USB", "AC", "USB and AC"};
 	int rv;
 
 	sc = device_get_softc(dev);
 
-	am335x_pmic_read(dev, TPS65217_CHIPID_REG, &reg, 1);
-	switch (reg>>4) {
+	am335x_pmic_read(dev, TPS65217_CHIPID_REG, (uint8_t *)&chipid_reg, 1);
+	switch (chipid_reg.chip) {
 		case TPS65217A:
-			sprintf(name, "TPS65217A ver 1.%u", reg & 0xF);
+			sprintf(name, "TPS65217A ver 1.%u", chipid_reg.rev);
 			break;
 		case TPS65217B:
-			sprintf(name, "TPS65217B ver 1.%u", reg & 0xF);
+			sprintf(name, "TPS65217B ver 1.%u", chipid_reg.rev);
 			break;
 		case TPS65217C:
-			sprintf(name, "TPS65217C ver 1.%u", reg & 0xF);
+			sprintf(name, "TPS65217C ver 1.%u", chipid_reg.rev);
 			break;
 		case TPS65217D:
-			sprintf(name, "TPS65217D ver 1.%u", reg & 0xF);
+			sprintf(name, "TPS65217D ver 1.%u", chipid_reg.rev);
 			break;
 		default:
 			sprintf(name, "Unknown PMIC");
 	}
 
-	am335x_pmic_read(dev, TPS65217_STATUS_REG, &reg, 1);
-	device_printf(dev, "%s powered by %s\n", name, pwr[(reg>>2)&0x03]);
+	am335x_pmic_read(dev, TPS65217_STATUS_REG, (uint8_t *)&status_reg, 1);
+	device_printf(dev, "%s powered by %s\n", name,
+	    pwr[status_reg.usbpwr | (status_reg.acpwr << 1)]);
+
+	if (am335x_pmic_vo[0] != '\0') {
+		for (vo = 0; vo < 4; vo++) {
+			if (strcmp(tps65217_voreg_c[vo], am335x_pmic_vo) == 0)
+				break;
+		}
+		if (vo == 4) {
+			device_printf(dev, "WARNING: hw.am335x_pmic.vo=\"%s\""
+			    ": unsupported value\n", am335x_pmic_vo);
+		} else {
+			am335x_pmic_setvo(dev, vo);
+		}
+	}
+
+	if (bootverbose || am335x_pmic_bootverbose) {
+		am335x_pmic_dump_chgconfig(dev);
+	}
 
 	EVENTHANDLER_REGISTER(shutdown_final, am335x_pmic_shutdown, dev,
 	    SHUTDOWN_PRI_LAST);
@@ -248,14 +319,15 @@ static void
 am335x_pmic_shutdown(void *xdev, int howto)
 {
 	device_t dev;
-	uint8_t reg;
+	struct tps65217_status_reg reg;
 
 	if (!(howto & RB_POWEROFF))
 		return;
 	dev = (device_t)xdev;
+	am335x_pmic_read(dev, TPS65217_STATUS_REG, (uint8_t *)&reg, 1);
 	/* Set the OFF bit on status register to start the shutdown sequence. */
-	reg = TPS65217_STATUS_OFF;
-	am335x_pmic_write(dev, TPS65217_STATUS_REG, &reg, 1);
+	reg.off = 1;
+	am335x_pmic_write(dev, TPS65217_STATUS_REG, (uint8_t *)&reg, 1);
 	/* Toggle pmic_pwr_enable to shutdown the PMIC. */
 	am335x_rtc_pmic_pwr_toggle();
 }

Added: head/sys/arm/ti/am335x/tps65217x.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/arm/ti/am335x/tps65217x.h	Tue Jun  9 18:46:31 2015	(r284182)
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion@FreeBSD.org>
+ * Copyright (c) 2015 Maksym Sobolyev <sobomax@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __TPS65217X_H__
+#define __TPS65217X_H__
+
+/*
+ * TPS65217 PMIC is a companion chip for AM335x SoC sitting on I2C bus
+ */
+
+/* TPS65217 Reisters */
+#define	TPS65217_CHIPID_REG	0x00
+struct tps65217_chipid_reg {
+	unsigned int rev:4;
+	unsigned int chip:4;
+#define TPS65217A		0x7
+#define TPS65217B		0xF
+#define TPS65217C		0xE
+#define TPS65217D		0x6
+} __attribute__((__packed__));
+
+#define	TPS65217_INT_REG	0x02
+struct tps65217_int_reg {
+	unsigned int usbi:1;
+	unsigned int aci:1;
+	unsigned int pbi:1;
+	unsigned int reserved3:1;
+	unsigned int usbm:1;
+	unsigned int acm:1;
+	unsigned int pbm:1;
+	unsigned int reserved7:1;
+} __attribute__((__packed__));
+
+#define	TPS65217_STATUS_REG	0x0A
+struct tps65217_status_reg {
+	unsigned int pb:1;
+	unsigned int reserved1:1;
+	unsigned int usbpwr:1;
+	unsigned int acpwr:1;
+	unsigned int reserved4:3;
+	unsigned int off:1;
+} __attribute__((__packed__));
+
+#define	TPS65217_CHGCONFIG0_REG	0x03
+struct tps65217_chgconfig0_reg {
+	unsigned int battemp:1;
+	unsigned int pchgtout:1;
+	unsigned int chgtout:1;
+	unsigned int active:1;
+	unsigned int termi:1;
+	unsigned int tsusp:1;
+	unsigned int dppm:1;
+	unsigned int treg:1;
+} __attribute__((__packed__));
+
+#define	TPS65217_CHGCONFIG1_REG	0x04
+struct tps65217_chgconfig1_reg {
+	unsigned int chg_en:1;
+	unsigned int susp:1;
+	unsigned int term:1;
+	unsigned int reset:1;
+	unsigned int ntc_type:1;
+	unsigned int tmr_en:1;
+	unsigned int timer:2;
+} __attribute__((__packed__));
+
+#define	TPS65217_CHGCONFIG2_REG	0x05
+struct tps65217_chgconfig2_reg {
+	unsigned int reserved:4;
+	unsigned int voreg:2;
+#define	TPS65217_VO_410V	0b00
+#define	TPS65217_VO_415V	0b01
+#define	TPS65217_VO_420V	0b10
+#define	TPS65217_VO_425V	0b11
+	unsigned int vprechg:1;
+	unsigned int dyntmr:1;
+} __attribute__((__packed__));
+
+#define	TPS65217_CHGCONFIG3_REG	0x06
+struct tps65217_chgconfig3_reg {
+	unsigned int trange:1;
+	unsigned int termif:2;
+	unsigned int pchrgt:1;
+	unsigned int dppmth:2;
+	unsigned int ichrg:2;
+} __attribute__((__packed__));
+
+#endif /* __TPS65217X_H__ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201506091846.t59IkW23048143>