2016-02-14 09:29:21 +03:00
/*
* Device driver for MFD hi655x PMIC
*
* Copyright ( c ) 2016 Hisilicon .
*
* Authors :
* Chen Feng < puck . chen @ hisilicon . com >
* Fei Wang < w . f @ huawei . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/gpio.h>
# include <linux/io.h>
# include <linux/interrupt.h>
# include <linux/init.h>
# include <linux/mfd/core.h>
# include <linux/mfd/hi655x-pmic.h>
# include <linux/module.h>
# include <linux/of_gpio.h>
# include <linux/of_platform.h>
# include <linux/platform_device.h>
# include <linux/regmap.h>
static const struct regmap_irq hi655x_irqs [ ] = {
2016-06-15 01:43:31 +03:00
{ . reg_offset = 0 , . mask = OTMP_D1R_INT_MASK } ,
{ . reg_offset = 0 , . mask = VSYS_2P5_R_INT_MASK } ,
{ . reg_offset = 0 , . mask = VSYS_UV_D3R_INT_MASK } ,
{ . reg_offset = 0 , . mask = VSYS_6P0_D200UR_INT_MASK } ,
{ . reg_offset = 0 , . mask = PWRON_D4SR_INT_MASK } ,
{ . reg_offset = 0 , . mask = PWRON_D20F_INT_MASK } ,
{ . reg_offset = 0 , . mask = PWRON_D20R_INT_MASK } ,
{ . reg_offset = 0 , . mask = RESERVE_INT_MASK } ,
2016-02-14 09:29:21 +03:00
} ;
static const struct regmap_irq_chip hi655x_irq_chip = {
. name = " hi655x-pmic " ,
. irqs = hi655x_irqs ,
. num_regs = 1 ,
. num_irqs = ARRAY_SIZE ( hi655x_irqs ) ,
. status_base = HI655X_IRQ_STAT_BASE ,
2016-06-15 01:43:30 +03:00
. ack_base = HI655X_IRQ_STAT_BASE ,
2016-02-14 09:29:21 +03:00
. mask_base = HI655X_IRQ_MASK_BASE ,
} ;
static struct regmap_config hi655x_regmap_config = {
. reg_bits = 32 ,
. reg_stride = HI655X_STRIDE ,
. val_bits = 8 ,
. max_register = HI655X_BUS_ADDR ( 0xFFF ) ,
} ;
2016-06-15 01:43:32 +03:00
static struct resource pwrkey_resources [ ] = {
{
. name = " down " ,
. start = PWRON_D20R_INT ,
. end = PWRON_D20R_INT ,
. flags = IORESOURCE_IRQ ,
} , {
. name = " up " ,
. start = PWRON_D20F_INT ,
. end = PWRON_D20F_INT ,
. flags = IORESOURCE_IRQ ,
} , {
. name = " hold 4s " ,
. start = PWRON_D4SR_INT ,
. end = PWRON_D4SR_INT ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
static const struct mfd_cell hi655x_pmic_devs [ ] = {
{
. name = " hi65xx-powerkey " ,
. num_resources = ARRAY_SIZE ( pwrkey_resources ) ,
. resources = & pwrkey_resources [ 0 ] ,
} ,
2017-03-17 10:58:50 +03:00
{ . name = " hi655x-regulator " , } ,
{ . name = " hi655x-clk " , } ,
2016-06-15 01:43:32 +03:00
} ;
2016-02-14 09:29:21 +03:00
static void hi655x_local_irq_clear ( struct regmap * map )
{
int i ;
regmap_write ( map , HI655X_ANA_IRQM_BASE , HI655X_IRQ_CLR ) ;
for ( i = 0 ; i < HI655X_IRQ_ARRAY ; i + + ) {
regmap_write ( map , HI655X_IRQ_STAT_BASE + i * HI655X_STRIDE ,
HI655X_IRQ_CLR ) ;
}
}
static int hi655x_pmic_probe ( struct platform_device * pdev )
{
int ret ;
struct hi655x_pmic * pmic ;
struct device * dev = & pdev - > dev ;
struct device_node * np = dev - > of_node ;
void __iomem * base ;
pmic = devm_kzalloc ( dev , sizeof ( * pmic ) , GFP_KERNEL ) ;
if ( ! pmic )
return - ENOMEM ;
pmic - > dev = dev ;
pmic - > res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
base = devm_ioremap_resource ( dev , pmic - > res ) ;
2016-06-18 20:26:07 +03:00
if ( IS_ERR ( base ) )
return PTR_ERR ( base ) ;
2016-02-14 09:29:21 +03:00
pmic - > regmap = devm_regmap_init_mmio_clk ( dev , NULL , base ,
& hi655x_regmap_config ) ;
regmap_read ( pmic - > regmap , HI655X_BUS_ADDR ( HI655X_VER_REG ) , & pmic - > ver ) ;
if ( ( pmic - > ver < PMU_VER_START ) | | ( pmic - > ver > PMU_VER_END ) ) {
dev_warn ( dev , " PMU version %d unsupported \n " , pmic - > ver ) ;
return - EINVAL ;
}
hi655x_local_irq_clear ( pmic - > regmap ) ;
pmic - > gpio = of_get_named_gpio ( np , " pmic-gpios " , 0 ) ;
if ( ! gpio_is_valid ( pmic - > gpio ) ) {
dev_err ( dev , " Failed to get the pmic-gpios \n " ) ;
return - ENODEV ;
}
ret = devm_gpio_request_one ( dev , pmic - > gpio , GPIOF_IN ,
" hi655x_pmic_irq " ) ;
if ( ret < 0 ) {
dev_err ( dev , " Failed to request gpio %d ret = %d \n " ,
pmic - > gpio , ret ) ;
return ret ;
}
ret = regmap_add_irq_chip ( pmic - > regmap , gpio_to_irq ( pmic - > gpio ) ,
IRQF_TRIGGER_LOW | IRQF_NO_SUSPEND , 0 ,
& hi655x_irq_chip , & pmic - > irq_data ) ;
if ( ret ) {
dev_err ( dev , " Failed to obtain 'hi655x_pmic_irq' %d \n " , ret ) ;
return ret ;
}
platform_set_drvdata ( pdev , pmic ) ;
ret = mfd_add_devices ( dev , PLATFORM_DEVID_AUTO , hi655x_pmic_devs ,
2016-06-15 01:43:32 +03:00
ARRAY_SIZE ( hi655x_pmic_devs ) , NULL , 0 ,
regmap_irq_get_domain ( pmic - > irq_data ) ) ;
2016-02-14 09:29:21 +03:00
if ( ret ) {
dev_err ( dev , " Failed to register device %d \n " , ret ) ;
regmap_del_irq_chip ( gpio_to_irq ( pmic - > gpio ) , pmic - > irq_data ) ;
return ret ;
}
return 0 ;
}
static int hi655x_pmic_remove ( struct platform_device * pdev )
{
struct hi655x_pmic * pmic = platform_get_drvdata ( pdev ) ;
regmap_del_irq_chip ( gpio_to_irq ( pmic - > gpio ) , pmic - > irq_data ) ;
mfd_remove_devices ( & pdev - > dev ) ;
return 0 ;
}
static const struct of_device_id hi655x_pmic_match [ ] = {
{ . compatible = " hisilicon,hi655x-pmic " , } ,
{ } ,
} ;
2016-10-14 18:40:51 +03:00
MODULE_DEVICE_TABLE ( of , hi655x_pmic_match ) ;
2016-02-14 09:29:21 +03:00
static struct platform_driver hi655x_pmic_driver = {
. driver = {
. name = " hi655x-pmic " ,
. of_match_table = of_match_ptr ( hi655x_pmic_match ) ,
} ,
. probe = hi655x_pmic_probe ,
. remove = hi655x_pmic_remove ,
} ;
module_platform_driver ( hi655x_pmic_driver ) ;
MODULE_AUTHOR ( " Chen Feng <puck.chen@hisilicon.com> " ) ;
MODULE_DESCRIPTION ( " Hisilicon hi655x PMIC driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;