2019-05-27 08:55:05 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2010-08-19 15:09:36 +03:00
/*
* ISP1704 USB Charger Detection driver
*
* Copyright ( C ) 2010 Nokia Corporation
2013-09-08 10:50:37 +02:00
* Copyright ( C ) 2012 - 2013 Pali Rohár < pali . rohar @ gmail . com >
2010-08-19 15:09:36 +03:00
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/err.h>
# include <linux/init.h>
# include <linux/types.h>
# include <linux/device.h>
# include <linux/sysfs.h>
# include <linux/platform_device.h>
# include <linux/power_supply.h>
# include <linux/delay.h>
2013-12-01 02:00:10 +01:00
# include <linux/of.h>
2010-08-19 15:09:36 +03:00
2018-12-13 02:38:58 +01:00
# include <linux/gpio/consumer.h>
2010-08-19 15:09:36 +03:00
# include <linux/usb/otg.h>
# include <linux/usb/ulpi.h>
# include <linux/usb/ch9.h>
# include <linux/usb/gadget.h>
/* Vendor specific Power Control register */
# define ISP1704_PWR_CTRL 0x3d
# define ISP1704_PWR_CTRL_SWCTRL (1 << 0)
# define ISP1704_PWR_CTRL_DET_COMP (1 << 1)
# define ISP1704_PWR_CTRL_BVALID_RISE (1 << 2)
# define ISP1704_PWR_CTRL_BVALID_FALL (1 << 3)
# define ISP1704_PWR_CTRL_DP_WKPU_EN (1 << 4)
# define ISP1704_PWR_CTRL_VDAT_DET (1 << 5)
# define ISP1704_PWR_CTRL_DPVSRC_EN (1 << 6)
# define ISP1704_PWR_CTRL_HWDETECT (1 << 7)
# define NXP_VENDOR_ID 0x04cc
static u16 isp170x_id [ ] = {
0x1704 ,
0x1707 ,
} ;
struct isp1704_charger {
2015-03-12 08:44:11 +01:00
struct device * dev ;
struct power_supply * psy ;
struct power_supply_desc psy_desc ;
2018-12-13 02:38:58 +01:00
struct gpio_desc * enable_gpio ;
2015-03-12 08:44:11 +01:00
struct usb_phy * phy ;
struct notifier_block nb ;
struct work_struct work ;
2010-08-19 15:09:36 +03:00
2010-11-04 16:31:47 +02:00
/* properties */
2010-11-04 16:31:46 +02:00
char model [ 8 ] ;
2010-08-19 15:09:36 +03:00
unsigned present : 1 ;
2010-11-04 16:31:47 +02:00
unsigned online : 1 ;
unsigned current_max ;
2010-08-19 15:09:36 +03:00
} ;
2012-02-13 13:24:16 +02:00
static inline int isp1704_read ( struct isp1704_charger * isp , u32 reg )
{
return usb_phy_io_read ( isp - > phy , reg ) ;
}
2016-01-01 13:03:29 +02:00
static inline int isp1704_write ( struct isp1704_charger * isp , u32 reg , u32 val )
2012-02-13 13:24:16 +02:00
{
return usb_phy_io_write ( isp - > phy , val , reg ) ;
}
2011-03-29 16:27:59 +03:00
static void isp1704_charger_set_power ( struct isp1704_charger * isp , bool on )
{
2018-12-13 02:38:58 +01:00
gpiod_set_value ( isp - > enable_gpio , on ) ;
2011-03-29 16:27:59 +03:00
}
2010-11-04 16:31:47 +02:00
/*
* Determine is the charging port DCP ( dedicated charger ) or CDP ( Host / HUB
* chargers ) .
*
* REVISIT : The method is defined in Battery Charging Specification and is
* applicable to any ULPI transceiver . Nothing isp170x specific here .
*/
static inline int isp1704_charger_type ( struct isp1704_charger * isp )
{
u8 reg ;
u8 func_ctrl ;
u8 otg_ctrl ;
int type = POWER_SUPPLY_TYPE_USB_DCP ;
2012-02-13 13:24:16 +02:00
func_ctrl = isp1704_read ( isp , ULPI_FUNC_CTRL ) ;
otg_ctrl = isp1704_read ( isp , ULPI_OTG_CTRL ) ;
2010-11-04 16:31:47 +02:00
/* disable pulldowns */
reg = ULPI_OTG_CTRL_DM_PULLDOWN | ULPI_OTG_CTRL_DP_PULLDOWN ;
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_CLR ( ULPI_OTG_CTRL ) , reg ) ;
2010-11-04 16:31:47 +02:00
/* full speed */
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_CLR ( ULPI_FUNC_CTRL ) ,
2010-11-04 16:31:47 +02:00
ULPI_FUNC_CTRL_XCVRSEL_MASK ) ;
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_SET ( ULPI_FUNC_CTRL ) ,
2010-11-04 16:31:47 +02:00
ULPI_FUNC_CTRL_FULL_SPEED ) ;
/* Enable strong pull-up on DP (1.5K) and reset */
reg = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET ;
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_SET ( ULPI_FUNC_CTRL ) , reg ) ;
2010-11-04 16:31:47 +02:00
usleep_range ( 1000 , 2000 ) ;
2012-02-13 13:24:16 +02:00
reg = isp1704_read ( isp , ULPI_DEBUG ) ;
2010-11-04 16:31:47 +02:00
if ( ( reg & 3 ) ! = 3 )
type = POWER_SUPPLY_TYPE_USB_CDP ;
/* recover original state */
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_FUNC_CTRL , func_ctrl ) ;
isp1704_write ( isp , ULPI_OTG_CTRL , otg_ctrl ) ;
2010-11-04 16:31:47 +02:00
return type ;
}
2010-08-19 15:09:36 +03:00
/*
* ISP1704 detects PS / 2 adapters as charger . To make sure the detected charger
* is actually a dedicated charger , the following steps need to be taken .
*/
static inline int isp1704_charger_verify ( struct isp1704_charger * isp )
{
int ret = 0 ;
u8 r ;
/* Reset the transceiver */
2012-02-13 13:24:16 +02:00
r = isp1704_read ( isp , ULPI_FUNC_CTRL ) ;
2010-08-19 15:09:36 +03:00
r | = ULPI_FUNC_CTRL_RESET ;
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_FUNC_CTRL , r ) ;
2010-08-19 15:09:36 +03:00
usleep_range ( 1000 , 2000 ) ;
/* Set normal mode */
r & = ~ ( ULPI_FUNC_CTRL_RESET | ULPI_FUNC_CTRL_OPMODE_MASK ) ;
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_FUNC_CTRL , r ) ;
2010-08-19 15:09:36 +03:00
/* Clear the DP and DM pull-down bits */
r = ULPI_OTG_CTRL_DP_PULLDOWN | ULPI_OTG_CTRL_DM_PULLDOWN ;
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_CLR ( ULPI_OTG_CTRL ) , r ) ;
2010-08-19 15:09:36 +03:00
/* Enable strong pull-up on DP (1.5K) and reset */
r = ULPI_FUNC_CTRL_TERMSELECT | ULPI_FUNC_CTRL_RESET ;
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_SET ( ULPI_FUNC_CTRL ) , r ) ;
2010-08-19 15:09:36 +03:00
usleep_range ( 1000 , 2000 ) ;
/* Read the line state */
2012-02-13 13:24:16 +02:00
if ( ! isp1704_read ( isp , ULPI_DEBUG ) ) {
2010-08-19 15:09:36 +03:00
/* Disable strong pull-up on DP (1.5K) */
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_CLR ( ULPI_FUNC_CTRL ) ,
2010-08-19 15:09:36 +03:00
ULPI_FUNC_CTRL_TERMSELECT ) ;
return 1 ;
}
/* Is it a charger or PS/2 connection */
/* Enable weak pull-up resistor on DP */
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_SET ( ISP1704_PWR_CTRL ) ,
2010-08-19 15:09:36 +03:00
ISP1704_PWR_CTRL_DP_WKPU_EN ) ;
/* Disable strong pull-up on DP (1.5K) */
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_CLR ( ULPI_FUNC_CTRL ) ,
2010-08-19 15:09:36 +03:00
ULPI_FUNC_CTRL_TERMSELECT ) ;
/* Enable weak pull-down resistor on DM */
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_SET ( ULPI_OTG_CTRL ) ,
2010-08-19 15:09:36 +03:00
ULPI_OTG_CTRL_DM_PULLDOWN ) ;
/* It's a charger if the line states are clear */
2012-02-13 13:24:16 +02:00
if ( ! ( isp1704_read ( isp , ULPI_DEBUG ) ) )
2010-08-19 15:09:36 +03:00
ret = 1 ;
/* Disable weak pull-up resistor on DP */
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_CLR ( ISP1704_PWR_CTRL ) ,
2010-08-19 15:09:36 +03:00
ISP1704_PWR_CTRL_DP_WKPU_EN ) ;
return ret ;
}
static inline int isp1704_charger_detect ( struct isp1704_charger * isp )
{
unsigned long timeout ;
2010-11-04 16:31:47 +02:00
u8 pwr_ctrl ;
2010-08-19 15:09:36 +03:00
int ret = 0 ;
2012-02-13 13:24:16 +02:00
pwr_ctrl = isp1704_read ( isp , ISP1704_PWR_CTRL ) ;
2010-11-04 16:31:47 +02:00
2010-08-19 15:09:36 +03:00
/* set SW control bit in PWR_CTRL register */
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ISP1704_PWR_CTRL ,
2010-08-19 15:09:36 +03:00
ISP1704_PWR_CTRL_SWCTRL ) ;
/* enable manual charger detection */
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ULPI_SET ( ISP1704_PWR_CTRL ) ,
2010-11-04 16:31:47 +02:00
ISP1704_PWR_CTRL_SWCTRL
| ISP1704_PWR_CTRL_DPVSRC_EN ) ;
2010-08-19 15:09:36 +03:00
usleep_range ( 1000 , 2000 ) ;
timeout = jiffies + msecs_to_jiffies ( 300 ) ;
do {
/* Check if there is a charger */
2012-02-13 13:24:16 +02:00
if ( isp1704_read ( isp , ISP1704_PWR_CTRL )
2010-08-19 15:09:36 +03:00
& ISP1704_PWR_CTRL_VDAT_DET ) {
ret = isp1704_charger_verify ( isp ) ;
break ;
}
2010-11-04 16:31:47 +02:00
} while ( ! time_after ( jiffies , timeout ) & & isp - > online ) ;
/* recover original state */
2012-02-13 13:24:16 +02:00
isp1704_write ( isp , ISP1704_PWR_CTRL , pwr_ctrl ) ;
2010-08-19 15:09:36 +03:00
return ret ;
}
2013-09-08 10:50:37 +02:00
static inline int isp1704_charger_detect_dcp ( struct isp1704_charger * isp )
{
if ( isp1704_charger_detect ( isp ) & &
isp1704_charger_type ( isp ) = = POWER_SUPPLY_TYPE_USB_DCP )
return true ;
else
return false ;
}
2010-08-19 15:09:36 +03:00
static void isp1704_charger_work ( struct work_struct * data )
{
struct isp1704_charger * isp =
container_of ( data , struct isp1704_charger , work ) ;
2010-11-04 16:31:47 +02:00
static DEFINE_MUTEX ( lock ) ;
2010-08-19 15:09:36 +03:00
2010-11-04 16:31:47 +02:00
mutex_lock ( & lock ) ;
2010-08-19 15:09:36 +03:00
2013-09-08 10:50:37 +02:00
switch ( isp - > phy - > last_event ) {
2010-08-19 15:09:36 +03:00
case USB_EVENT_VBUS :
2013-09-08 10:50:37 +02:00
/* do not call wall charger detection more times */
if ( ! isp - > present ) {
isp - > online = true ;
isp - > present = 1 ;
isp1704_charger_set_power ( isp , 1 ) ;
/* detect wall charger */
if ( isp1704_charger_detect_dcp ( isp ) ) {
2015-03-12 08:44:11 +01:00
isp - > psy_desc . type = POWER_SUPPLY_TYPE_USB_DCP ;
2013-09-08 10:50:37 +02:00
isp - > current_max = 1800 ;
} else {
2015-03-12 08:44:11 +01:00
isp - > psy_desc . type = POWER_SUPPLY_TYPE_USB ;
2013-09-08 10:50:37 +02:00
isp - > current_max = 500 ;
}
2010-11-04 16:31:47 +02:00
2013-09-08 10:50:37 +02:00
/* enable data pullups */
if ( isp - > phy - > otg - > gadget )
usb_gadget_connect ( isp - > phy - > otg - > gadget ) ;
2010-11-04 16:31:47 +02:00
}
2015-03-12 08:44:11 +01:00
if ( isp - > psy_desc . type ! = POWER_SUPPLY_TYPE_USB_DCP ) {
2010-11-04 16:31:47 +02:00
/*
* Only 500 mA here or high speed chirp
* handshaking may break
*/
2013-09-08 10:50:37 +02:00
if ( isp - > current_max > 500 )
isp - > current_max = 500 ;
if ( isp - > current_max > 100 )
2015-03-12 08:44:11 +01:00
isp - > psy_desc . type = POWER_SUPPLY_TYPE_USB_CDP ;
2010-11-04 16:31:47 +02:00
}
2010-08-19 15:09:36 +03:00
break ;
case USB_EVENT_NONE :
2010-11-04 16:31:47 +02:00
isp - > online = false ;
isp - > present = 0 ;
isp - > current_max = 0 ;
2015-03-12 08:44:11 +01:00
isp - > psy_desc . type = POWER_SUPPLY_TYPE_USB ;
2010-11-04 16:31:47 +02:00
/*
* Disable data pullups . We need to prevent the controller from
* enumerating .
*
* FIXME : This is here to allow charger detection with Host / HUB
* chargers . The pullups may be enabled elsewhere , so this can
* not be the final solution .
*/
2012-02-13 13:24:17 +02:00
if ( isp - > phy - > otg - > gadget )
usb_gadget_disconnect ( isp - > phy - > otg - > gadget ) ;
2011-03-29 16:27:59 +03:00
isp1704_charger_set_power ( isp , 0 ) ;
2010-11-04 16:31:47 +02:00
break ;
2010-08-19 15:09:36 +03:00
default :
2010-11-04 16:31:47 +02:00
goto out ;
2010-08-19 15:09:36 +03:00
}
2015-03-12 08:44:11 +01:00
power_supply_changed ( isp - > psy ) ;
2010-11-04 16:31:47 +02:00
out :
mutex_unlock ( & lock ) ;
}
static int isp1704_notifier_call ( struct notifier_block * nb ,
2013-09-08 10:50:37 +02:00
unsigned long val , void * v )
2010-11-04 16:31:47 +02:00
{
struct isp1704_charger * isp =
container_of ( nb , struct isp1704_charger , nb ) ;
schedule_work ( & isp - > work ) ;
2010-08-19 15:09:36 +03:00
return NOTIFY_OK ;
}
static int isp1704_charger_get_property ( struct power_supply * psy ,
enum power_supply_property psp ,
union power_supply_propval * val )
{
2015-03-12 08:44:11 +01:00
struct isp1704_charger * isp = power_supply_get_drvdata ( psy ) ;
2010-08-19 15:09:36 +03:00
switch ( psp ) {
case POWER_SUPPLY_PROP_PRESENT :
val - > intval = isp - > present ;
break ;
2010-11-04 16:31:47 +02:00
case POWER_SUPPLY_PROP_ONLINE :
val - > intval = isp - > online ;
break ;
case POWER_SUPPLY_PROP_CURRENT_MAX :
val - > intval = isp - > current_max ;
break ;
2010-08-19 15:09:36 +03:00
case POWER_SUPPLY_PROP_MODEL_NAME :
val - > strval = isp - > model ;
break ;
case POWER_SUPPLY_PROP_MANUFACTURER :
val - > strval = " NXP " ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static enum power_supply_property power_props [ ] = {
POWER_SUPPLY_PROP_PRESENT ,
2010-11-04 16:31:47 +02:00
POWER_SUPPLY_PROP_ONLINE ,
POWER_SUPPLY_PROP_CURRENT_MAX ,
2010-08-19 15:09:36 +03:00
POWER_SUPPLY_PROP_MODEL_NAME ,
POWER_SUPPLY_PROP_MANUFACTURER ,
} ;
static inline int isp1704_test_ulpi ( struct isp1704_charger * isp )
{
int vendor ;
int product ;
int i ;
2019-07-05 10:36:12 +01:00
int ret ;
2010-08-19 15:09:36 +03:00
/* Test ULPI interface */
2012-02-13 13:24:16 +02:00
ret = isp1704_write ( isp , ULPI_SCRATCH , 0xaa ) ;
2010-08-19 15:09:36 +03:00
if ( ret < 0 )
return ret ;
2012-02-13 13:24:16 +02:00
ret = isp1704_read ( isp , ULPI_SCRATCH ) ;
2010-08-19 15:09:36 +03:00
if ( ret < 0 )
return ret ;
if ( ret ! = 0xaa )
return - ENODEV ;
/* Verify the product and vendor id matches */
2012-02-13 13:24:16 +02:00
vendor = isp1704_read ( isp , ULPI_VENDOR_ID_LOW ) ;
vendor | = isp1704_read ( isp , ULPI_VENDOR_ID_HIGH ) < < 8 ;
2010-08-19 15:09:36 +03:00
if ( vendor ! = NXP_VENDOR_ID )
return - ENODEV ;
2012-02-13 13:24:16 +02:00
product = isp1704_read ( isp , ULPI_PRODUCT_ID_LOW ) ;
product | = isp1704_read ( isp , ULPI_PRODUCT_ID_HIGH ) < < 8 ;
2010-08-19 15:09:36 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( isp170x_id ) ; i + + ) {
if ( product = = isp170x_id [ i ] ) {
sprintf ( isp - > model , " isp%x " , product ) ;
return product ;
}
}
dev_err ( isp - > dev , " product id %x not matching known ids " , product ) ;
return - ENODEV ;
}
2012-11-19 13:22:23 -05:00
static int isp1704_charger_probe ( struct platform_device * pdev )
2010-08-19 15:09:36 +03:00
{
struct isp1704_charger * isp ;
int ret = - ENODEV ;
2015-03-12 08:44:11 +01:00
struct power_supply_config psy_cfg = { } ;
2010-08-19 15:09:36 +03:00
2013-03-11 15:34:15 +09:00
isp = devm_kzalloc ( & pdev - > dev , sizeof ( * isp ) , GFP_KERNEL ) ;
2010-08-19 15:09:36 +03:00
if ( ! isp )
return - ENOMEM ;
2018-12-13 02:38:58 +01:00
isp - > enable_gpio = devm_gpiod_get ( & pdev - > dev , " nxp,enable " ,
GPIOD_OUT_HIGH ) ;
if ( IS_ERR ( isp - > enable_gpio ) ) {
ret = PTR_ERR ( isp - > enable_gpio ) ;
dev_err ( & pdev - > dev , " Could not get reset gpio: %d \n " , ret ) ;
return ret ;
}
if ( pdev - > dev . of_node )
2013-12-01 02:00:10 +01:00
isp - > phy = devm_usb_get_phy_by_phandle ( & pdev - > dev , " usb-phy " , 0 ) ;
else
isp - > phy = devm_usb_get_phy ( & pdev - > dev , USB_PHY_TYPE_USB2 ) ;
if ( IS_ERR ( isp - > phy ) ) {
ret = PTR_ERR ( isp - > phy ) ;
2016-02-21 12:28:18 +01:00
dev_err ( & pdev - > dev , " usb_get_phy failed \n " ) ;
2013-12-01 02:00:10 +01:00
goto fail0 ;
}
2010-08-19 15:09:36 +03:00
2010-11-04 16:31:48 +02:00
isp - > dev = & pdev - > dev ;
platform_set_drvdata ( pdev , isp ) ;
2011-03-29 16:27:59 +03:00
isp1704_charger_set_power ( isp , 1 ) ;
2010-08-19 15:09:36 +03:00
ret = isp1704_test_ulpi ( isp ) ;
2016-02-21 12:28:18 +01:00
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " isp1704_test_ulpi failed \n " ) ;
2010-08-19 15:09:36 +03:00
goto fail1 ;
2016-02-21 12:28:18 +01:00
}
2010-08-19 15:09:36 +03:00
2015-03-12 08:44:11 +01:00
isp - > psy_desc . name = " isp1704 " ;
isp - > psy_desc . type = POWER_SUPPLY_TYPE_USB ;
isp - > psy_desc . properties = power_props ;
isp - > psy_desc . num_properties = ARRAY_SIZE ( power_props ) ;
isp - > psy_desc . get_property = isp1704_charger_get_property ;
2010-08-19 15:09:36 +03:00
2015-03-12 08:44:11 +01:00
psy_cfg . drv_data = isp ;
isp - > psy = power_supply_register ( isp - > dev , & isp - > psy_desc , & psy_cfg ) ;
if ( IS_ERR ( isp - > psy ) ) {
ret = PTR_ERR ( isp - > psy ) ;
2016-02-21 12:28:18 +01:00
dev_err ( & pdev - > dev , " power_supply_register failed \n " ) ;
2010-08-19 15:09:36 +03:00
goto fail1 ;
2015-03-12 08:44:11 +01:00
}
2010-08-19 15:09:36 +03:00
/*
2012-02-13 13:24:16 +02:00
* REVISIT : using work in order to allow the usb notifications to be
2010-08-19 15:09:36 +03:00
* made atomically in the future .
*/
INIT_WORK ( & isp - > work , isp1704_charger_work ) ;
isp - > nb . notifier_call = isp1704_notifier_call ;
2012-02-13 13:24:16 +02:00
ret = usb_register_notifier ( isp - > phy , & isp - > nb ) ;
2016-02-21 12:28:18 +01:00
if ( ret ) {
dev_err ( & pdev - > dev , " usb_register_notifier failed \n " ) ;
2010-08-19 15:09:36 +03:00
goto fail2 ;
2016-02-21 12:28:18 +01:00
}
2010-08-19 15:09:36 +03:00
dev_info ( isp - > dev , " registered with product id %s \n " , isp - > model ) ;
2010-11-08 12:22:40 +02:00
/*
* Taking over the D + pullup .
*
* FIXME : The device will be disconnected if it was already
* enumerated . The charger driver should be always loaded before any
* gadget is loaded .
*/
2012-02-13 13:24:17 +02:00
if ( isp - > phy - > otg - > gadget )
usb_gadget_disconnect ( isp - > phy - > otg - > gadget ) ;
2010-11-08 12:22:40 +02:00
2013-09-08 10:50:37 +02:00
if ( isp - > phy - > last_event = = USB_EVENT_NONE )
isp1704_charger_set_power ( isp , 0 ) ;
2010-11-08 12:22:40 +02:00
/* Detect charger if VBUS is valid (the cable was already plugged). */
2013-09-08 10:50:37 +02:00
if ( isp - > phy - > last_event = = USB_EVENT_VBUS & &
! isp - > phy - > otg - > default_a )
2010-11-08 12:22:40 +02:00
schedule_work ( & isp - > work ) ;
2010-08-19 15:09:36 +03:00
return 0 ;
fail2 :
2015-03-12 08:44:11 +01:00
power_supply_unregister ( isp - > psy ) ;
2010-08-19 15:09:36 +03:00
fail1 :
2012-03-27 23:22:13 +03:00
isp1704_charger_set_power ( isp , 0 ) ;
2010-08-19 15:09:36 +03:00
fail0 :
dev_err ( & pdev - > dev , " failed to register isp1704 with error %d \n " , ret ) ;
return ret ;
}
2012-11-19 13:26:07 -05:00
static int isp1704_charger_remove ( struct platform_device * pdev )
2010-08-19 15:09:36 +03:00
{
struct isp1704_charger * isp = platform_get_drvdata ( pdev ) ;
2012-02-13 13:24:16 +02:00
usb_unregister_notifier ( isp - > phy , & isp - > nb ) ;
2015-03-12 08:44:11 +01:00
power_supply_unregister ( isp - > psy ) ;
2011-03-29 16:27:59 +03:00
isp1704_charger_set_power ( isp , 0 ) ;
2010-08-19 15:09:36 +03:00
return 0 ;
}
2013-12-01 02:00:10 +01:00
# ifdef CONFIG_OF
static const struct of_device_id omap_isp1704_of_match [ ] = {
{ . compatible = " nxp,isp1704 " , } ,
2016-02-21 12:28:19 +01:00
{ . compatible = " nxp,isp1707 " , } ,
2013-12-01 02:00:10 +01:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , omap_isp1704_of_match ) ;
# endif
2010-08-19 15:09:36 +03:00
static struct platform_driver isp1704_charger_driver = {
. driver = {
. name = " isp1704_charger " ,
2013-12-01 02:00:10 +01:00
. of_match_table = of_match_ptr ( omap_isp1704_of_match ) ,
2010-08-19 15:09:36 +03:00
} ,
. probe = isp1704_charger_probe ,
2012-11-19 13:20:40 -05:00
. remove = isp1704_charger_remove ,
2010-08-19 15:09:36 +03:00
} ;
2011-11-26 12:01:10 +08:00
module_platform_driver ( isp1704_charger_driver ) ;
2010-08-19 15:09:36 +03:00
MODULE_ALIAS ( " platform:isp1704_charger " ) ;
MODULE_AUTHOR ( " Nokia Corporation " ) ;
MODULE_DESCRIPTION ( " ISP170x USB Charger driver " ) ;
MODULE_LICENSE ( " GPL " ) ;