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>
2018-09-14 11:27:46 +03:00
# include <linux/of_device.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 " ,
} ;
2018-09-14 11:32:26 +03:00
static struct mfd_cell bd718xx_mfd_cells [ ] = {
2018-08-03 14:08:14 +03:00
{
. name = " gpio-keys " ,
. platform_data = & bd718xx_powerkey_data ,
. pdata_size = sizeof ( bd718xx_powerkey_data ) ,
} ,
2018-09-14 11:27:46 +03:00
{ . name = " bd718xx-clk " , } ,
{ . name = " bd718xx-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 ,
. mask_invert = false ,
} ;
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 ,
2018-08-03 14:08:14 +03:00
. cache_type = REGCACHE_RBTREE ,
} ;
2018-09-14 11:32:26 +03:00
static int bd718xx_i2c_probe ( struct i2c_client * i2c ,
2018-08-03 14:08:14 +03:00
const struct i2c_device_id * id )
{
2018-09-14 11:32:26 +03:00
struct bd718xx * bd718xx ;
2018-09-14 11:27:46 +03:00
int ret ;
if ( ! i2c - > irq ) {
dev_err ( & i2c - > dev , " No IRQ configured \n " ) ;
return - EINVAL ;
}
2018-08-03 14:08:14 +03:00
2018-09-14 11:32:26 +03:00
bd718xx = devm_kzalloc ( & i2c - > dev , sizeof ( struct bd718xx ) , GFP_KERNEL ) ;
2018-08-03 14:08:14 +03:00
2018-09-14 11:32:26 +03:00
if ( ! bd718xx )
2018-08-03 14:08:14 +03:00
return - ENOMEM ;
2018-09-14 11:32:26 +03:00
bd718xx - > chip_irq = i2c - > irq ;
2019-06-03 10:24:32 +03:00
bd718xx - > chip . chip_type = ( unsigned int ) ( uintptr_t )
2018-09-14 11:27:46 +03:00
of_device_get_match_data ( & i2c - > dev ) ;
2019-06-03 10:24:32 +03:00
bd718xx - > chip . dev = & i2c - > dev ;
2018-09-14 11:32:26 +03:00
dev_set_drvdata ( & i2c - > dev , bd718xx ) ;
2018-08-03 14:08:14 +03:00
2019-06-03 10:24:32 +03:00
bd718xx - > chip . regmap = devm_regmap_init_i2c ( i2c ,
& bd718xx_regmap_config ) ;
if ( IS_ERR ( bd718xx - > chip . regmap ) ) {
2018-08-03 14:08:14 +03:00
dev_err ( & i2c - > dev , " regmap initialization failed \n " ) ;
2019-06-03 10:24:32 +03:00
return PTR_ERR ( bd718xx - > chip . regmap ) ;
2018-08-03 14:08:14 +03:00
}
2019-06-03 10:24:32 +03:00
ret = devm_regmap_add_irq_chip ( & i2c - > dev , bd718xx - > chip . regmap ,
2018-09-14 11:32:26 +03:00
bd718xx - > chip_irq , IRQF_ONESHOT , 0 ,
& bd718xx_irq_chip , & bd718xx - > irq_data ) ;
2018-08-03 14:08:14 +03:00
if ( ret ) {
dev_err ( & i2c - > dev , " Failed to add irq_chip \n " ) ;
return ret ;
}
2018-09-14 11:32:26 +03:00
ret = regmap_irq_get_virq ( bd718xx - > irq_data , BD718XX_INT_PWRBTN_S ) ;
2018-08-03 14:08:14 +03:00
if ( ret < 0 ) {
dev_err ( & i2c - > dev , " Failed to get the IRQ \n " ) ;
return ret ;
}
button . irq = ret ;
2019-06-03 10:24:32 +03:00
ret = devm_mfd_add_devices ( bd718xx - > chip . dev , PLATFORM_DEVID_AUTO ,
2018-09-14 11:32:26 +03:00
bd718xx_mfd_cells ,
ARRAY_SIZE ( bd718xx_mfd_cells ) , NULL , 0 ,
regmap_irq_get_domain ( bd718xx - > irq_data ) ) ;
2018-08-03 14:08:14 +03:00
if ( ret )
dev_err ( & i2c - > dev , " Failed to create subdevices \n " ) ;
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
} ,
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
} ,
2018-09-14 11:32:26 +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 " ) ;