2019-05-27 09:55:21 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2015-02-22 15:15:29 +03:00
/*
* Copyright ( c ) 2014 MediaTek Inc .
* Author : Flora Fu , MediaTek
*/
# include <linux/interrupt.h>
2019-08-18 16:56:06 +03:00
# include <linux/ioport.h>
2015-02-22 15:15:29 +03:00
# include <linux/module.h>
# include <linux/of_device.h>
# include <linux/of_irq.h>
# include <linux/regmap.h>
# include <linux/mfd/core.h>
2016-01-27 14:47:38 +03:00
# include <linux/mfd/mt6323/core.h>
2019-08-05 08:21:49 +03:00
# include <linux/mfd/mt6397/core.h>
2016-01-27 14:47:38 +03:00
# include <linux/mfd/mt6323/registers.h>
2019-08-05 08:21:49 +03:00
# include <linux/mfd/mt6397/registers.h>
2015-02-22 15:15:29 +03:00
2019-08-18 16:56:08 +03:00
# define MT6323_RTC_BASE 0x8000
# define MT6323_RTC_SIZE 0x40
2015-05-06 10:23:40 +03:00
# define MT6397_RTC_BASE 0xe000
# define MT6397_RTC_SIZE 0x3e
2019-08-18 16:56:08 +03:00
# define MT6323_PWRC_BASE 0x8000
# define MT6323_PWRC_SIZE 0x40
static const struct resource mt6323_rtc_resources [ ] = {
DEFINE_RES_MEM ( MT6323_RTC_BASE , MT6323_RTC_SIZE ) ,
DEFINE_RES_IRQ ( MT6323_IRQ_STATUS_RTC ) ,
} ;
2015-05-06 10:23:40 +03:00
static const struct resource mt6397_rtc_resources [ ] = {
2019-08-18 16:56:06 +03:00
DEFINE_RES_MEM ( MT6397_RTC_BASE , MT6397_RTC_SIZE ) ,
DEFINE_RES_IRQ ( MT6397_IRQ_RTC ) ,
2015-05-06 10:23:40 +03:00
} ;
2017-10-25 16:16:04 +03:00
static const struct resource mt6323_keys_resources [ ] = {
DEFINE_RES_IRQ ( MT6323_IRQ_STATUS_PWRKEY ) ,
DEFINE_RES_IRQ ( MT6323_IRQ_STATUS_FCHRKEY ) ,
} ;
static const struct resource mt6397_keys_resources [ ] = {
DEFINE_RES_IRQ ( MT6397_IRQ_PWRKEY ) ,
DEFINE_RES_IRQ ( MT6397_IRQ_HOMEKEY ) ,
} ;
2019-08-18 16:56:08 +03:00
static const struct resource mt6323_pwrc_resources [ ] = {
DEFINE_RES_MEM ( MT6323_PWRC_BASE , MT6323_PWRC_SIZE ) ,
} ;
2016-01-27 14:47:38 +03:00
static const struct mfd_cell mt6323_devs [ ] = {
{
2019-08-18 16:56:08 +03:00
. name = " mt6323-rtc " ,
. num_resources = ARRAY_SIZE ( mt6323_rtc_resources ) ,
. resources = mt6323_rtc_resources ,
. of_compatible = " mediatek,mt6323-rtc " ,
} , {
2016-01-27 14:47:38 +03:00
. name = " mt6323-regulator " ,
. of_compatible = " mediatek,mt6323-regulator "
2017-03-20 09:47:27 +03:00
} , {
2017-01-23 06:54:45 +03:00
. name = " mt6323-led " ,
. of_compatible = " mediatek,mt6323-led "
2017-10-25 16:16:04 +03:00
} , {
. name = " mtk-pmic-keys " ,
. num_resources = ARRAY_SIZE ( mt6323_keys_resources ) ,
. resources = mt6323_keys_resources ,
. of_compatible = " mediatek,mt6323-keys "
2019-08-18 16:56:08 +03:00
} , {
. name = " mt6323-pwrc " ,
. num_resources = ARRAY_SIZE ( mt6323_pwrc_resources ) ,
. resources = mt6323_pwrc_resources ,
. of_compatible = " mediatek,mt6323-pwrc "
2017-01-23 06:54:45 +03:00
} ,
2016-01-27 14:47:38 +03:00
} ;
2015-02-22 15:15:29 +03:00
static const struct mfd_cell mt6397_devs [ ] = {
{
. name = " mt6397-rtc " ,
2015-05-06 10:23:40 +03:00
. num_resources = ARRAY_SIZE ( mt6397_rtc_resources ) ,
. resources = mt6397_rtc_resources ,
2015-02-22 15:15:29 +03:00
. of_compatible = " mediatek,mt6397-rtc " ,
} , {
. name = " mt6397-regulator " ,
. of_compatible = " mediatek,mt6397-regulator " ,
} , {
. name = " mt6397-codec " ,
. of_compatible = " mediatek,mt6397-codec " ,
} , {
. name = " mt6397-clk " ,
. of_compatible = " mediatek,mt6397-clk " ,
2015-05-27 12:10:35 +03:00
} , {
. name = " mt6397-pinctrl " ,
. of_compatible = " mediatek,mt6397-pinctrl " ,
2017-10-25 16:16:04 +03:00
} , {
. name = " mtk-pmic-keys " ,
. num_resources = ARRAY_SIZE ( mt6397_keys_resources ) ,
. resources = mt6397_keys_resources ,
. of_compatible = " mediatek,mt6397-keys "
}
2015-02-22 15:15:29 +03:00
} ;
2015-08-10 16:10:45 +03:00
# ifdef CONFIG_PM_SLEEP
static int mt6397_irq_suspend ( struct device * dev )
{
struct mt6397_chip * chip = dev_get_drvdata ( dev ) ;
2016-01-27 14:47:36 +03:00
regmap_write ( chip - > regmap , chip - > int_con [ 0 ] , chip - > wake_mask [ 0 ] ) ;
regmap_write ( chip - > regmap , chip - > int_con [ 1 ] , chip - > wake_mask [ 1 ] ) ;
2015-08-10 16:10:45 +03:00
enable_irq_wake ( chip - > irq ) ;
return 0 ;
}
static int mt6397_irq_resume ( struct device * dev )
{
struct mt6397_chip * chip = dev_get_drvdata ( dev ) ;
2016-01-27 14:47:36 +03:00
regmap_write ( chip - > regmap , chip - > int_con [ 0 ] , chip - > irq_masks_cur [ 0 ] ) ;
regmap_write ( chip - > regmap , chip - > int_con [ 1 ] , chip - > irq_masks_cur [ 1 ] ) ;
2015-08-10 16:10:45 +03:00
disable_irq_wake ( chip - > irq ) ;
return 0 ;
}
# endif
static SIMPLE_DEV_PM_OPS ( mt6397_pm_ops , mt6397_irq_suspend ,
mt6397_irq_resume ) ;
2019-10-03 21:53:23 +03:00
struct chip_data {
u32 cid_addr ;
u32 cid_shift ;
} ;
static const struct chip_data mt6323_core = {
. cid_addr = MT6323_CID ,
. cid_shift = 0 ,
} ;
static const struct chip_data mt6397_core = {
. cid_addr = MT6397_CID ,
. cid_shift = 0 ,
} ;
2015-02-22 15:15:29 +03:00
static int mt6397_probe ( struct platform_device * pdev )
{
int ret ;
2016-01-27 14:47:37 +03:00
unsigned int id ;
struct mt6397_chip * pmic ;
2019-10-03 21:53:23 +03:00
const struct chip_data * pmic_core ;
2015-02-22 15:15:29 +03:00
2016-01-27 14:47:37 +03:00
pmic = devm_kzalloc ( & pdev - > dev , sizeof ( * pmic ) , GFP_KERNEL ) ;
if ( ! pmic )
2015-02-22 15:15:29 +03:00
return - ENOMEM ;
2016-01-27 14:47:37 +03:00
pmic - > dev = & pdev - > dev ;
2016-01-27 14:47:36 +03:00
2015-02-22 15:15:29 +03:00
/*
* mt6397 MFD is child device of soc pmic wrapper .
* Regmap is set from its parent .
*/
2016-01-27 14:47:37 +03:00
pmic - > regmap = dev_get_regmap ( pdev - > dev . parent , NULL ) ;
if ( ! pmic - > regmap )
2015-02-22 15:15:29 +03:00
return - ENODEV ;
2019-10-03 21:53:23 +03:00
pmic_core = of_device_get_match_data ( & pdev - > dev ) ;
if ( ! pmic_core )
return - ENODEV ;
2016-01-27 14:47:37 +03:00
2019-10-03 21:53:23 +03:00
ret = regmap_read ( pmic - > regmap , pmic_core - > cid_addr , & id ) ;
2016-01-27 14:47:37 +03:00
if ( ret ) {
2019-10-03 21:53:23 +03:00
dev_err ( & pdev - > dev , " Failed to read chip id: %d \n " , ret ) ;
2016-04-15 11:30:29 +03:00
return ret ;
2016-01-27 14:47:37 +03:00
}
2019-10-03 21:53:23 +03:00
pmic - > chip_id = ( id > > pmic_core - > cid_shift ) & 0xff ;
platform_set_drvdata ( pdev , pmic ) ;
2016-04-15 11:30:29 +03:00
pmic - > irq = platform_get_irq ( pdev , 0 ) ;
if ( pmic - > irq < = 0 )
return pmic - > irq ;
2019-10-03 21:53:23 +03:00
ret = mt6397_irq_init ( pmic ) ;
if ( ret )
return ret ;
2016-04-15 11:30:29 +03:00
2019-10-03 21:53:23 +03:00
switch ( pmic - > chip_id ) {
case MT6323_CHIP_ID :
2019-10-20 18:07:20 +03:00
ret = devm_mfd_add_devices ( & pdev - > dev , PLATFORM_DEVID_NONE ,
mt6323_devs , ARRAY_SIZE ( mt6323_devs ) ,
NULL , 0 , pmic - > irq_domain ) ;
2016-01-27 14:47:38 +03:00
break ;
2019-08-05 08:21:49 +03:00
case MT6391_CHIP_ID :
case MT6397_CHIP_ID :
2019-10-20 18:07:20 +03:00
ret = devm_mfd_add_devices ( & pdev - > dev , PLATFORM_DEVID_NONE ,
mt6397_devs , ARRAY_SIZE ( mt6397_devs ) ,
NULL , 0 , pmic - > irq_domain ) ;
2016-01-27 14:47:37 +03:00
break ;
default :
2019-10-03 21:53:23 +03:00
dev_err ( & pdev - > dev , " unsupported chip: %d \n " , pmic - > chip_id ) ;
2018-10-22 05:55:06 +03:00
return - ENODEV ;
2016-01-27 14:47:37 +03:00
}
2015-02-22 15:15:29 +03:00
2016-01-27 14:47:37 +03:00
if ( ret ) {
irq_domain_remove ( pmic - > irq_domain ) ;
2015-02-22 15:15:29 +03:00
dev_err ( & pdev - > dev , " failed to add child devices: %d \n " , ret ) ;
2016-01-27 14:47:37 +03:00
}
2015-02-22 15:15:29 +03:00
return ret ;
}
static const struct of_device_id mt6397_of_match [ ] = {
2019-10-03 21:53:23 +03:00
{
. compatible = " mediatek,mt6323 " ,
. data = & mt6323_core ,
} , {
. compatible = " mediatek,mt6397 " ,
. data = & mt6397_core ,
} , {
/* sentinel */
}
2015-02-22 15:15:29 +03:00
} ;
MODULE_DEVICE_TABLE ( of , mt6397_of_match ) ;
2016-02-10 19:50:18 +03:00
static const struct platform_device_id mt6397_id [ ] = {
{ " mt6397 " , 0 } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( platform , mt6397_id ) ;
2015-02-22 15:15:29 +03:00
static struct platform_driver mt6397_driver = {
. probe = mt6397_probe ,
. driver = {
. name = " mt6397 " ,
. of_match_table = of_match_ptr ( mt6397_of_match ) ,
2015-08-10 16:10:45 +03:00
. pm = & mt6397_pm_ops ,
2015-02-22 15:15:29 +03:00
} ,
2016-02-10 19:50:18 +03:00
. id_table = mt6397_id ,
2015-02-22 15:15:29 +03:00
} ;
module_platform_driver ( mt6397_driver ) ;
MODULE_AUTHOR ( " Flora Fu, MediaTek " ) ;
MODULE_DESCRIPTION ( " Driver for MediaTek MT6397 PMIC " ) ;
MODULE_LICENSE ( " GPL " ) ;