2013-07-29 21:00:43 +04:00
/*
* da9063 - core . c : Device access for Dialog DA9063 modules
*
* Copyright 2012 Dialog Semiconductors Ltd .
* Copyright 2013 Philipp Zabel , Pengutronix
*
2016-08-08 16:16:11 +03:00
* Author : Krystian Garbaciak , Dialog Semiconductor
* Author : Michal Hajduk , Dialog Semiconductor
2013-07-29 21:00:43 +04:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/device.h>
# include <linux/delay.h>
# include <linux/interrupt.h>
# include <linux/mutex.h>
# include <linux/mfd/core.h>
# include <linux/regmap.h>
# include <linux/mfd/da9063/core.h>
# include <linux/mfd/da9063/pdata.h>
# include <linux/mfd/da9063/registers.h>
# include <linux/proc_fs.h>
# include <linux/kthread.h>
# include <linux/uaccess.h>
2013-07-29 21:00:44 +04:00
static struct resource da9063_regulators_resources [ ] = {
{
. name = " LDO_LIM " ,
. start = DA9063_IRQ_LDO_LIM ,
. end = DA9063_IRQ_LDO_LIM ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
static struct resource da9063_rtc_resources [ ] = {
{
. name = " ALARM " ,
. start = DA9063_IRQ_ALARM ,
. end = DA9063_IRQ_ALARM ,
. flags = IORESOURCE_IRQ ,
} ,
{
. name = " TICK " ,
. start = DA9063_IRQ_TICK ,
. end = DA9063_IRQ_TICK ,
. flags = IORESOURCE_IRQ ,
}
} ;
static struct resource da9063_onkey_resources [ ] = {
{
2015-05-19 13:32:45 +03:00
. name = " ONKEY " ,
2013-07-29 21:00:44 +04:00
. start = DA9063_IRQ_ONKEY ,
. end = DA9063_IRQ_ONKEY ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
static struct resource da9063_hwmon_resources [ ] = {
{
. start = DA9063_IRQ_ADC_RDY ,
. end = DA9063_IRQ_ADC_RDY ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
2013-11-18 17:32:57 +04:00
static const struct mfd_cell da9063_devs [ ] = {
2013-07-29 21:00:43 +04:00
{
. name = DA9063_DRVNAME_REGULATORS ,
2013-07-29 21:00:44 +04:00
. num_resources = ARRAY_SIZE ( da9063_regulators_resources ) ,
. resources = da9063_regulators_resources ,
2013-07-29 21:00:43 +04:00
} ,
{
. name = DA9063_DRVNAME_LEDS ,
} ,
{
. name = DA9063_DRVNAME_WATCHDOG ,
2015-01-20 16:54:25 +03:00
. of_compatible = " dlg,da9063-watchdog " ,
2013-07-29 21:00:43 +04:00
} ,
{
. name = DA9063_DRVNAME_HWMON ,
2013-07-29 21:00:44 +04:00
. num_resources = ARRAY_SIZE ( da9063_hwmon_resources ) ,
. resources = da9063_hwmon_resources ,
2013-07-29 21:00:43 +04:00
} ,
{
. name = DA9063_DRVNAME_ONKEY ,
2013-07-29 21:00:44 +04:00
. num_resources = ARRAY_SIZE ( da9063_onkey_resources ) ,
. resources = da9063_onkey_resources ,
2015-05-19 13:32:45 +03:00
. of_compatible = " dlg,da9063-onkey " ,
2013-07-29 21:00:43 +04:00
} ,
{
. name = DA9063_DRVNAME_RTC ,
2013-07-29 21:00:44 +04:00
. num_resources = ARRAY_SIZE ( da9063_rtc_resources ) ,
. resources = da9063_rtc_resources ,
2015-01-20 16:54:25 +03:00
. of_compatible = " dlg,da9063-rtc " ,
2013-07-29 21:00:43 +04:00
} ,
{
. name = DA9063_DRVNAME_VIBRATION ,
} ,
} ;
2015-05-19 13:32:45 +03:00
static int da9063_clear_fault_log ( struct da9063 * da9063 )
{
int ret = 0 ;
int fault_log = 0 ;
ret = regmap_read ( da9063 - > regmap , DA9063_REG_FAULT_LOG , & fault_log ) ;
if ( ret < 0 ) {
dev_err ( da9063 - > dev , " Cannot read FAULT_LOG. \n " ) ;
return - EIO ;
}
if ( fault_log ) {
if ( fault_log & DA9063_TWD_ERROR )
dev_dbg ( da9063 - > dev ,
" Fault log entry detected: DA9063_TWD_ERROR \n " ) ;
if ( fault_log & DA9063_POR )
dev_dbg ( da9063 - > dev ,
" Fault log entry detected: DA9063_POR \n " ) ;
if ( fault_log & DA9063_VDD_FAULT )
dev_dbg ( da9063 - > dev ,
" Fault log entry detected: DA9063_VDD_FAULT \n " ) ;
if ( fault_log & DA9063_VDD_START )
dev_dbg ( da9063 - > dev ,
" Fault log entry detected: DA9063_VDD_START \n " ) ;
if ( fault_log & DA9063_TEMP_CRIT )
dev_dbg ( da9063 - > dev ,
" Fault log entry detected: DA9063_TEMP_CRIT \n " ) ;
if ( fault_log & DA9063_KEY_RESET )
dev_dbg ( da9063 - > dev ,
" Fault log entry detected: DA9063_KEY_RESET \n " ) ;
if ( fault_log & DA9063_NSHUTDOWN )
dev_dbg ( da9063 - > dev ,
" Fault log entry detected: DA9063_NSHUTDOWN \n " ) ;
if ( fault_log & DA9063_WAIT_SHUT )
dev_dbg ( da9063 - > dev ,
" Fault log entry detected: DA9063_WAIT_SHUT \n " ) ;
}
ret = regmap_write ( da9063 - > regmap ,
DA9063_REG_FAULT_LOG ,
fault_log ) ;
if ( ret < 0 )
dev_err ( da9063 - > dev ,
" Cannot reset FAULT_LOG values %d \n " , ret ) ;
return ret ;
}
2013-07-29 21:00:43 +04:00
int da9063_device_init ( struct da9063 * da9063 , unsigned int irq )
{
struct da9063_pdata * pdata = da9063 - > dev - > platform_data ;
2014-02-14 18:08:11 +04:00
int model , variant_id , variant_code ;
2013-07-29 21:00:43 +04:00
int ret ;
2015-05-19 13:32:45 +03:00
ret = da9063_clear_fault_log ( da9063 ) ;
if ( ret < 0 )
dev_err ( da9063 - > dev , " Cannot clear fault log \n " ) ;
2013-07-29 21:00:43 +04:00
if ( pdata ) {
da9063 - > flags = pdata - > flags ;
da9063 - > irq_base = pdata - > irq_base ;
} else {
da9063 - > flags = 0 ;
2014-11-21 18:29:07 +03:00
da9063 - > irq_base = - 1 ;
2013-07-29 21:00:43 +04:00
}
da9063 - > chip_irq = irq ;
if ( pdata & & pdata - > init ! = NULL ) {
ret = pdata - > init ( da9063 ) ;
if ( ret ! = 0 ) {
dev_err ( da9063 - > dev ,
" Platform initialization failed. \n " ) ;
return ret ;
}
}
ret = regmap_read ( da9063 - > regmap , DA9063_REG_CHIP_ID , & model ) ;
if ( ret < 0 ) {
dev_err ( da9063 - > dev , " Cannot read chip model id. \n " ) ;
return - EIO ;
}
if ( model ! = PMIC_DA9063 ) {
dev_err ( da9063 - > dev , " Invalid chip model id: 0x%02x \n " , model ) ;
return - ENODEV ;
}
2014-02-14 18:08:11 +04:00
ret = regmap_read ( da9063 - > regmap , DA9063_REG_CHIP_VARIANT , & variant_id ) ;
2013-07-29 21:00:43 +04:00
if ( ret < 0 ) {
2014-02-14 18:08:11 +04:00
dev_err ( da9063 - > dev , " Cannot read chip variant id. \n " ) ;
2013-07-29 21:00:43 +04:00
return - EIO ;
}
2014-02-14 18:08:11 +04:00
variant_code = variant_id > > DA9063_CHIP_VARIANT_SHIFT ;
dev_info ( da9063 - > dev ,
" Device detected (chip-ID: 0x%02X, var-ID: 0x%02X) \n " ,
model , variant_id ) ;
2014-07-21 14:39:33 +04:00
if ( variant_code < PMIC_DA9063_BB & & variant_code ! = PMIC_DA9063_AD ) {
dev_err ( da9063 - > dev ,
" Cannot support variant code: 0x%02X \n " , variant_code ) ;
2013-07-29 21:00:43 +04:00
return - ENODEV ;
}
da9063 - > model = model ;
2014-02-14 18:08:11 +04:00
da9063 - > variant_code = variant_code ;
2013-07-29 21:00:43 +04:00
2013-07-29 21:00:44 +04:00
ret = da9063_irq_init ( da9063 ) ;
if ( ret ) {
dev_err ( da9063 - > dev , " Cannot initialize interrupts. \n " ) ;
return ret ;
}
2014-11-21 18:29:07 +03:00
da9063 - > irq_base = regmap_irq_chip_get_base ( da9063 - > regmap_irq ) ;
2013-07-29 21:00:43 +04:00
ret = mfd_add_devices ( da9063 - > dev , - 1 , da9063_devs ,
ARRAY_SIZE ( da9063_devs ) , NULL , da9063 - > irq_base ,
NULL ) ;
if ( ret )
dev_err ( da9063 - > dev , " Cannot add MFD cells \n " ) ;
return ret ;
}
void da9063_device_exit ( struct da9063 * da9063 )
{
mfd_remove_devices ( da9063 - > dev ) ;
2013-07-29 21:00:44 +04:00
da9063_irq_exit ( da9063 ) ;
2013-07-29 21:00:43 +04:00
}
MODULE_DESCRIPTION ( " PMIC driver for Dialog DA9063 " ) ;
2016-08-08 16:16:11 +03:00
MODULE_AUTHOR ( " Krystian Garbaciak " ) ;
MODULE_AUTHOR ( " Michal Hajduk " ) ;
2013-07-29 21:00:43 +04:00
MODULE_LICENSE ( " GPL " ) ;