2018-08-03 14:08:14 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
//
// Copyright (C) 2018 ROHM Semiconductors
//
2018-09-14 11:32:26 +03:00
// ROHM BD71837MWV and BD71847MWV PMIC driver
2018-08-03 14:08:14 +03:00
//
2018-09-14 11:32:26 +03:00
// Datasheet for BD71837MWV available from
2018-08-03 14:08:14 +03:00
// https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e
2018-09-14 11:27:46 +03:00
# include <linux/gpio_keys.h>
2018-08-03 14:08:14 +03:00
# include <linux/i2c.h>
# include <linux/input.h>
# include <linux/interrupt.h>
# include <linux/mfd/rohm-bd718x7.h>
# include <linux/mfd/core.h>
# include <linux/module.h>
2023-07-14 20:47:27 +03:00
# include <linux/of.h>
2018-08-03 14:08:14 +03:00
# include <linux/regmap.h>
2018-09-14 11:27:46 +03:00
# include <linux/types.h>
2018-08-03 14:08:14 +03:00
static struct gpio_keys_button button = {
. code = KEY_POWER ,
. gpio = - 1 ,
. type = EV_KEY ,
} ;
static struct gpio_keys_platform_data bd718xx_powerkey_data = {
. buttons = & button ,
. nbuttons = 1 ,
. name = " bd718xx-pwrkey " ,
} ;
2020-01-20 16:42:38 +03:00
static struct mfd_cell bd71837_mfd_cells [ ] = {
2018-08-03 14:08:14 +03:00
{
. name = " gpio-keys " ,
. platform_data = & bd718xx_powerkey_data ,
. pdata_size = sizeof ( bd718xx_powerkey_data ) ,
} ,
2020-01-20 16:42:38 +03:00
{ . name = " bd71837-clk " , } ,
{ . name = " bd71837-pmic " , } ,
} ;
static struct mfd_cell bd71847_mfd_cells [ ] = {
{
. name = " gpio-keys " ,
. platform_data = & bd718xx_powerkey_data ,
. pdata_size = sizeof ( bd718xx_powerkey_data ) ,
} ,
{ . name = " bd71847-clk " , } ,
{ . name = " bd71847-pmic " , } ,
2018-08-03 14:08:14 +03:00
} ;
2018-09-14 11:32:26 +03:00
static const struct regmap_irq bd718xx_irqs [ ] = {
REGMAP_IRQ_REG ( BD718XX_INT_SWRST , 0 , BD718XX_INT_SWRST_MASK ) ,
REGMAP_IRQ_REG ( BD718XX_INT_PWRBTN_S , 0 , BD718XX_INT_PWRBTN_S_MASK ) ,
REGMAP_IRQ_REG ( BD718XX_INT_PWRBTN_L , 0 , BD718XX_INT_PWRBTN_L_MASK ) ,
REGMAP_IRQ_REG ( BD718XX_INT_PWRBTN , 0 , BD718XX_INT_PWRBTN_MASK ) ,
REGMAP_IRQ_REG ( BD718XX_INT_WDOG , 0 , BD718XX_INT_WDOG_MASK ) ,
REGMAP_IRQ_REG ( BD718XX_INT_ON_REQ , 0 , BD718XX_INT_ON_REQ_MASK ) ,
REGMAP_IRQ_REG ( BD718XX_INT_STBY_REQ , 0 , BD718XX_INT_STBY_REQ_MASK ) ,
2018-08-03 14:08:14 +03:00
} ;
2018-09-14 11:32:26 +03:00
static struct regmap_irq_chip bd718xx_irq_chip = {
. name = " bd718xx-irq " ,
. irqs = bd718xx_irqs ,
. num_irqs = ARRAY_SIZE ( bd718xx_irqs ) ,
2018-08-03 14:08:14 +03:00
. num_regs = 1 ,
. irq_reg_stride = 1 ,
2018-09-14 11:27:46 +03:00
. status_base = BD718XX_REG_IRQ ,
. mask_base = BD718XX_REG_MIRQ ,
. ack_base = BD718XX_REG_IRQ ,
2018-08-03 14:08:14 +03:00
. init_ack_masked = true ,
} ;
static const struct regmap_range pmic_status_range = {
2018-09-14 11:27:46 +03:00
. range_min = BD718XX_REG_IRQ ,
. range_max = BD718XX_REG_POW_STATE ,
2018-08-03 14:08:14 +03:00
} ;
static const struct regmap_access_table volatile_regs = {
. yes_ranges = & pmic_status_range ,
. n_yes_ranges = 1 ,
} ;
2018-09-14 11:32:26 +03:00
static const struct regmap_config bd718xx_regmap_config = {
2018-08-03 14:08:14 +03:00
. reg_bits = 8 ,
. val_bits = 8 ,
. volatile_table = & volatile_regs ,
2018-09-14 11:27:46 +03:00
. max_register = BD718XX_MAX_REGISTER - 1 ,
2024-02-06 10:13:07 +03:00
. cache_type = REGCACHE_MAPLE ,
2018-08-03 14:08:14 +03:00
} ;
2021-04-05 14:40:44 +03:00
static int bd718xx_init_press_duration ( struct regmap * regmap ,
struct device * dev )
2019-05-21 23:41:14 +03:00
{
u32 short_press_ms , long_press_ms ;
u32 short_press_value , long_press_value ;
int ret ;
ret = of_property_read_u32 ( dev - > of_node , " rohm,short-press-ms " ,
& short_press_ms ) ;
if ( ! ret ) {
short_press_value = min ( 15u , ( short_press_ms + 250 ) / 500 ) ;
2021-04-05 14:40:44 +03:00
ret = regmap_update_bits ( regmap , BD718XX_REG_PWRONCONFIG0 ,
2019-05-21 23:41:14 +03:00
BD718XX_PWRBTN_PRESS_DURATION_MASK ,
short_press_value ) ;
if ( ret ) {
dev_err ( dev , " Failed to init pwron short press \n " ) ;
return ret ;
}
}
ret = of_property_read_u32 ( dev - > of_node , " rohm,long-press-ms " ,
& long_press_ms ) ;
if ( ! ret ) {
long_press_value = min ( 15u , ( long_press_ms + 500 ) / 1000 ) ;
2021-04-05 14:40:44 +03:00
ret = regmap_update_bits ( regmap , BD718XX_REG_PWRONCONFIG1 ,
2019-05-21 23:41:14 +03:00
BD718XX_PWRBTN_PRESS_DURATION_MASK ,
long_press_value ) ;
if ( ret ) {
dev_err ( dev , " Failed to init pwron long press \n " ) ;
return ret ;
}
}
return 0 ;
}
2022-11-19 01:43:08 +03:00
static int bd718xx_i2c_probe ( struct i2c_client * i2c )
2018-08-03 14:08:14 +03:00
{
2021-04-05 14:40:44 +03:00
struct regmap * regmap ;
struct regmap_irq_chip_data * irq_data ;
2018-09-14 11:27:46 +03:00
int ret ;
2020-01-20 16:42:38 +03:00
unsigned int chip_type ;
struct mfd_cell * mfd ;
int cells ;
2018-09-14 11:27:46 +03:00
if ( ! i2c - > irq ) {
dev_err ( & i2c - > dev , " No IRQ configured \n " ) ;
return - EINVAL ;
}
2020-01-20 16:42:38 +03:00
chip_type = ( unsigned int ) ( uintptr_t )
of_device_get_match_data ( & i2c - > dev ) ;
switch ( chip_type ) {
case ROHM_CHIP_TYPE_BD71837 :
mfd = bd71837_mfd_cells ;
cells = ARRAY_SIZE ( bd71837_mfd_cells ) ;
break ;
case ROHM_CHIP_TYPE_BD71847 :
mfd = bd71847_mfd_cells ;
cells = ARRAY_SIZE ( bd71847_mfd_cells ) ;
break ;
default :
dev_err ( & i2c - > dev , " Unknown device type " ) ;
return - EINVAL ;
}
2018-08-03 14:08:14 +03:00
2021-04-05 14:40:44 +03:00
regmap = devm_regmap_init_i2c ( i2c , & bd718xx_regmap_config ) ;
2022-11-23 12:19:49 +03:00
if ( IS_ERR ( regmap ) )
return dev_err_probe ( & i2c - > dev , PTR_ERR ( regmap ) ,
" regmap initialization failed \n " ) ;
2018-08-03 14:08:14 +03:00
2021-04-05 14:40:44 +03:00
ret = devm_regmap_add_irq_chip ( & i2c - > dev , regmap , i2c - > irq ,
IRQF_ONESHOT , 0 , & bd718xx_irq_chip ,
& irq_data ) ;
2022-11-23 12:19:49 +03:00
if ( ret )
return dev_err_probe ( & i2c - > dev , ret , " Failed to add irq_chip \n " ) ;
2018-08-03 14:08:14 +03:00
2021-04-05 14:40:44 +03:00
ret = bd718xx_init_press_duration ( regmap , & i2c - > dev ) ;
2019-05-21 23:41:14 +03:00
if ( ret )
return ret ;
2021-04-05 14:40:44 +03:00
ret = regmap_irq_get_virq ( irq_data , BD718XX_INT_PWRBTN_S ) ;
2018-08-03 14:08:14 +03:00
2022-11-23 12:19:49 +03:00
if ( ret < 0 )
return dev_err_probe ( & i2c - > dev , ret , " Failed to get the IRQ \n " ) ;
2018-08-03 14:08:14 +03:00
button . irq = ret ;
2021-04-05 14:40:44 +03:00
ret = devm_mfd_add_devices ( & i2c - > dev , PLATFORM_DEVID_AUTO ,
2020-01-20 16:42:38 +03:00
mfd , cells , NULL , 0 ,
2021-04-05 14:40:44 +03:00
regmap_irq_get_domain ( irq_data ) ) ;
2018-08-03 14:08:14 +03:00
if ( ret )
2022-11-23 12:19:49 +03:00
dev_err_probe ( & i2c - > dev , ret , " Failed to create subdevices \n " ) ;
2018-08-03 14:08:14 +03:00
return ret ;
}
2018-09-14 11:32:26 +03:00
static const struct of_device_id bd718xx_of_match [ ] = {
2018-09-14 11:27:46 +03:00
{
. compatible = " rohm,bd71837 " ,
2019-06-03 10:24:32 +03:00
. data = ( void * ) ROHM_CHIP_TYPE_BD71837 ,
2018-09-14 11:27:46 +03:00
} ,
{
. compatible = " rohm,bd71847 " ,
2019-06-03 10:24:32 +03:00
. data = ( void * ) ROHM_CHIP_TYPE_BD71847 ,
2018-09-14 11:27:46 +03:00
} ,
2020-01-20 16:43:01 +03:00
{
. compatible = " rohm,bd71850 " ,
. data = ( void * ) ROHM_CHIP_TYPE_BD71847 ,
} ,
2018-08-03 14:08:14 +03:00
{ }
} ;
2018-09-14 11:32:26 +03:00
MODULE_DEVICE_TABLE ( of , bd718xx_of_match ) ;
2018-08-03 14:08:14 +03:00
2018-09-14 11:32:26 +03:00
static struct i2c_driver bd718xx_i2c_driver = {
2018-08-03 14:08:14 +03:00
. driver = {
. name = " rohm-bd718x7 " ,
2018-09-14 11:32:26 +03:00
. of_match_table = bd718xx_of_match ,
2018-08-03 14:08:14 +03:00
} ,
2023-05-15 21:27:52 +03:00
. probe = bd718xx_i2c_probe ,
2018-08-03 14:08:14 +03:00
} ;
2018-09-14 11:32:26 +03:00
static int __init bd718xx_i2c_init ( void )
2018-08-03 14:08:14 +03:00
{
2018-09-14 11:32:26 +03:00
return i2c_add_driver ( & bd718xx_i2c_driver ) ;
2018-08-03 14:08:14 +03:00
}
/* Initialise early so consumer devices can complete system boot */
2018-09-14 11:32:26 +03:00
subsys_initcall ( bd718xx_i2c_init ) ;
2018-08-03 14:08:14 +03:00
2018-09-14 11:32:26 +03:00
static void __exit bd718xx_i2c_exit ( void )
2018-08-03 14:08:14 +03:00
{
2018-09-14 11:32:26 +03:00
i2c_del_driver ( & bd718xx_i2c_driver ) ;
2018-08-03 14:08:14 +03:00
}
2018-09-14 11:32:26 +03:00
module_exit ( bd718xx_i2c_exit ) ;
2018-08-03 14:08:14 +03:00
MODULE_AUTHOR ( " Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> " ) ;
2018-09-14 11:32:26 +03:00
MODULE_DESCRIPTION ( " ROHM BD71837/BD71847 Power Management IC driver " ) ;
2018-08-03 14:08:14 +03:00
MODULE_LICENSE ( " GPL " ) ;