2019-05-27 09:55:06 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2015-07-01 16:11:32 +03:00
/*
2017-04-03 17:46:40 +03:00
* Core , IRQ and I2C device driver for DA9061 and DA9062 PMICs
* Copyright ( C ) 2015 - 2017 Dialog Semiconductor
2015-07-01 16:11:32 +03:00
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/device.h>
# include <linux/interrupt.h>
2021-05-26 15:47:02 +03:00
# include <linux/of_device.h>
2015-07-01 16:11:32 +03:00
# include <linux/regmap.h>
# include <linux/irq.h>
# include <linux/mfd/core.h>
# include <linux/i2c.h>
# include <linux/mfd/da9062/core.h>
# include <linux/mfd/da9062/registers.h>
# include <linux/regulator/of_regulator.h>
# define DA9062_REG_EVENT_A_OFFSET 0
# define DA9062_REG_EVENT_B_OFFSET 1
# define DA9062_REG_EVENT_C_OFFSET 2
2020-02-26 04:07:22 +03:00
# define DA9062_IRQ_LOW 0
# define DA9062_IRQ_HIGH 1
2017-04-03 17:46:40 +03:00
static struct regmap_irq da9061_irqs [ ] = {
/* EVENT A */
[ DA9061_IRQ_ONKEY ] = {
. reg_offset = DA9062_REG_EVENT_A_OFFSET ,
. mask = DA9062AA_M_NONKEY_MASK ,
} ,
[ DA9061_IRQ_WDG_WARN ] = {
. reg_offset = DA9062_REG_EVENT_A_OFFSET ,
. mask = DA9062AA_M_WDG_WARN_MASK ,
} ,
[ DA9061_IRQ_SEQ_RDY ] = {
. reg_offset = DA9062_REG_EVENT_A_OFFSET ,
. mask = DA9062AA_M_SEQ_RDY_MASK ,
} ,
/* EVENT B */
[ DA9061_IRQ_TEMP ] = {
. reg_offset = DA9062_REG_EVENT_B_OFFSET ,
. mask = DA9062AA_M_TEMP_MASK ,
} ,
[ DA9061_IRQ_LDO_LIM ] = {
. reg_offset = DA9062_REG_EVENT_B_OFFSET ,
. mask = DA9062AA_M_LDO_LIM_MASK ,
} ,
[ DA9061_IRQ_DVC_RDY ] = {
. reg_offset = DA9062_REG_EVENT_B_OFFSET ,
. mask = DA9062AA_M_DVC_RDY_MASK ,
} ,
[ DA9061_IRQ_VDD_WARN ] = {
. reg_offset = DA9062_REG_EVENT_B_OFFSET ,
. mask = DA9062AA_M_VDD_WARN_MASK ,
} ,
/* EVENT C */
[ DA9061_IRQ_GPI0 ] = {
. reg_offset = DA9062_REG_EVENT_C_OFFSET ,
. mask = DA9062AA_M_GPI0_MASK ,
} ,
[ DA9061_IRQ_GPI1 ] = {
. reg_offset = DA9062_REG_EVENT_C_OFFSET ,
. mask = DA9062AA_M_GPI1_MASK ,
} ,
[ DA9061_IRQ_GPI2 ] = {
. reg_offset = DA9062_REG_EVENT_C_OFFSET ,
. mask = DA9062AA_M_GPI2_MASK ,
} ,
[ DA9061_IRQ_GPI3 ] = {
. reg_offset = DA9062_REG_EVENT_C_OFFSET ,
. mask = DA9062AA_M_GPI3_MASK ,
} ,
[ DA9061_IRQ_GPI4 ] = {
. reg_offset = DA9062_REG_EVENT_C_OFFSET ,
. mask = DA9062AA_M_GPI4_MASK ,
} ,
} ;
static struct regmap_irq_chip da9061_irq_chip = {
. name = " da9061-irq " ,
. irqs = da9061_irqs ,
. num_irqs = DA9061_NUM_IRQ ,
. num_regs = 3 ,
. status_base = DA9062AA_EVENT_A ,
. mask_base = DA9062AA_IRQ_MASK_A ,
. ack_base = DA9062AA_EVENT_A ,
} ;
2015-07-01 16:11:32 +03:00
static struct regmap_irq da9062_irqs [ ] = {
/* EVENT A */
[ DA9062_IRQ_ONKEY ] = {
. reg_offset = DA9062_REG_EVENT_A_OFFSET ,
. mask = DA9062AA_M_NONKEY_MASK ,
} ,
[ DA9062_IRQ_ALARM ] = {
. reg_offset = DA9062_REG_EVENT_A_OFFSET ,
. mask = DA9062AA_M_ALARM_MASK ,
} ,
[ DA9062_IRQ_TICK ] = {
. reg_offset = DA9062_REG_EVENT_A_OFFSET ,
. mask = DA9062AA_M_TICK_MASK ,
} ,
[ DA9062_IRQ_WDG_WARN ] = {
. reg_offset = DA9062_REG_EVENT_A_OFFSET ,
. mask = DA9062AA_M_WDG_WARN_MASK ,
} ,
[ DA9062_IRQ_SEQ_RDY ] = {
. reg_offset = DA9062_REG_EVENT_A_OFFSET ,
. mask = DA9062AA_M_SEQ_RDY_MASK ,
} ,
/* EVENT B */
[ DA9062_IRQ_TEMP ] = {
. reg_offset = DA9062_REG_EVENT_B_OFFSET ,
. mask = DA9062AA_M_TEMP_MASK ,
} ,
[ DA9062_IRQ_LDO_LIM ] = {
. reg_offset = DA9062_REG_EVENT_B_OFFSET ,
. mask = DA9062AA_M_LDO_LIM_MASK ,
} ,
[ DA9062_IRQ_DVC_RDY ] = {
. reg_offset = DA9062_REG_EVENT_B_OFFSET ,
. mask = DA9062AA_M_DVC_RDY_MASK ,
} ,
[ DA9062_IRQ_VDD_WARN ] = {
. reg_offset = DA9062_REG_EVENT_B_OFFSET ,
. mask = DA9062AA_M_VDD_WARN_MASK ,
} ,
/* EVENT C */
[ DA9062_IRQ_GPI0 ] = {
. reg_offset = DA9062_REG_EVENT_C_OFFSET ,
. mask = DA9062AA_M_GPI0_MASK ,
} ,
[ DA9062_IRQ_GPI1 ] = {
. reg_offset = DA9062_REG_EVENT_C_OFFSET ,
. mask = DA9062AA_M_GPI1_MASK ,
} ,
[ DA9062_IRQ_GPI2 ] = {
. reg_offset = DA9062_REG_EVENT_C_OFFSET ,
. mask = DA9062AA_M_GPI2_MASK ,
} ,
[ DA9062_IRQ_GPI3 ] = {
. reg_offset = DA9062_REG_EVENT_C_OFFSET ,
. mask = DA9062AA_M_GPI3_MASK ,
} ,
[ DA9062_IRQ_GPI4 ] = {
. reg_offset = DA9062_REG_EVENT_C_OFFSET ,
. mask = DA9062AA_M_GPI4_MASK ,
} ,
} ;
static struct regmap_irq_chip da9062_irq_chip = {
. name = " da9062-irq " ,
. irqs = da9062_irqs ,
. num_irqs = DA9062_NUM_IRQ ,
. num_regs = 3 ,
. status_base = DA9062AA_EVENT_A ,
. mask_base = DA9062AA_IRQ_MASK_A ,
. ack_base = DA9062AA_EVENT_A ,
} ;
2020-09-22 22:26:52 +03:00
static const struct resource da9061_core_resources [ ] = {
2017-04-03 17:46:40 +03:00
DEFINE_RES_IRQ_NAMED ( DA9061_IRQ_VDD_WARN , " VDD_WARN " ) ,
} ;
2020-09-22 22:26:52 +03:00
static const struct resource da9061_regulators_resources [ ] = {
2017-04-03 17:46:40 +03:00
DEFINE_RES_IRQ_NAMED ( DA9061_IRQ_LDO_LIM , " LDO_LIM " ) ,
} ;
2020-09-22 22:26:52 +03:00
static const struct resource da9061_thermal_resources [ ] = {
2017-04-03 17:46:40 +03:00
DEFINE_RES_IRQ_NAMED ( DA9061_IRQ_TEMP , " THERMAL " ) ,
} ;
2020-09-22 22:26:52 +03:00
static const struct resource da9061_wdt_resources [ ] = {
2017-04-03 17:46:40 +03:00
DEFINE_RES_IRQ_NAMED ( DA9061_IRQ_WDG_WARN , " WD_WARN " ) ,
} ;
2020-09-22 22:26:52 +03:00
static const struct resource da9061_onkey_resources [ ] = {
2017-04-03 17:46:40 +03:00
DEFINE_RES_IRQ_NAMED ( DA9061_IRQ_ONKEY , " ONKEY " ) ,
} ;
static const struct mfd_cell da9061_devs [ ] = {
{
. name = " da9061-core " ,
. num_resources = ARRAY_SIZE ( da9061_core_resources ) ,
. resources = da9061_core_resources ,
} ,
{
. name = " da9062-regulators " ,
. num_resources = ARRAY_SIZE ( da9061_regulators_resources ) ,
. resources = da9061_regulators_resources ,
} ,
{
. name = " da9061-watchdog " ,
. num_resources = ARRAY_SIZE ( da9061_wdt_resources ) ,
. resources = da9061_wdt_resources ,
. of_compatible = " dlg,da9061-watchdog " ,
} ,
{
. name = " da9061-thermal " ,
. num_resources = ARRAY_SIZE ( da9061_thermal_resources ) ,
. resources = da9061_thermal_resources ,
. of_compatible = " dlg,da9061-thermal " ,
} ,
{
. name = " da9061-onkey " ,
. num_resources = ARRAY_SIZE ( da9061_onkey_resources ) ,
. resources = da9061_onkey_resources ,
. of_compatible = " dlg,da9061-onkey " ,
} ,
} ;
2020-09-22 22:26:52 +03:00
static const struct resource da9062_core_resources [ ] = {
2015-07-01 16:11:32 +03:00
DEFINE_RES_NAMED ( DA9062_IRQ_VDD_WARN , 1 , " VDD_WARN " , IORESOURCE_IRQ ) ,
} ;
2020-09-22 22:26:52 +03:00
static const struct resource da9062_regulators_resources [ ] = {
2015-07-01 16:11:32 +03:00
DEFINE_RES_NAMED ( DA9062_IRQ_LDO_LIM , 1 , " LDO_LIM " , IORESOURCE_IRQ ) ,
} ;
2020-09-22 22:26:52 +03:00
static const struct resource da9062_thermal_resources [ ] = {
2015-07-01 16:11:32 +03:00
DEFINE_RES_NAMED ( DA9062_IRQ_TEMP , 1 , " THERMAL " , IORESOURCE_IRQ ) ,
} ;
2020-09-22 22:26:52 +03:00
static const struct resource da9062_wdt_resources [ ] = {
2015-07-01 16:11:32 +03:00
DEFINE_RES_NAMED ( DA9062_IRQ_WDG_WARN , 1 , " WD_WARN " , IORESOURCE_IRQ ) ,
} ;
2020-09-22 22:26:52 +03:00
static const struct resource da9062_rtc_resources [ ] = {
2015-07-21 13:29:06 +03:00
DEFINE_RES_NAMED ( DA9062_IRQ_ALARM , 1 , " ALARM " , IORESOURCE_IRQ ) ,
DEFINE_RES_NAMED ( DA9062_IRQ_TICK , 1 , " TICK " , IORESOURCE_IRQ ) ,
} ;
2020-09-22 22:26:52 +03:00
static const struct resource da9062_onkey_resources [ ] = {
2015-07-23 19:17:41 +03:00
DEFINE_RES_NAMED ( DA9062_IRQ_ONKEY , 1 , " ONKEY " , IORESOURCE_IRQ ) ,
} ;
2020-09-22 22:26:52 +03:00
static const struct resource da9062_gpio_resources [ ] = {
2019-12-12 19:04:12 +03:00
DEFINE_RES_NAMED ( DA9062_IRQ_GPI0 , 1 , " GPI0 " , IORESOURCE_IRQ ) ,
DEFINE_RES_NAMED ( DA9062_IRQ_GPI1 , 1 , " GPI1 " , IORESOURCE_IRQ ) ,
DEFINE_RES_NAMED ( DA9062_IRQ_GPI2 , 1 , " GPI2 " , IORESOURCE_IRQ ) ,
DEFINE_RES_NAMED ( DA9062_IRQ_GPI3 , 1 , " GPI3 " , IORESOURCE_IRQ ) ,
DEFINE_RES_NAMED ( DA9062_IRQ_GPI4 , 1 , " GPI4 " , IORESOURCE_IRQ ) ,
} ;
2015-07-01 16:11:32 +03:00
static const struct mfd_cell da9062_devs [ ] = {
{
. name = " da9062-core " ,
. num_resources = ARRAY_SIZE ( da9062_core_resources ) ,
. resources = da9062_core_resources ,
} ,
{
. name = " da9062-regulators " ,
. num_resources = ARRAY_SIZE ( da9062_regulators_resources ) ,
. resources = da9062_regulators_resources ,
} ,
{
. name = " da9062-watchdog " ,
. num_resources = ARRAY_SIZE ( da9062_wdt_resources ) ,
. resources = da9062_wdt_resources ,
2020-01-08 12:57:02 +03:00
. of_compatible = " dlg,da9062-watchdog " ,
2015-07-01 16:11:32 +03:00
} ,
{
. name = " da9062-thermal " ,
. num_resources = ARRAY_SIZE ( da9062_thermal_resources ) ,
. resources = da9062_thermal_resources ,
. of_compatible = " dlg,da9062-thermal " ,
} ,
2015-07-21 13:29:06 +03:00
{
. name = " da9062-rtc " ,
. num_resources = ARRAY_SIZE ( da9062_rtc_resources ) ,
. resources = da9062_rtc_resources ,
. of_compatible = " dlg,da9062-rtc " ,
} ,
2015-07-23 19:17:41 +03:00
{
. name = " da9062-onkey " ,
. num_resources = ARRAY_SIZE ( da9062_onkey_resources ) ,
. resources = da9062_onkey_resources ,
2019-12-12 19:04:12 +03:00
. of_compatible = " dlg,da9062-onkey " ,
} ,
{
. name = " da9062-gpio " ,
. num_resources = ARRAY_SIZE ( da9062_gpio_resources ) ,
. resources = da9062_gpio_resources ,
. of_compatible = " dlg,da9062-gpio " ,
2015-07-23 19:17:41 +03:00
} ,
2015-07-01 16:11:32 +03:00
} ;
static int da9062_clear_fault_log ( struct da9062 * chip )
{
int ret ;
int fault_log ;
ret = regmap_read ( chip - > regmap , DA9062AA_FAULT_LOG , & fault_log ) ;
if ( ret < 0 )
return ret ;
if ( fault_log ) {
if ( fault_log & DA9062AA_TWD_ERROR_MASK )
dev_dbg ( chip - > dev , " Fault log entry detected: TWD_ERROR \n " ) ;
if ( fault_log & DA9062AA_POR_MASK )
dev_dbg ( chip - > dev , " Fault log entry detected: POR \n " ) ;
if ( fault_log & DA9062AA_VDD_FAULT_MASK )
dev_dbg ( chip - > dev , " Fault log entry detected: VDD_FAULT \n " ) ;
if ( fault_log & DA9062AA_VDD_START_MASK )
dev_dbg ( chip - > dev , " Fault log entry detected: VDD_START \n " ) ;
if ( fault_log & DA9062AA_TEMP_CRIT_MASK )
dev_dbg ( chip - > dev , " Fault log entry detected: TEMP_CRIT \n " ) ;
if ( fault_log & DA9062AA_KEY_RESET_MASK )
dev_dbg ( chip - > dev , " Fault log entry detected: KEY_RESET \n " ) ;
if ( fault_log & DA9062AA_NSHUTDOWN_MASK )
dev_dbg ( chip - > dev , " Fault log entry detected: NSHUTDOWN \n " ) ;
if ( fault_log & DA9062AA_WAIT_SHUT_MASK )
dev_dbg ( chip - > dev , " Fault log entry detected: WAIT_SHUT \n " ) ;
ret = regmap_write ( chip - > regmap , DA9062AA_FAULT_LOG ,
fault_log ) ;
}
return ret ;
}
2015-10-09 13:22:03 +03:00
static int da9062_get_device_type ( struct da9062 * chip )
2015-07-01 16:11:32 +03:00
{
2017-04-03 17:46:40 +03:00
int device_id , variant_id , variant_mrc , variant_vrc ;
char * type ;
2015-07-01 16:11:32 +03:00
int ret ;
ret = regmap_read ( chip - > regmap , DA9062AA_DEVICE_ID , & device_id ) ;
if ( ret < 0 ) {
dev_err ( chip - > dev , " Cannot read chip ID. \n " ) ;
return - EIO ;
}
if ( device_id ! = DA9062_PMIC_DEVICE_ID ) {
dev_err ( chip - > dev , " Invalid device ID: 0x%02x \n " , device_id ) ;
return - ENODEV ;
}
ret = regmap_read ( chip - > regmap , DA9062AA_VARIANT_ID , & variant_id ) ;
if ( ret < 0 ) {
dev_err ( chip - > dev , " Cannot read chip variant id. \n " ) ;
return - EIO ;
}
2017-04-03 17:46:40 +03:00
variant_vrc = ( variant_id & DA9062AA_VRC_MASK ) > > DA9062AA_VRC_SHIFT ;
switch ( variant_vrc ) {
case DA9062_PMIC_VARIANT_VRC_DA9061 :
type = " DA9061 " ;
break ;
case DA9062_PMIC_VARIANT_VRC_DA9062 :
type = " DA9062 " ;
break ;
default :
type = " Unknown " ;
break ;
}
2015-07-01 16:11:32 +03:00
dev_info ( chip - > dev ,
2017-04-03 17:46:40 +03:00
" Device detected (device-ID: 0x%02X, var-ID: 0x%02X, %s) \n " ,
device_id , variant_id , type ) ;
2015-07-01 16:11:32 +03:00
variant_mrc = ( variant_id & DA9062AA_MRC_MASK ) > > DA9062AA_MRC_SHIFT ;
if ( variant_mrc < DA9062_PMIC_VARIANT_MRC_AA ) {
dev_err ( chip - > dev ,
" Cannot support variant MRC: 0x%02X \n " , variant_mrc ) ;
return - ENODEV ;
}
return ret ;
}
2020-02-26 04:07:22 +03:00
static u32 da9062_configure_irq_type ( struct da9062 * chip , int irq , u32 * trigger )
{
u32 irq_type = 0 ;
struct irq_data * irq_data = irq_get_irq_data ( irq ) ;
if ( ! irq_data ) {
dev_err ( chip - > dev , " Invalid IRQ: %d \n " , irq ) ;
return - EINVAL ;
}
* trigger = irqd_get_trigger_type ( irq_data ) ;
switch ( * trigger ) {
case IRQ_TYPE_LEVEL_HIGH :
irq_type = DA9062_IRQ_HIGH ;
break ;
case IRQ_TYPE_LEVEL_LOW :
irq_type = DA9062_IRQ_LOW ;
break ;
default :
dev_warn ( chip - > dev , " Unsupported IRQ type: %d \n " , * trigger ) ;
return - EINVAL ;
}
return regmap_update_bits ( chip - > regmap , DA9062AA_CONFIG_A ,
DA9062AA_IRQ_TYPE_MASK ,
irq_type < < DA9062AA_IRQ_TYPE_SHIFT ) ;
}
2017-04-03 17:46:40 +03:00
static const struct regmap_range da9061_aa_readable_ranges [ ] = {
2018-03-28 14:03:09 +03:00
regmap_reg_range ( DA9062AA_PAGE_CON , DA9062AA_STATUS_B ) ,
regmap_reg_range ( DA9062AA_STATUS_D , DA9062AA_EVENT_C ) ,
regmap_reg_range ( DA9062AA_IRQ_MASK_A , DA9062AA_IRQ_MASK_C ) ,
regmap_reg_range ( DA9062AA_CONTROL_A , DA9062AA_GPIO_4 ) ,
regmap_reg_range ( DA9062AA_GPIO_WKUP_MODE , DA9062AA_GPIO_OUT3_4 ) ,
regmap_reg_range ( DA9062AA_BUCK1_CONT , DA9062AA_BUCK4_CONT ) ,
regmap_reg_range ( DA9062AA_BUCK3_CONT , DA9062AA_BUCK3_CONT ) ,
regmap_reg_range ( DA9062AA_LDO1_CONT , DA9062AA_LDO4_CONT ) ,
regmap_reg_range ( DA9062AA_DVC_1 , DA9062AA_DVC_1 ) ,
regmap_reg_range ( DA9062AA_SEQ , DA9062AA_ID_4_3 ) ,
regmap_reg_range ( DA9062AA_ID_12_11 , DA9062AA_ID_16_15 ) ,
regmap_reg_range ( DA9062AA_ID_22_21 , DA9062AA_ID_32_31 ) ,
regmap_reg_range ( DA9062AA_SEQ_A , DA9062AA_WAIT ) ,
regmap_reg_range ( DA9062AA_RESET , DA9062AA_BUCK_ILIM_C ) ,
regmap_reg_range ( DA9062AA_BUCK1_CFG , DA9062AA_BUCK3_CFG ) ,
regmap_reg_range ( DA9062AA_VBUCK1_A , DA9062AA_VBUCK4_A ) ,
regmap_reg_range ( DA9062AA_VBUCK3_A , DA9062AA_VBUCK3_A ) ,
regmap_reg_range ( DA9062AA_VLDO1_A , DA9062AA_VLDO4_A ) ,
2020-02-26 04:07:22 +03:00
regmap_reg_range ( DA9062AA_CONFIG_A , DA9062AA_CONFIG_A ) ,
2018-03-28 14:03:09 +03:00
regmap_reg_range ( DA9062AA_VBUCK1_B , DA9062AA_VBUCK4_B ) ,
regmap_reg_range ( DA9062AA_VBUCK3_B , DA9062AA_VBUCK3_B ) ,
regmap_reg_range ( DA9062AA_VLDO1_B , DA9062AA_VLDO4_B ) ,
regmap_reg_range ( DA9062AA_INTERFACE , DA9062AA_CONFIG_E ) ,
regmap_reg_range ( DA9062AA_CONFIG_G , DA9062AA_CONFIG_K ) ,
regmap_reg_range ( DA9062AA_CONFIG_M , DA9062AA_CONFIG_M ) ,
regmap_reg_range ( DA9062AA_GP_ID_0 , DA9062AA_GP_ID_19 ) ,
regmap_reg_range ( DA9062AA_DEVICE_ID , DA9062AA_CONFIG_ID ) ,
2017-04-03 17:46:40 +03:00
} ;
static const struct regmap_range da9061_aa_writeable_ranges [ ] = {
2018-03-28 14:03:09 +03:00
regmap_reg_range ( DA9062AA_PAGE_CON , DA9062AA_PAGE_CON ) ,
regmap_reg_range ( DA9062AA_FAULT_LOG , DA9062AA_EVENT_C ) ,
regmap_reg_range ( DA9062AA_IRQ_MASK_A , DA9062AA_IRQ_MASK_C ) ,
regmap_reg_range ( DA9062AA_CONTROL_A , DA9062AA_GPIO_4 ) ,
regmap_reg_range ( DA9062AA_GPIO_WKUP_MODE , DA9062AA_GPIO_OUT3_4 ) ,
regmap_reg_range ( DA9062AA_BUCK1_CONT , DA9062AA_BUCK4_CONT ) ,
regmap_reg_range ( DA9062AA_BUCK3_CONT , DA9062AA_BUCK3_CONT ) ,
regmap_reg_range ( DA9062AA_LDO1_CONT , DA9062AA_LDO4_CONT ) ,
regmap_reg_range ( DA9062AA_DVC_1 , DA9062AA_DVC_1 ) ,
regmap_reg_range ( DA9062AA_SEQ , DA9062AA_ID_4_3 ) ,
regmap_reg_range ( DA9062AA_ID_12_11 , DA9062AA_ID_16_15 ) ,
regmap_reg_range ( DA9062AA_ID_22_21 , DA9062AA_ID_32_31 ) ,
regmap_reg_range ( DA9062AA_SEQ_A , DA9062AA_WAIT ) ,
regmap_reg_range ( DA9062AA_RESET , DA9062AA_BUCK_ILIM_C ) ,
regmap_reg_range ( DA9062AA_BUCK1_CFG , DA9062AA_BUCK3_CFG ) ,
regmap_reg_range ( DA9062AA_VBUCK1_A , DA9062AA_VBUCK4_A ) ,
regmap_reg_range ( DA9062AA_VBUCK3_A , DA9062AA_VBUCK3_A ) ,
regmap_reg_range ( DA9062AA_VLDO1_A , DA9062AA_VLDO4_A ) ,
2020-02-26 04:07:22 +03:00
regmap_reg_range ( DA9062AA_CONFIG_A , DA9062AA_CONFIG_A ) ,
2018-03-28 14:03:09 +03:00
regmap_reg_range ( DA9062AA_VBUCK1_B , DA9062AA_VBUCK4_B ) ,
regmap_reg_range ( DA9062AA_VBUCK3_B , DA9062AA_VBUCK3_B ) ,
regmap_reg_range ( DA9062AA_VLDO1_B , DA9062AA_VLDO4_B ) ,
2022-09-15 12:20:04 +03:00
regmap_reg_range ( DA9062AA_CONFIG_J , DA9062AA_CONFIG_J ) ,
2018-03-28 14:03:09 +03:00
regmap_reg_range ( DA9062AA_GP_ID_0 , DA9062AA_GP_ID_19 ) ,
2017-04-03 17:46:40 +03:00
} ;
static const struct regmap_range da9061_aa_volatile_ranges [ ] = {
2018-03-28 14:03:09 +03:00
regmap_reg_range ( DA9062AA_PAGE_CON , DA9062AA_STATUS_B ) ,
regmap_reg_range ( DA9062AA_STATUS_D , DA9062AA_EVENT_C ) ,
regmap_reg_range ( DA9062AA_CONTROL_A , DA9062AA_CONTROL_B ) ,
regmap_reg_range ( DA9062AA_CONTROL_E , DA9062AA_CONTROL_F ) ,
regmap_reg_range ( DA9062AA_BUCK1_CONT , DA9062AA_BUCK4_CONT ) ,
regmap_reg_range ( DA9062AA_BUCK3_CONT , DA9062AA_BUCK3_CONT ) ,
regmap_reg_range ( DA9062AA_LDO1_CONT , DA9062AA_LDO4_CONT ) ,
regmap_reg_range ( DA9062AA_DVC_1 , DA9062AA_DVC_1 ) ,
regmap_reg_range ( DA9062AA_SEQ , DA9062AA_SEQ ) ,
2017-04-03 17:46:40 +03:00
} ;
static const struct regmap_access_table da9061_aa_readable_table = {
. yes_ranges = da9061_aa_readable_ranges ,
. n_yes_ranges = ARRAY_SIZE ( da9061_aa_readable_ranges ) ,
} ;
static const struct regmap_access_table da9061_aa_writeable_table = {
. yes_ranges = da9061_aa_writeable_ranges ,
. n_yes_ranges = ARRAY_SIZE ( da9061_aa_writeable_ranges ) ,
} ;
static const struct regmap_access_table da9061_aa_volatile_table = {
. yes_ranges = da9061_aa_volatile_ranges ,
. n_yes_ranges = ARRAY_SIZE ( da9061_aa_volatile_ranges ) ,
} ;
static const struct regmap_range_cfg da9061_range_cfg [ ] = {
{
. range_min = DA9062AA_PAGE_CON ,
. range_max = DA9062AA_CONFIG_ID ,
. selector_reg = DA9062AA_PAGE_CON ,
. selector_mask = 1 < < DA9062_I2C_PAGE_SEL_SHIFT ,
. selector_shift = DA9062_I2C_PAGE_SEL_SHIFT ,
. window_start = 0 ,
. window_len = 256 ,
}
} ;
static struct regmap_config da9061_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. ranges = da9061_range_cfg ,
. num_ranges = ARRAY_SIZE ( da9061_range_cfg ) ,
. max_register = DA9062AA_CONFIG_ID ,
. cache_type = REGCACHE_RBTREE ,
. rd_table = & da9061_aa_readable_table ,
. wr_table = & da9061_aa_writeable_table ,
. volatile_table = & da9061_aa_volatile_table ,
} ;
2015-07-01 16:11:32 +03:00
static const struct regmap_range da9062_aa_readable_ranges [ ] = {
2018-03-28 14:03:09 +03:00
regmap_reg_range ( DA9062AA_PAGE_CON , DA9062AA_STATUS_B ) ,
regmap_reg_range ( DA9062AA_STATUS_D , DA9062AA_EVENT_C ) ,
regmap_reg_range ( DA9062AA_IRQ_MASK_A , DA9062AA_IRQ_MASK_C ) ,
regmap_reg_range ( DA9062AA_CONTROL_A , DA9062AA_GPIO_4 ) ,
regmap_reg_range ( DA9062AA_GPIO_WKUP_MODE , DA9062AA_BUCK4_CONT ) ,
regmap_reg_range ( DA9062AA_BUCK3_CONT , DA9062AA_BUCK3_CONT ) ,
regmap_reg_range ( DA9062AA_LDO1_CONT , DA9062AA_LDO4_CONT ) ,
regmap_reg_range ( DA9062AA_DVC_1 , DA9062AA_DVC_1 ) ,
regmap_reg_range ( DA9062AA_COUNT_S , DA9062AA_SECOND_D ) ,
regmap_reg_range ( DA9062AA_SEQ , DA9062AA_ID_4_3 ) ,
regmap_reg_range ( DA9062AA_ID_12_11 , DA9062AA_ID_16_15 ) ,
regmap_reg_range ( DA9062AA_ID_22_21 , DA9062AA_ID_32_31 ) ,
regmap_reg_range ( DA9062AA_SEQ_A , DA9062AA_BUCK3_CFG ) ,
regmap_reg_range ( DA9062AA_VBUCK2_A , DA9062AA_VBUCK4_A ) ,
regmap_reg_range ( DA9062AA_VBUCK3_A , DA9062AA_VBUCK3_A ) ,
regmap_reg_range ( DA9062AA_VLDO1_A , DA9062AA_VLDO4_A ) ,
regmap_reg_range ( DA9062AA_VBUCK2_B , DA9062AA_VBUCK4_B ) ,
regmap_reg_range ( DA9062AA_VBUCK3_B , DA9062AA_VBUCK3_B ) ,
regmap_reg_range ( DA9062AA_VLDO1_B , DA9062AA_VLDO4_B ) ,
regmap_reg_range ( DA9062AA_BBAT_CONT , DA9062AA_BBAT_CONT ) ,
regmap_reg_range ( DA9062AA_INTERFACE , DA9062AA_CONFIG_E ) ,
regmap_reg_range ( DA9062AA_CONFIG_G , DA9062AA_CONFIG_K ) ,
regmap_reg_range ( DA9062AA_CONFIG_M , DA9062AA_CONFIG_M ) ,
regmap_reg_range ( DA9062AA_TRIM_CLDR , DA9062AA_GP_ID_19 ) ,
regmap_reg_range ( DA9062AA_DEVICE_ID , DA9062AA_CONFIG_ID ) ,
2015-07-01 16:11:32 +03:00
} ;
static const struct regmap_range da9062_aa_writeable_ranges [ ] = {
2018-03-28 14:03:09 +03:00
regmap_reg_range ( DA9062AA_PAGE_CON , DA9062AA_PAGE_CON ) ,
regmap_reg_range ( DA9062AA_FAULT_LOG , DA9062AA_EVENT_C ) ,
regmap_reg_range ( DA9062AA_IRQ_MASK_A , DA9062AA_IRQ_MASK_C ) ,
regmap_reg_range ( DA9062AA_CONTROL_A , DA9062AA_GPIO_4 ) ,
regmap_reg_range ( DA9062AA_GPIO_WKUP_MODE , DA9062AA_BUCK4_CONT ) ,
regmap_reg_range ( DA9062AA_BUCK3_CONT , DA9062AA_BUCK3_CONT ) ,
regmap_reg_range ( DA9062AA_LDO1_CONT , DA9062AA_LDO4_CONT ) ,
regmap_reg_range ( DA9062AA_DVC_1 , DA9062AA_DVC_1 ) ,
regmap_reg_range ( DA9062AA_COUNT_S , DA9062AA_ALARM_Y ) ,
regmap_reg_range ( DA9062AA_SEQ , DA9062AA_ID_4_3 ) ,
regmap_reg_range ( DA9062AA_ID_12_11 , DA9062AA_ID_16_15 ) ,
regmap_reg_range ( DA9062AA_ID_22_21 , DA9062AA_ID_32_31 ) ,
regmap_reg_range ( DA9062AA_SEQ_A , DA9062AA_BUCK3_CFG ) ,
regmap_reg_range ( DA9062AA_VBUCK2_A , DA9062AA_VBUCK4_A ) ,
regmap_reg_range ( DA9062AA_VBUCK3_A , DA9062AA_VBUCK3_A ) ,
regmap_reg_range ( DA9062AA_VLDO1_A , DA9062AA_VLDO4_A ) ,
regmap_reg_range ( DA9062AA_VBUCK2_B , DA9062AA_VBUCK4_B ) ,
regmap_reg_range ( DA9062AA_VBUCK3_B , DA9062AA_VBUCK3_B ) ,
regmap_reg_range ( DA9062AA_VLDO1_B , DA9062AA_VLDO4_B ) ,
regmap_reg_range ( DA9062AA_BBAT_CONT , DA9062AA_BBAT_CONT ) ,
2021-11-24 09:51:19 +03:00
regmap_reg_range ( DA9062AA_CONFIG_J , DA9062AA_CONFIG_J ) ,
2018-03-28 14:03:09 +03:00
regmap_reg_range ( DA9062AA_GP_ID_0 , DA9062AA_GP_ID_19 ) ,
2015-07-01 16:11:32 +03:00
} ;
static const struct regmap_range da9062_aa_volatile_ranges [ ] = {
2018-03-28 14:03:09 +03:00
regmap_reg_range ( DA9062AA_PAGE_CON , DA9062AA_STATUS_B ) ,
regmap_reg_range ( DA9062AA_STATUS_D , DA9062AA_EVENT_C ) ,
regmap_reg_range ( DA9062AA_CONTROL_A , DA9062AA_CONTROL_B ) ,
regmap_reg_range ( DA9062AA_CONTROL_E , DA9062AA_CONTROL_F ) ,
regmap_reg_range ( DA9062AA_BUCK2_CONT , DA9062AA_BUCK4_CONT ) ,
regmap_reg_range ( DA9062AA_BUCK3_CONT , DA9062AA_BUCK3_CONT ) ,
regmap_reg_range ( DA9062AA_LDO1_CONT , DA9062AA_LDO4_CONT ) ,
regmap_reg_range ( DA9062AA_DVC_1 , DA9062AA_DVC_1 ) ,
regmap_reg_range ( DA9062AA_COUNT_S , DA9062AA_SECOND_D ) ,
regmap_reg_range ( DA9062AA_SEQ , DA9062AA_SEQ ) ,
regmap_reg_range ( DA9062AA_EN_32K , DA9062AA_EN_32K ) ,
2015-07-01 16:11:32 +03:00
} ;
static const struct regmap_access_table da9062_aa_readable_table = {
. yes_ranges = da9062_aa_readable_ranges ,
. n_yes_ranges = ARRAY_SIZE ( da9062_aa_readable_ranges ) ,
} ;
static const struct regmap_access_table da9062_aa_writeable_table = {
. yes_ranges = da9062_aa_writeable_ranges ,
. n_yes_ranges = ARRAY_SIZE ( da9062_aa_writeable_ranges ) ,
} ;
static const struct regmap_access_table da9062_aa_volatile_table = {
. yes_ranges = da9062_aa_volatile_ranges ,
. n_yes_ranges = ARRAY_SIZE ( da9062_aa_volatile_ranges ) ,
} ;
static const struct regmap_range_cfg da9062_range_cfg [ ] = {
{
. range_min = DA9062AA_PAGE_CON ,
. range_max = DA9062AA_CONFIG_ID ,
. selector_reg = DA9062AA_PAGE_CON ,
. selector_mask = 1 < < DA9062_I2C_PAGE_SEL_SHIFT ,
. selector_shift = DA9062_I2C_PAGE_SEL_SHIFT ,
. window_start = 0 ,
. window_len = 256 ,
}
} ;
static struct regmap_config da9062_regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
. ranges = da9062_range_cfg ,
. num_ranges = ARRAY_SIZE ( da9062_range_cfg ) ,
. max_register = DA9062AA_CONFIG_ID ,
. cache_type = REGCACHE_RBTREE ,
. rd_table = & da9062_aa_readable_table ,
. wr_table = & da9062_aa_writeable_table ,
. volatile_table = & da9062_aa_volatile_table ,
} ;
2017-04-03 17:46:40 +03:00
static const struct of_device_id da9062_dt_ids [ ] = {
{ . compatible = " dlg,da9061 " , . data = ( void * ) COMPAT_TYPE_DA9061 , } ,
{ . compatible = " dlg,da9062 " , . data = ( void * ) COMPAT_TYPE_DA9062 , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , da9062_dt_ids ) ;
2022-11-19 01:42:42 +03:00
static int da9062_i2c_probe ( struct i2c_client * i2c )
2015-07-01 16:11:32 +03:00
{
2022-11-19 01:42:42 +03:00
const struct i2c_device_id * id = i2c_client_get_device_id ( i2c ) ;
2015-07-01 16:11:32 +03:00
struct da9062 * chip ;
unsigned int irq_base ;
2017-04-03 17:46:40 +03:00
const struct mfd_cell * cell ;
const struct regmap_irq_chip * irq_chip ;
const struct regmap_config * config ;
int cell_num ;
2020-02-26 04:07:22 +03:00
u32 trigger_type = 0 ;
2015-07-01 16:11:32 +03:00
int ret ;
chip = devm_kzalloc ( & i2c - > dev , sizeof ( * chip ) , GFP_KERNEL ) ;
if ( ! chip )
return - ENOMEM ;
2021-05-26 15:47:02 +03:00
if ( i2c - > dev . of_node )
chip - > chip_type = ( uintptr_t ) of_device_get_match_data ( & i2c - > dev ) ;
else
2017-04-03 17:46:40 +03:00
chip - > chip_type = id - > driver_data ;
2015-07-01 16:11:32 +03:00
i2c_set_clientdata ( i2c , chip ) ;
chip - > dev = & i2c - > dev ;
if ( ! i2c - > irq ) {
dev_err ( chip - > dev , " No IRQ configured \n " ) ;
return - EINVAL ;
}
2017-04-03 17:46:40 +03:00
switch ( chip - > chip_type ) {
case COMPAT_TYPE_DA9061 :
cell = da9061_devs ;
cell_num = ARRAY_SIZE ( da9061_devs ) ;
irq_chip = & da9061_irq_chip ;
config = & da9061_regmap_config ;
break ;
case COMPAT_TYPE_DA9062 :
cell = da9062_devs ;
cell_num = ARRAY_SIZE ( da9062_devs ) ;
irq_chip = & da9062_irq_chip ;
config = & da9062_regmap_config ;
break ;
default :
dev_err ( chip - > dev , " Unrecognised chip type \n " ) ;
return - ENODEV ;
}
chip - > regmap = devm_regmap_init_i2c ( i2c , config ) ;
2015-07-01 16:11:32 +03:00
if ( IS_ERR ( chip - > regmap ) ) {
ret = PTR_ERR ( chip - > regmap ) ;
dev_err ( chip - > dev , " Failed to allocate register map: %d \n " ,
ret ) ;
return ret ;
}
2021-11-24 09:51:19 +03:00
/* If SMBus is not available and only I2C is possible, enter I2C mode */
if ( i2c_check_functionality ( i2c - > adapter , I2C_FUNC_I2C ) ) {
dev_info ( chip - > dev , " Entering I2C mode! \n " ) ;
ret = regmap_clear_bits ( chip - > regmap , DA9062AA_CONFIG_J ,
DA9062AA_TWOWIRE_TO_MASK ) ;
if ( ret < 0 ) {
dev_err ( chip - > dev , " Failed to set Two-Wire Bus Mode. \n " ) ;
return ret ;
}
}
2015-07-01 16:11:32 +03:00
ret = da9062_clear_fault_log ( chip ) ;
if ( ret < 0 )
dev_warn ( chip - > dev , " Cannot clear fault log \n " ) ;
2015-10-09 13:22:03 +03:00
ret = da9062_get_device_type ( chip ) ;
2015-07-01 16:11:32 +03:00
if ( ret )
return ret ;
2020-02-26 04:07:22 +03:00
ret = da9062_configure_irq_type ( chip , i2c - > irq , & trigger_type ) ;
if ( ret < 0 ) {
dev_err ( chip - > dev , " Failed to configure IRQ type \n " ) ;
return ret ;
}
2015-07-01 16:11:32 +03:00
ret = regmap_add_irq_chip ( chip - > regmap , i2c - > irq ,
2020-02-26 04:07:22 +03:00
trigger_type | IRQF_SHARED | IRQF_ONESHOT ,
- 1 , irq_chip , & chip - > regmap_irq ) ;
2015-07-01 16:11:32 +03:00
if ( ret ) {
dev_err ( chip - > dev , " Failed to request IRQ %d: %d \n " ,
i2c - > irq , ret ) ;
return ret ;
}
irq_base = regmap_irq_chip_get_base ( chip - > regmap_irq ) ;
2017-04-03 17:46:40 +03:00
ret = mfd_add_devices ( chip - > dev , PLATFORM_DEVID_NONE , cell ,
cell_num , NULL , irq_base ,
2015-07-01 16:11:32 +03:00
NULL ) ;
if ( ret ) {
dev_err ( chip - > dev , " Cannot register child devices \n " ) ;
regmap_del_irq_chip ( i2c - > irq , chip - > regmap_irq ) ;
return ret ;
}
return ret ;
}
2022-08-15 11:02:30 +03:00
static void da9062_i2c_remove ( struct i2c_client * i2c )
2015-07-01 16:11:32 +03:00
{
struct da9062 * chip = i2c_get_clientdata ( i2c ) ;
mfd_remove_devices ( chip - > dev ) ;
regmap_del_irq_chip ( i2c - > irq , chip - > regmap_irq ) ;
}
static const struct i2c_device_id da9062_i2c_id [ ] = {
2017-04-03 17:46:40 +03:00
{ " da9061 " , COMPAT_TYPE_DA9061 } ,
{ " da9062 " , COMPAT_TYPE_DA9062 } ,
2015-07-01 16:11:32 +03:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( i2c , da9062_i2c_id ) ;
static struct i2c_driver da9062_i2c_driver = {
. driver = {
. name = " da9062 " ,
2020-11-20 19:21:20 +03:00
. of_match_table = da9062_dt_ids ,
2015-07-01 16:11:32 +03:00
} ,
2022-11-19 01:42:42 +03:00
. probe_new = da9062_i2c_probe ,
2015-07-01 16:11:32 +03:00
. remove = da9062_i2c_remove ,
. id_table = da9062_i2c_id ,
} ;
module_i2c_driver ( da9062_i2c_driver ) ;
2017-04-03 17:46:40 +03:00
MODULE_DESCRIPTION ( " Core device driver for Dialog DA9061 and DA9062 " ) ;
2015-07-01 16:11:32 +03:00
MODULE_AUTHOR ( " Steve Twiss <stwiss.opensource@diasemi.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;