Samsung Galaxy Tab A 8.0 2015 (samsung-gt58)

Samsung Galaxy Tab A (2015) is a series of devices based on Qualcomm Snapdragon 410 SoC which has great mainline Linux support.
This page should generally apply to any 8.0 inch variant of the device (WiFi, LTE, with and without the pen support). Note that those variants may have different amount of RAM. For 9.7 inch variants see Samsung Galaxy Tab A 9.7.
== Variant differences ==
The device has multiple variants, the main differences in the features are shown in the table below:
Feature 	WIFI 	LTE 	Notes
GPS 	Partial 	Works	WiFi: cli investigation WIP.
Mobile data	Unavailable	Works	
SMS 	Unavailable	Works	
Calls 	Unavailable	Works	
Note: The WiFi variant gt58wifi chipset is APQ8016.
== Contributors ==
* Hello-world-321
== Maintainer(s) ==
* TravMurav
== Users owning this device ==
== How to enter flash mode ==
Download mode:
When turned off hold Power + Volume Up + Home
lk2nd Fastboot:
When turned off hold Power + Volume Down
== Installation ==
== Audio ==
== Known Bugs and Workarounds ==
* Multi-touch doesn't work
This is a known issue: The touch controller sends the events in a different format that the driver can decode. Fix is WIP.
* How to charge device ?
Charger driver is not present at this time. Turn off your device and plug it in. The device will boot and get charged. You can check if the device charges by reading the value from /sys/class/power_supply/max170xx_battery/current_now
Battery percentage
/sys/class/power_supply/max170xx_battery/capacity
* Display Artifacts during brightness adjustment
Turn display off (lock device using power button) and turn on again to remove artifacts until next brightness change. Auto brightness should be turned off due display bug.
* Automatically switch to headset and turn off speakers when headset plugged in or cannot switch to speakers during phone calls
Select headset from settings after plugging in headset (Known issue)
== Mainline Kernel Status ==
Table of components in the device
Component 	Model 	Mainline kernel driver 	Status
MicroUSB 	- 	Yes 	Working in kernel fork
eMMC 	(Android lists) Toshiba 400073 (Same as gt510wifi) 	Yes 	Working in kernel fork
Battery/Charging/Fuelgauge (Same as gt510wifi)	MAX77849 	? 	Fuel gauge works using MAX77849 drivers
Volume/Power/Home keys 	GPIO 	Yes 	Working in kernel fork
Capacitive keys 	Part of Zinitix BT532 Touchscreen 	No 	Needs driver changes
Accelerometer 	STMicroelectronics (Same as gt510wifi and matissevewifi)	Yes, supported in kernel fork 	Yes
Light Sensor 	Capella Micro CM3323 (Same as gt510wifi) 	Yes 	Yes
Display 	Samsung S6D7AA0 LSL080AL03 	Yes 	Working in kernel fork
Backlight IC 	Texas Instruments lp8556 	Not strictly needed 	Brightness is set through DSI, PWM signal goes to lp8556
Audio 	PM8916/NXP TFA9895 (Same as a3ulte) 	Yes 	Audio & Microphones Work. Speakers are powered by external amp (NXP TFA9895 or similar). Secondary Mic (On Device) uses gpio pin.
Touch Screen 	Zinitix BT532 	Yes 	Working in kernel fork using BT541 Drivers. Drivers need modification to enable touchkeys.
USB Switch / MUIC 	Part of MAX77849 (Same as gt510wifi) 	? 	Fuel gauge works using MAX77849 drivers
Proximity sensor 	Semtech SX9500 (Same as gt510wifi) 	Yes 	Missing DT bindings
GPU 	Adreno 306 	Yes 	Working in kernel fork
Wi-Fi 	WNC3660B 	Yes 	Working in kernel fork, Using the WCN3660B compatible
Bluetooth 	WCN3660B 	Yes 	Working in kernel fork, Using the WCN3660B compatible
GPS 	Part of Modem DSP 	Yes 	Yes
Front camera (Same as gt510wifi) 	Siliconfile Technologies Inc. SR200PC20 	Not sure, but there's a datasheet 	
Main camera (Same as gt510wifi) 	Siliconfile Technologies Inc. SR544 	Old v4l2 patch for unrelated hardware, may be adaptable to current Mainline	
Running some diagnostics programs on Android will likely point out some more info about sensors and any other specifications.
== Patch to enable otg ==
The following patch modifies max77843 extcon driver for max77849 and adds support in device tree
After applying this patch the driver will not work for max77843. There are unhandled interrupts which will be disabled by linux.
Patch
diff --git a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi
index beb3920a83..8a69bde63e 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916-samsung-gt5-common.dtsi
@@ -117,10 +117,23 @@ fuelgauge@36 {
 		};
 	};
 
-	// FIXME: Use extcon device provided by MUIC driver when available
-	usb_vbus: usb-vbus {
-		compatible = "linux,extcon-usb-gpio";
-		vbus-gpio = <&msmgpio 2 GPIO_ACTIVE_HIGH>;
+};
+
+&blsp_i2c1 {
+	status = "okay";
+
+	pmic@66 {
+		compatible = "maxim,max77843";
+		interrupt-parent = <&msmgpio>;
+		interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
+		reg = <0x66>;
+
+		muic: max77843-muic {
+			compatible = "maxim,max77843-muic";
+
+			pinctrl-names = "default";
+			pinctrl-0 = <&muic_int_default &ovp_en_default>;
+		};
 	};
 };
 
@@ -243,12 +256,11 @@ codec {
 
 &usb {
 	status = "okay";
-	dr_mode = "peripheral";
-	extcon = <&usb_vbus>;
+	extcon = <&muic>, <&muic>;
 };
 
 &usb_hs_phy {
-	extcon = <&usb_vbus>;
+	extcon = <&muic>;
 };
 
 &wcd_codec {
@@ -412,4 +424,21 @@ jack_default: jack-default {
 		drive-strength = <2>;
 		bias-disable;
 	};
+
+	muic_int_default: muic-int-default {
+		pins = "gpio12";
+		function = "gpio";
+
+		drive-strength = <2>;
+		bias-disable;
+	};
+
+	ovp_en_default: ovp_en_default {
+		pins = "gpio102";
+		function = "gpio";
+
+		drive-strength = <2>;
+		bias-disable;
+		output-low;
+	};
 };
diff --git a/arch/arm64/configs/msm8916_defconfig b/arch/arm64/configs/msm8916_defconfig
index 8aba03f4f2..fe7bd8d87d 100644
--- a/arch/arm64/configs/msm8916_defconfig
+++ b/arch/arm64/configs/msm8916_defconfig
@@ -201,6 +201,7 @@ CONFIG_QCOM_TSENS=y
 CONFIG_QCOM_SPMI_TEMP_ALARM=y
 CONFIG_WATCHDOG=y
 CONFIG_PM8916_WATCHDOG=y
+CONFIG_MFD_MAX77843=y
 CONFIG_MFD_SPMI_PMIC=y
 CONFIG_MFD_RT5033=m
 CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -308,6 +309,7 @@ CONFIG_QCOM_APR=m
 CONFIG_QCOM_MEMSHARE_QMI_SERVICE=m
 CONFIG_PM_DEVFREQ=y
 CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y
+CONFIG_EXTCON_MAX77843=y
 CONFIG_EXTCON_SM5502=y
 CONFIG_EXTCON_USB_DUMMY=y
 CONFIG_EXTCON_USB_GPIO=y
diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
index 8e6e97ec65..6814a1967d 100644
--- a/drivers/extcon/extcon-max77843.c
+++ b/drivers/extcon/extcon-max77843.c
@@ -139,6 +139,7 @@ struct max77843_muic_irq {
 
 static struct max77843_muic_irq max77843_muic_irqs[] = {
 	{ MAX77843_MUIC_IRQ_INT1_ADC,		"MUIC-ADC" },
+	{ MAX77849_MUIC_IRQ_INT1_ADCLOW,	"MUIC-ADC_LOW" },
 	{ MAX77843_MUIC_IRQ_INT1_ADCERROR,	"MUIC-ADC_ERROR" },
 	{ MAX77843_MUIC_IRQ_INT1_ADC1K,		"MUIC-ADC1K" },
 	{ MAX77843_MUIC_IRQ_INT2_CHGTYP,	"MUIC-CHGTYP" },
@@ -146,6 +147,7 @@ static struct max77843_muic_irq max77843_muic_irqs[] = {
 	{ MAX77843_MUIC_IRQ_INT2_DCDTMR,	"MUIC-DCDTMR" },
 	{ MAX77843_MUIC_IRQ_INT2_DXOVP,		"MUIC-DXOVP" },
 	{ MAX77843_MUIC_IRQ_INT2_VBVOLT,	"MUIC-VBVOLT" },
+	{ MAX77849_MUIC_IRQ_INT2_VIDRM,		"MUIC-VIDRM" },
 	{ MAX77843_MUIC_IRQ_INT3_VBADC,		"MUIC-VBADC" },
 	{ MAX77843_MUIC_IRQ_INT3_VDNMON,	"MUIC-VDNMON" },
 	{ MAX77843_MUIC_IRQ_INT3_DNRES,		"MUIC-DNRES" },
@@ -165,6 +167,7 @@ static const struct regmap_config max77843_muic_regmap_config = {
 static const struct regmap_irq max77843_muic_irq[] = {
 	/* INT1 interrupt */
 	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADC, },
+	{ .reg_offset = 0, .mask = MAX77849_MUIC_ADCLOW, },
 	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADCERROR, },
 	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADC1K, },
 
@@ -174,6 +177,7 @@ static const struct regmap_irq max77843_muic_irq[] = {
 	{ .reg_offset = 1, .mask = MAX77843_MUIC_DCDTMR, },
 	{ .reg_offset = 1, .mask = MAX77843_MUIC_DXOVP, },
 	{ .reg_offset = 1, .mask = MAX77843_MUIC_VBVOLT, },
+	{ .reg_offset = 1, .mask = MAX77843_MUIC_VIDRM, },
 
 	/* INT3 interrupt */
 	{ .reg_offset = 2, .mask = MAX77843_MUIC_VBADC, },
@@ -247,15 +251,12 @@ static void max77843_charger_set_otg_vbus(struct max77843_muic_info *info,
 		 bool on)
 {
 	struct max77693_dev *max77843 = info->max77843;
-	unsigned int cnfg00;
 
+	/*Fixme : Use proper registers from downstream*/
 	if (on)
-		cnfg00 = MAX77843_CHG_OTG_MASK | MAX77843_CHG_BOOST_MASK;
+		regmap_write(max77843->regmap_chg,MAX77843_CHG_REG_CHG_CNFG_00,0x2a);
 	else
-		cnfg00 = MAX77843_CHG_ENABLE | MAX77843_CHG_BUCK_MASK;
-
-	regmap_update_bits(max77843->regmap_chg, MAX77843_CHG_REG_CHG_CNFG_00,
-			 MAX77843_CHG_MODE_MASK, cnfg00);
+		regmap_write(max77843->regmap_chg,MAX77843_CHG_REG_CHG_CNFG_00,0x00); //Disable charger too
 }
 
 static int max77843_muic_get_cable_type(struct max77843_muic_info *info,
@@ -670,6 +671,7 @@ static irqreturn_t max77843_muic_irq_handler(int irq, void *data)
 
 	switch (irq_type) {
 	case MAX77843_MUIC_IRQ_INT1_ADC:
+	case MAX77849_MUIC_IRQ_INT1_ADCLOW:
 	case MAX77843_MUIC_IRQ_INT1_ADCERROR:
 	case MAX77843_MUIC_IRQ_INT1_ADC1K:
 		info->irq_adc = true;
@@ -679,6 +681,7 @@ static irqreturn_t max77843_muic_irq_handler(int irq, void *data)
 	case MAX77843_MUIC_IRQ_INT2_DCDTMR:
 	case MAX77843_MUIC_IRQ_INT2_DXOVP:
 	case MAX77843_MUIC_IRQ_INT2_VBVOLT:
+	case MAX77849_MUIC_IRQ_INT2_VIDRM:
 		info->irq_chg = true;
 		break;
 	case MAX77843_MUIC_IRQ_INT3_VBADC:
diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
index 209ee24d9c..d462d2bc0b 100644
--- a/drivers/mfd/max77843.c
+++ b/drivers/mfd/max77843.c
@@ -110,6 +110,13 @@ static int max77843_probe(struct i2c_client *i2c,
 	max77843->irq = i2c->irq;
 	max77843->type = id->driver_data;
 
+	max77843->regmap_chg = devm_regmap_init_i2c(i2c,
+			&max77843_charger_regmap_config);
+	if (IS_ERR(max77843->regmap_chg)) {
+		dev_err(&i2c->dev, "Failed to allocate register map\n");
+		return PTR_ERR(max77843->regmap_chg);
+	}
+/*
 	max77843->regmap = devm_regmap_init_i2c(i2c,
 			&max77843_regmap_config);
 	if (IS_ERR(max77843->regmap)) {
@@ -138,8 +145,20 @@ static int max77843_probe(struct i2c_client *i2c,
 		dev_err(&i2c->dev, "Failed to init Charger\n");
 		goto err_pmic_id;
 	}
+*/
+
+	/* No active discharge on safeout ldo 1,2 */
+	ret = regmap_update_bits(max77843->regmap_chg,
+				 MAX77843_SYS_REG_SAFEOUTCTRL,
+				 0x00, 0x30);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to disable active discharge\n");
+	}
+
+	/* Disable charger */
+	regmap_write(max77843->regmap_chg,MAX77843_CHG_REG_CHG_CNFG_00,0x00);
 
-	ret = regmap_update_bits(max77843->regmap,
+	ret = regmap_update_bits(max77843->regmap_chg,
 				 MAX77843_SYS_REG_INTSRCMASK,
 				 MAX77843_INTSRC_MASK_MASK,
 				 (unsigned int)~MAX77843_INTSRC_MASK_MASK);
diff --git a/include/linux/mfd/max77843-private.h b/include/linux/mfd/max77843-private.h
index 0bc7454c4d..10d294e7ae 100644
--- a/include/linux/mfd/max77843-private.h
+++ b/include/linux/mfd/max77843-private.h
@@ -13,9 +13,9 @@
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 
-#define I2C_ADDR_TOPSYS	(0xCC >> 1)
-#define I2C_ADDR_CHG	(0xD2 >> 1)
-#define I2C_ADDR_FG	(0x6C >> 1)
+//#define I2C_ADDR_TOPSYS	(0xCC >> 1)
+#define I2C_ADDR_CHG	(0xCC >> 1)
+//#define I2C_ADDR_FG	(0x6C >> 1)
 #define I2C_ADDR_MUIC	(0x4A >> 1)
 
 /* Topsys, Haptic and LED registers */
@@ -28,7 +28,6 @@ enum max77843_sys_reg {
 	MAX77843_SYS_REG_SYSINTSRC	= 0x24,
 	MAX77843_SYS_REG_SYSINTMASK	= 0x26,
 	MAX77843_SYS_REG_TOPSYS_STAT	= 0x28,
-	MAX77843_SYS_REG_SAFEOUTCTRL	= 0xC6,
 
 	MAX77843_SYS_REG_END,
 };
@@ -70,6 +69,7 @@ enum max77843_charger_reg {
 	MAX77843_CHG_REG_CHG_CNFG_10	= 0xC1,
 	MAX77843_CHG_REG_CHG_CNFG_11	= 0xC2,
 	MAX77843_CHG_REG_CHG_CNFG_12	= 0xC3,
+	MAX77843_SYS_REG_SAFEOUTCTRL	= 0xC6,
 
 	MAX77843_CHG_REG_END,
 };
@@ -156,6 +156,7 @@ enum max77843_irq {
 enum max77843_irq_muic {
 	/* MUIC: INT1 */
 	MAX77843_MUIC_IRQ_INT1_ADC,
+	MAX77849_MUIC_IRQ_INT1_ADCLOW,
 	MAX77843_MUIC_IRQ_INT1_ADCERROR,
 	MAX77843_MUIC_IRQ_INT1_ADC1K,
 
@@ -165,6 +166,7 @@ enum max77843_irq_muic {
 	MAX77843_MUIC_IRQ_INT2_DCDTMR,
 	MAX77843_MUIC_IRQ_INT2_DXOVP,
 	MAX77843_MUIC_IRQ_INT2_VBVOLT,
+	MAX77849_MUIC_IRQ_INT2_VIDRM,
 
 	/* MUIC: INT3 */
 	MAX77843_MUIC_IRQ_INT3_VBADC,
@@ -283,6 +285,7 @@ enum max77843_irq_muic {
 #define MAX77843_CHG_INPUT_CURRENT_LIMIT_STEP	33000
 
 #define MAX77843_MUIC_ADC			BIT(0)
+#define MAX77849_MUIC_ADCLOW		BIT(1)
 #define MAX77843_MUIC_ADCERROR			BIT(2)
 #define MAX77843_MUIC_ADC1K			BIT(3)
 
@@ -291,6 +294,7 @@ enum max77843_irq_muic {
 #define MAX77843_MUIC_DCDTMR			BIT(2)
 #define MAX77843_MUIC_DXOVP			BIT(3)
 #define MAX77843_MUIC_VBVOLT			BIT(4)
+#define MAX77843_MUIC_VIDRM				BIT(5)
 
 #define MAX77843_MUIC_VBADC			BIT(0)
 #define MAX77843_MUIC_VDNMON			BIT(1)
@@ -303,21 +307,25 @@ enum max77843_irq_muic {
 
 /* MAX77843 INTSRCMASK register */
 #define MAX77843_INTSRCMASK_CHGR		0
-#define MAX77843_INTSRCMASK_SYS			1
-#define MAX77843_INTSRCMASK_FG			2
-#define MAX77843_INTSRCMASK_MUIC		3
+#define MAX77843_INTSRCMASK_SYS			2
+//#define MAX77843_INTSRCMASK_FG			2 //not in downstream
+#define MAX77843_INTSRCMASK_MUIC		1
 
 #define MAX77843_INTSRCMASK_CHGR_MASK BIT(MAX77843_INTSRCMASK_CHGR)
 #define MAX77843_INTSRCMASK_SYS_MASK BIT(MAX77843_INTSRCMASK_SYS)
 #define MAX77843_INTSRCMASK_FG_MASK BIT(MAX77843_INTSRCMASK_FG)
 #define MAX77843_INTSRCMASK_MUIC_MASK BIT(MAX77843_INTSRCMASK_MUIC)
 
+/*Only unmask muic for now
 #define MAX77843_INTSRC_MASK_MASK \
 	(MAX77843_INTSRCMASK_MUIC_MASK | MAX77843_INTSRCMASK_FG_MASK | \
 	MAX77843_INTSRCMASK_SYS_MASK | MAX77843_INTSRCMASK_CHGR_MASK)
+*/
+#define MAX77843_INTSRC_MASK_MASK 	(MAX77843_INTSRCMASK_MUIC_MASK)
 
 /* MAX77843 STATUS register*/
 #define MAX77843_MUIC_STATUS1_ADC_SHIFT		0
+#define MAX77849_MUIC_STATUS1_ADCLOW_SHIFT		5
 #define MAX77843_MUIC_STATUS1_ADCERROR_SHIFT	6
 #define MAX77843_MUIC_STATUS1_ADC1K_SHIFT	7
 #define MAX77843_MUIC_STATUS2_CHGTYP_SHIFT	0
@@ -331,6 +339,7 @@ enum max77843_irq_muic {
 #define MAX77843_MUIC_STATUS3_MPNACK_SHIFT	6
 
 #define MAX77843_MUIC_STATUS1_ADC_MASK		(0x1f << MAX77843_MUIC_STATUS1_ADC_SHIFT)
+#define MAX77849_MUIC_STATUS1_ADCLOW_MASK	BIT(MAX77849_MUIC_STATUS1_ADCLOW_SHIFT)
 #define MAX77843_MUIC_STATUS1_ADCERROR_MASK	BIT(MAX77843_MUIC_STATUS1_ADCERROR_SHIFT)
 #define MAX77843_MUIC_STATUS1_ADC1K_MASK	BIT(MAX77843_MUIC_STATUS1_ADC1K_SHIFT)
 #define MAX77843_MUIC_STATUS2_CHGTYP_MASK	(0x7 << MAX77843_MUIC_STATUS2_CHGTYP_SHIFT)
Reference datasheets (similar devices)
* MFD : https://www.infinite-electronic.kr/datasheet/94-MAX14616AEWA.pd 
* Charger : https://datasheets.maximintegrated.com/en/ds/MAX77860.pdf
* Others : 
*# https://datasheets.maximintegrated.com/en/ds/MAX77818.pdf
*# https://datasheets.maximintegrated.com/en/ds/MAX77829.pdf
== Hardware / sensor status and details ==
Output from hwtest on SM-T350, pmos V23.12.
Note that hwtest expects accelerometer units to be g, whereas the data appear to be m/s2.
hwtest
Category 	Model 	Path 	Status 	Value
framebuffer 	msmdrmfb 	/sys/class/graphics/fb0 	Working	U:768x1024p-0
drm 	 	/sys/class/drm/card0-DSI-1 	Working	768x1024
accelerometer	lis2hh12 	/sys/bus/iio/devices/iio:device2	Working	5.22, 0.57, -8.17 g
vibrator 	gpio-vibrator 	/dev/input/event5 	Working	
input 	pm8941_pwrkey 	/dev/input/event0 	Working	
input 	pm8941_resin 	/dev/input/event1 	Working	
input 	GPIO Buttons 	/dev/input/event2 	Working	
input 	GPIO Hall Effect Sensor 	/dev/input/event3 	Working	
input 	Zinitix Capacitive TouchScreen	/dev/input/event4 	Working	
input 	samsung-a2015 Headset Jack 	/dev/input/event6 	Working	
== GPS investigation gt58wifi (SM-T350) ==
For overview, see Snapdragon 410/412#Modem
Test setup: pre-built image, v24.06, soc-qcom-msm8916-rproc-all, phosh/mmcli.
Location service is enumerated,
 $ qrtr-lookup 16
 Service Version Instance Node Port
 16 2 0 0 14 Location service (~ PDS v2)
Due to "no modem", replace device /dev/modem with uri qrtr://0 (undocumented, or worse).
Location features are get/set-able,
 # qmicli -V
 qmicli 1.34.0
 # qmicli -d qrtr://0 --loc-get-nmea-types
 Successfully retrieved NMEA types: gga, rmc, gsv, gsa, vtg, pqxfi, pstis
 # qmicli -d qrtr://0 --loc-get-engine-lock
 Successfully retrieved engine lock: none
But, almost any hack may work, since the api is apparently autogenerated, not designed,
 # qmicli -d qrtr://-0:anything-here! --loc-get-operation-mode
 Successfully retrieved operation mode: standalone
 # qmicli -d qrtr://-1 --loc-get-operation-mode
 error: node with id 4294967295 not found in QRTR bus
Ignorant end-user attempts at matching Snapdragon 410/412#GNSS_(GPS) fail
 # qmicli -d qrtr://0 --loc-start --client-no-release-cid
 [qrtr://0] Successfully started location tracking (session id 0)
 [qrtr://0] Client ID not released:
 Service: 'loc'
 CID: '1'
 # qmicli -d qrtr://0 --loc-follow-nmea --client-cid=1
 error: operation failed: Unknown client 1 for service loc
"Downstream gpsd-pds" works. See arrow-db410c#Location_service_(PDS).
 
If you're interested in bringing up the modem/gps on APQ variants of the device, feel free to reach out to travmurav via pmOS Matrix_and_IRC channels.
== See also ==
* 
* msm8916 mainline kernel package
* Samsung_Galaxy_Tab_A_9.7_2015_(samsung-gt510)
* Mainline kernel tree for msm8916 devices