2018-08-30 19:52:54 +03:00
// SPDX-License-Identifier: GPL-2.0
2014-06-03 09:26:02 +04:00
/*
2018-08-30 19:52:54 +03:00
* Intel SoC PMIC MFD Driver
2014-06-03 09:26:02 +04:00
*
* Copyright ( C ) 2013 , 2014 Intel Corporation . All rights reserved .
*
* Author : Yang , Bin < bin . yang @ intel . com >
* Author : Zhu , Lejun < lejun . zhu @ linux . intel . com >
*/
2018-08-30 19:52:53 +03:00
# include <linux/acpi.h>
2014-06-03 09:26:02 +04:00
# include <linux/i2c.h>
# include <linux/interrupt.h>
2018-08-30 19:52:53 +03:00
# include <linux/module.h>
# include <linux/mfd/core.h>
2014-06-03 09:26:02 +04:00
# include <linux/mfd/intel_soc_pmic.h>
2015-06-26 12:02:07 +03:00
# include <linux/pwm.h>
2018-08-30 19:52:53 +03:00
# include <linux/regmap.h>
2014-06-03 09:26:02 +04:00
# include "intel_soc_pmic_core.h"
2017-09-04 16:22:42 +03:00
/* Crystal Cove PMIC shares same ACPI ID between different platforms */
# define BYT_CRC_HRV 2
# define CHT_CRC_HRV 3
2015-06-26 12:02:07 +03:00
/* PWM consumed by the Intel GFX */
static struct pwm_lookup crc_pwm_lookup [ ] = {
2019-12-16 23:29:05 +03:00
PWM_LOOKUP ( " crystal_cove_pwm " , 0 , " 0000:00:02.0 " , " pwm_pmic_backlight " , 0 , PWM_POLARITY_NORMAL ) ,
2015-06-26 12:02:07 +03:00
} ;
2014-06-03 09:26:02 +04:00
static int intel_soc_pmic_i2c_probe ( struct i2c_client * i2c ,
const struct i2c_device_id * i2c_id )
{
struct device * dev = & i2c - > dev ;
struct intel_soc_pmic_config * config ;
struct intel_soc_pmic * pmic ;
2017-09-04 16:22:42 +03:00
unsigned long long hrv ;
acpi_status status ;
2014-06-03 09:26:02 +04:00
int ret ;
2017-09-04 16:22:42 +03:00
/*
* There are 2 different Crystal Cove PMICs a Bay Trail and Cherry
* Trail version , use _HRV to differentiate between the 2.
*/
status = acpi_evaluate_integer ( ACPI_HANDLE ( dev ) , " _HRV " , NULL , & hrv ) ;
if ( ACPI_FAILURE ( status ) ) {
dev_err ( dev , " Failed to get PMIC hardware revision \n " ) ;
2014-06-03 09:26:02 +04:00
return - ENODEV ;
2017-09-04 16:22:42 +03:00
}
switch ( hrv ) {
case BYT_CRC_HRV :
config = & intel_soc_pmic_config_byt_crc ;
break ;
case CHT_CRC_HRV :
config = & intel_soc_pmic_config_cht_crc ;
break ;
default :
dev_warn ( dev , " Unknown hardware rev %llu, assuming BYT \n " , hrv ) ;
config = & intel_soc_pmic_config_byt_crc ;
}
2014-06-03 09:26:02 +04:00
pmic = devm_kzalloc ( dev , sizeof ( * pmic ) , GFP_KERNEL ) ;
2015-02-11 13:10:50 +03:00
if ( ! pmic )
return - ENOMEM ;
2014-06-03 09:26:02 +04:00
dev_set_drvdata ( dev , pmic ) ;
pmic - > regmap = devm_regmap_init_i2c ( i2c , config - > regmap_config ) ;
2017-04-23 15:29:24 +03:00
if ( IS_ERR ( pmic - > regmap ) )
return PTR_ERR ( pmic - > regmap ) ;
2017-02-21 14:09:14 +03:00
pmic - > irq = i2c - > irq ;
2014-06-03 09:26:02 +04:00
ret = regmap_add_irq_chip ( pmic - > regmap , pmic - > irq ,
config - > irq_flags | IRQF_ONESHOT ,
0 , config - > irq_chip ,
& pmic - > irq_chip_data ) ;
if ( ret )
return ret ;
ret = enable_irq_wake ( pmic - > irq ) ;
if ( ret )
dev_warn ( dev , " Can't enable IRQ as wake source: %d \n " , ret ) ;
2015-06-26 12:02:07 +03:00
/* Add lookup table for crc-pwm */
pwm_add_table ( crc_pwm_lookup , ARRAY_SIZE ( crc_pwm_lookup ) ) ;
2014-06-03 09:26:02 +04:00
ret = mfd_add_devices ( dev , - 1 , config - > cell_dev ,
config - > n_cell_devs , NULL , 0 ,
regmap_irq_get_domain ( pmic - > irq_chip_data ) ) ;
if ( ret )
goto err_del_irq_chip ;
return 0 ;
err_del_irq_chip :
regmap_del_irq_chip ( pmic - > irq , pmic - > irq_chip_data ) ;
return ret ;
}
static int intel_soc_pmic_i2c_remove ( struct i2c_client * i2c )
{
struct intel_soc_pmic * pmic = dev_get_drvdata ( & i2c - > dev ) ;
regmap_del_irq_chip ( pmic - > irq , pmic - > irq_chip_data ) ;
2015-06-26 12:02:07 +03:00
/* remove crc-pwm lookup table */
pwm_remove_table ( crc_pwm_lookup , ARRAY_SIZE ( crc_pwm_lookup ) ) ;
2014-06-03 09:26:02 +04:00
mfd_remove_devices ( & i2c - > dev ) ;
return 0 ;
}
static void intel_soc_pmic_shutdown ( struct i2c_client * i2c )
{
struct intel_soc_pmic * pmic = dev_get_drvdata ( & i2c - > dev ) ;
disable_irq ( pmic - > irq ) ;
return ;
}
2014-09-12 08:35:45 +04:00
# if defined(CONFIG_PM_SLEEP)
2014-06-03 09:26:02 +04:00
static int intel_soc_pmic_suspend ( struct device * dev )
{
struct intel_soc_pmic * pmic = dev_get_drvdata ( dev ) ;
disable_irq ( pmic - > irq ) ;
return 0 ;
}
static int intel_soc_pmic_resume ( struct device * dev )
{
struct intel_soc_pmic * pmic = dev_get_drvdata ( dev ) ;
enable_irq ( pmic - > irq ) ;
return 0 ;
}
2014-09-12 08:35:45 +04:00
# endif
2014-06-03 09:26:02 +04:00
static SIMPLE_DEV_PM_OPS ( intel_soc_pmic_pm_ops , intel_soc_pmic_suspend ,
intel_soc_pmic_resume ) ;
static const struct i2c_device_id intel_soc_pmic_i2c_id [ ] = {
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , intel_soc_pmic_i2c_id ) ;
2014-07-02 14:30:12 +04:00
# if defined(CONFIG_ACPI)
2015-06-13 15:20:51 +03:00
static const struct acpi_device_id intel_soc_pmic_acpi_match [ ] = {
2017-09-04 16:22:42 +03:00
{ " INT33FD " } ,
2014-06-03 09:26:02 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( acpi , intel_soc_pmic_acpi_match ) ;
2014-07-02 14:30:12 +04:00
# endif
2014-06-03 09:26:02 +04:00
static struct i2c_driver intel_soc_pmic_i2c_driver = {
. driver = {
. name = " intel_soc_pmic_i2c " ,
. pm = & intel_soc_pmic_pm_ops ,
. acpi_match_table = ACPI_PTR ( intel_soc_pmic_acpi_match ) ,
} ,
. probe = intel_soc_pmic_i2c_probe ,
. remove = intel_soc_pmic_i2c_remove ,
. id_table = intel_soc_pmic_i2c_id ,
. shutdown = intel_soc_pmic_shutdown ,
} ;
module_i2c_driver ( intel_soc_pmic_i2c_driver ) ;
MODULE_DESCRIPTION ( " I2C driver for Intel SoC PMIC " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Yang, Bin <bin.yang@intel.com> " ) ;
MODULE_AUTHOR ( " Zhu, Lejun <lejun.zhu@linux.intel.com> " ) ;