2018-08-30 19:51:03 +03:00
// SPDX-License-Identifier: GPL-2.0
2014-11-24 17:24:47 +08:00
/*
2018-08-30 19:51:03 +03:00
* XPower AXP288 PMIC operation region driver
2014-11-24 17:24:47 +08:00
*
* Copyright ( C ) 2014 Intel Corporation . All rights reserved .
*/
# include <linux/acpi.h>
2018-08-30 19:51:02 +03:00
# include <linux/init.h>
2014-11-24 17:24:47 +08:00
# include <linux/mfd/axp20x.h>
2018-08-30 19:51:02 +03:00
# include <linux/regmap.h>
2018-10-11 16:29:10 +02:00
# include <linux/platform_device.h>
# include <asm/iosf_mbi.h>
2014-11-24 17:24:47 +08:00
# include "intel_pmic.h"
# define XPOWER_GPADC_LOW 0x5b
2017-05-14 23:35:39 +02:00
# define XPOWER_GPI1_CTRL 0x92
# define GPI1_LDO_MASK GENMASK(2, 0)
# define GPI1_LDO_ON (3 << 0)
# define GPI1_LDO_OFF (4 << 0)
2014-11-24 17:24:47 +08:00
2017-07-08 15:40:08 +02:00
# define AXP288_ADC_TS_PIN_GPADC 0xf2
# define AXP288_ADC_TS_PIN_ON 0xf3
2014-11-24 17:24:47 +08:00
static struct pmic_table power_table [ ] = {
{
. address = 0x00 ,
. reg = 0x13 ,
. bit = 0x05 ,
2017-04-21 13:48:08 +02:00
} , /* ALD1 */
2014-11-24 17:24:47 +08:00
{
. address = 0x04 ,
. reg = 0x13 ,
. bit = 0x06 ,
2017-04-21 13:48:08 +02:00
} , /* ALD2 */
2014-11-24 17:24:47 +08:00
{
. address = 0x08 ,
. reg = 0x13 ,
. bit = 0x07 ,
2017-04-21 13:48:08 +02:00
} , /* ALD3 */
2014-11-24 17:24:47 +08:00
{
. address = 0x0c ,
. reg = 0x12 ,
. bit = 0x03 ,
2017-04-21 13:48:08 +02:00
} , /* DLD1 */
2014-11-24 17:24:47 +08:00
{
. address = 0x10 ,
. reg = 0x12 ,
. bit = 0x04 ,
2017-04-21 13:48:08 +02:00
} , /* DLD2 */
2014-11-24 17:24:47 +08:00
{
. address = 0x14 ,
. reg = 0x12 ,
. bit = 0x05 ,
2017-04-21 13:48:08 +02:00
} , /* DLD3 */
2014-11-24 17:24:47 +08:00
{
. address = 0x18 ,
. reg = 0x12 ,
. bit = 0x06 ,
2017-04-21 13:48:08 +02:00
} , /* DLD4 */
2014-11-24 17:24:47 +08:00
{
. address = 0x1c ,
. reg = 0x12 ,
. bit = 0x00 ,
2017-04-21 13:48:08 +02:00
} , /* ELD1 */
2014-11-24 17:24:47 +08:00
{
. address = 0x20 ,
. reg = 0x12 ,
. bit = 0x01 ,
2017-04-21 13:48:08 +02:00
} , /* ELD2 */
2014-11-24 17:24:47 +08:00
{
. address = 0x24 ,
. reg = 0x12 ,
. bit = 0x02 ,
2017-04-21 13:48:08 +02:00
} , /* ELD3 */
2014-11-24 17:24:47 +08:00
{
. address = 0x28 ,
. reg = 0x13 ,
. bit = 0x02 ,
2017-04-21 13:48:08 +02:00
} , /* FLD1 */
2014-11-24 17:24:47 +08:00
{
. address = 0x2c ,
. reg = 0x13 ,
. bit = 0x03 ,
2017-04-21 13:48:08 +02:00
} , /* FLD2 */
2014-11-24 17:24:47 +08:00
{
. address = 0x30 ,
. reg = 0x13 ,
. bit = 0x04 ,
2017-04-21 13:48:08 +02:00
} , /* FLD3 */
2014-11-24 17:24:47 +08:00
{
2017-04-21 13:48:08 +02:00
. address = 0x34 ,
2014-11-24 17:24:47 +08:00
. reg = 0x10 ,
. bit = 0x03 ,
2017-04-21 13:48:08 +02:00
} , /* BUC1 */
2014-11-24 17:24:47 +08:00
{
2017-04-21 13:48:08 +02:00
. address = 0x38 ,
2014-11-24 17:24:47 +08:00
. reg = 0x10 ,
. bit = 0x06 ,
2017-04-21 13:48:08 +02:00
} , /* BUC2 */
2014-11-24 17:24:47 +08:00
{
2017-04-21 13:48:08 +02:00
. address = 0x3c ,
2014-11-24 17:24:47 +08:00
. reg = 0x10 ,
. bit = 0x05 ,
2017-04-21 13:48:08 +02:00
} , /* BUC3 */
2014-11-24 17:24:47 +08:00
{
2017-04-21 13:48:08 +02:00
. address = 0x40 ,
2014-11-24 17:24:47 +08:00
. reg = 0x10 ,
. bit = 0x04 ,
2017-04-21 13:48:08 +02:00
} , /* BUC4 */
2014-11-24 17:24:47 +08:00
{
2017-04-21 13:48:08 +02:00
. address = 0x44 ,
2014-11-24 17:24:47 +08:00
. reg = 0x10 ,
. bit = 0x01 ,
2017-04-21 13:48:08 +02:00
} , /* BUC5 */
2014-11-24 17:24:47 +08:00
{
2017-04-21 13:48:08 +02:00
. address = 0x48 ,
2014-11-24 17:24:47 +08:00
. reg = 0x10 ,
. bit = 0x00
2017-04-21 13:48:08 +02:00
} , /* BUC6 */
2017-05-14 23:35:39 +02:00
{
. address = 0x4c ,
. reg = 0x92 ,
} , /* GPI1 */
2014-11-24 17:24:47 +08:00
} ;
/* TMP0 - TMP5 are the same, all from GPADC */
static struct pmic_table thermal_table [ ] = {
{
. address = 0x00 ,
. reg = XPOWER_GPADC_LOW
} ,
{
. address = 0x0c ,
. reg = XPOWER_GPADC_LOW
} ,
{
. address = 0x18 ,
. reg = XPOWER_GPADC_LOW
} ,
{
. address = 0x24 ,
. reg = XPOWER_GPADC_LOW
} ,
{
. address = 0x30 ,
. reg = XPOWER_GPADC_LOW
} ,
{
. address = 0x3c ,
. reg = XPOWER_GPADC_LOW
} ,
} ;
static int intel_xpower_pmic_get_power ( struct regmap * regmap , int reg ,
int bit , u64 * value )
{
int data ;
if ( regmap_read ( regmap , reg , & data ) )
return - EIO ;
2017-05-14 23:35:39 +02:00
/* GPIO1 LDO regulator needs special handling */
if ( reg = = XPOWER_GPI1_CTRL )
* value = ( ( data & GPI1_LDO_MASK ) = = GPI1_LDO_ON ) ;
else
* value = ( data & BIT ( bit ) ) ? 1 : 0 ;
2014-11-24 17:24:47 +08:00
return 0 ;
}
static int intel_xpower_pmic_update_power ( struct regmap * regmap , int reg ,
int bit , bool on )
{
2018-10-11 16:29:10 +02:00
int data , ret ;
2014-11-24 17:24:47 +08:00
2017-05-14 23:35:39 +02:00
/* GPIO1 LDO regulator needs special handling */
if ( reg = = XPOWER_GPI1_CTRL )
return regmap_update_bits ( regmap , reg , GPI1_LDO_MASK ,
on ? GPI1_LDO_ON : GPI1_LDO_OFF ) ;
2018-10-11 16:29:10 +02:00
ret = iosf_mbi_block_punit_i2c_access ( ) ;
if ( ret )
return ret ;
if ( regmap_read ( regmap , reg , & data ) ) {
ret = - EIO ;
goto out ;
}
2014-11-24 17:24:47 +08:00
if ( on )
data | = BIT ( bit ) ;
else
data & = ~ BIT ( bit ) ;
if ( regmap_write ( regmap , reg , data ) )
2018-10-11 16:29:10 +02:00
ret = - EIO ;
out :
iosf_mbi_unblock_punit_i2c_access ( ) ;
2014-11-24 17:24:47 +08:00
2018-10-11 16:29:10 +02:00
return ret ;
2014-11-24 17:24:47 +08:00
}
/**
* intel_xpower_pmic_get_raw_temp ( ) : Get raw temperature reading from the PMIC
*
* @ regmap : regmap of the PMIC device
* @ reg : register to get the reading
*
* Return a positive value on success , errno on failure .
*/
static int intel_xpower_pmic_get_raw_temp ( struct regmap * regmap , int reg )
{
2017-04-19 15:07:00 +02:00
u8 buf [ 2 ] ;
2017-07-08 15:40:08 +02:00
int ret ;
2014-11-24 17:24:47 +08:00
2017-07-08 15:40:08 +02:00
ret = regmap_write ( regmap , AXP288_ADC_TS_PIN_CTRL ,
AXP288_ADC_TS_PIN_GPADC ) ;
if ( ret )
return ret ;
/* After switching to the GPADC pin give things some time to settle */
usleep_range ( 6000 , 10000 ) ;
ret = regmap_bulk_read ( regmap , AXP288_GP_ADC_H , buf , 2 ) ;
if ( ret = = 0 )
ret = ( buf [ 0 ] < < 4 ) + ( ( buf [ 1 ] > > 4 ) & 0x0f ) ;
regmap_write ( regmap , AXP288_ADC_TS_PIN_CTRL , AXP288_ADC_TS_PIN_ON ) ;
2014-11-24 17:24:47 +08:00
2017-07-08 15:40:08 +02:00
return ret ;
2014-11-24 17:24:47 +08:00
}
static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = {
. get_power = intel_xpower_pmic_get_power ,
. update_power = intel_xpower_pmic_update_power ,
. get_raw_temp = intel_xpower_pmic_get_raw_temp ,
. power_table = power_table ,
. power_table_count = ARRAY_SIZE ( power_table ) ,
. thermal_table = thermal_table ,
. thermal_table_count = ARRAY_SIZE ( thermal_table ) ,
} ;
2014-11-24 17:32:33 +08:00
static acpi_status intel_xpower_pmic_gpio_handler ( u32 function ,
acpi_physical_address address , u32 bit_width , u64 * value ,
void * handler_context , void * region_context )
{
return AE_OK ;
}
2014-11-24 17:24:47 +08:00
static int intel_xpower_pmic_opregion_probe ( struct platform_device * pdev )
{
2014-11-24 17:32:33 +08:00
struct device * parent = pdev - > dev . parent ;
struct axp20x_dev * axp20x = dev_get_drvdata ( parent ) ;
acpi_status status ;
int result ;
status = acpi_install_address_space_handler ( ACPI_HANDLE ( parent ) ,
ACPI_ADR_SPACE_GPIO , intel_xpower_pmic_gpio_handler ,
NULL , NULL ) ;
if ( ACPI_FAILURE ( status ) )
return - ENODEV ;
result = intel_pmic_install_opregion_handler ( & pdev - > dev ,
ACPI_HANDLE ( parent ) , axp20x - > regmap ,
& intel_xpower_pmic_opregion_data ) ;
if ( result )
acpi_remove_address_space_handler ( ACPI_HANDLE ( parent ) ,
ACPI_ADR_SPACE_GPIO ,
intel_xpower_pmic_gpio_handler ) ;
return result ;
2014-11-24 17:24:47 +08:00
}
static struct platform_driver intel_xpower_pmic_opregion_driver = {
. probe = intel_xpower_pmic_opregion_probe ,
. driver = {
. name = " axp288_pmic_acpi " ,
} ,
} ;
2018-01-09 22:26:58 +02:00
builtin_platform_driver ( intel_xpower_pmic_opregion_driver ) ;