2019-06-03 08:44:49 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2015-12-19 02:17:41 +03:00
/*
* Maxim Integrated MAX3355 USB OTG chip extcon driver
*
* Copyright ( C ) 2014 - 2015 Cogent Embedded , Inc .
* Author : Sergei Shtylyov < sergei . shtylyov @ cogentembedded . com >
*/
2017-09-21 06:11:24 +03:00
# include <linux/extcon-provider.h>
2015-12-19 02:17:41 +03:00
# include <linux/gpio/consumer.h>
# include <linux/interrupt.h>
# include <linux/module.h>
2018-07-11 18:50:29 +03:00
# include <linux/mod_devicetable.h>
2015-12-19 02:17:41 +03:00
# include <linux/platform_device.h>
struct max3355_data {
struct extcon_dev * edev ;
struct gpio_desc * id_gpiod ;
struct gpio_desc * shdn_gpiod ;
} ;
static const unsigned int max3355_cable [ ] = {
EXTCON_USB ,
EXTCON_USB_HOST ,
EXTCON_NONE ,
} ;
static irqreturn_t max3355_id_irq ( int irq , void * dev_id )
{
struct max3355_data * data = dev_id ;
int id = gpiod_get_value_cansleep ( data - > id_gpiod ) ;
if ( id ) {
/*
* ID = 1 means USB HOST cable detached .
* As we don ' t have event for USB peripheral cable attached ,
* we simulate USB peripheral attach here .
*/
2016-08-16 09:55:34 +03:00
extcon_set_state_sync ( data - > edev , EXTCON_USB_HOST , false ) ;
extcon_set_state_sync ( data - > edev , EXTCON_USB , true ) ;
2015-12-19 02:17:41 +03:00
} else {
/*
* ID = 0 means USB HOST cable attached .
* As we don ' t have event for USB peripheral cable detached ,
* we simulate USB peripheral detach here .
*/
2016-08-16 09:55:34 +03:00
extcon_set_state_sync ( data - > edev , EXTCON_USB , false ) ;
extcon_set_state_sync ( data - > edev , EXTCON_USB_HOST , true ) ;
2015-12-19 02:17:41 +03:00
}
return IRQ_HANDLED ;
}
static int max3355_probe ( struct platform_device * pdev )
{
struct max3355_data * data ;
struct gpio_desc * gpiod ;
int irq , err ;
data = devm_kzalloc ( & pdev - > dev , sizeof ( struct max3355_data ) ,
GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
gpiod = devm_gpiod_get ( & pdev - > dev , " id " , GPIOD_IN ) ;
if ( IS_ERR ( gpiod ) ) {
dev_err ( & pdev - > dev , " failed to get ID_OUT GPIO \n " ) ;
return PTR_ERR ( gpiod ) ;
}
data - > id_gpiod = gpiod ;
gpiod = devm_gpiod_get ( & pdev - > dev , " maxim,shdn " , GPIOD_OUT_HIGH ) ;
if ( IS_ERR ( gpiod ) ) {
dev_err ( & pdev - > dev , " failed to get SHDN# GPIO \n " ) ;
return PTR_ERR ( gpiod ) ;
}
data - > shdn_gpiod = gpiod ;
data - > edev = devm_extcon_dev_allocate ( & pdev - > dev , max3355_cable ) ;
if ( IS_ERR ( data - > edev ) ) {
dev_err ( & pdev - > dev , " failed to allocate extcon device \n " ) ;
return PTR_ERR ( data - > edev ) ;
}
err = devm_extcon_dev_register ( & pdev - > dev , data - > edev ) ;
if ( err < 0 ) {
dev_err ( & pdev - > dev , " failed to register extcon device \n " ) ;
return err ;
}
irq = gpiod_to_irq ( data - > id_gpiod ) ;
if ( irq < 0 ) {
dev_err ( & pdev - > dev , " failed to translate ID_OUT GPIO to IRQ \n " ) ;
return irq ;
}
err = devm_request_threaded_irq ( & pdev - > dev , irq , NULL , max3355_id_irq ,
IRQF_ONESHOT | IRQF_NO_SUSPEND |
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING ,
pdev - > name , data ) ;
if ( err < 0 ) {
dev_err ( & pdev - > dev , " failed to request ID_OUT IRQ \n " ) ;
return err ;
}
platform_set_drvdata ( pdev , data ) ;
/* Perform initial detection */
max3355_id_irq ( irq , data ) ;
return 0 ;
}
2024-02-25 18:54:53 +03:00
static void max3355_remove ( struct platform_device * pdev )
2015-12-19 02:17:41 +03:00
{
struct max3355_data * data = platform_get_drvdata ( pdev ) ;
gpiod_set_value_cansleep ( data - > shdn_gpiod , 0 ) ;
}
static const struct of_device_id max3355_match_table [ ] = {
{ . compatible = " maxim,max3355 " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , max3355_match_table ) ;
static struct platform_driver max3355_driver = {
. probe = max3355_probe ,
2024-02-25 18:54:53 +03:00
. remove_new = max3355_remove ,
2015-12-19 02:17:41 +03:00
. driver = {
. name = " extcon-max3355 " ,
. of_match_table = max3355_match_table ,
} ,
} ;
module_platform_driver ( max3355_driver ) ;
MODULE_AUTHOR ( " Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> " ) ;
MODULE_DESCRIPTION ( " Maxim MAX3355 extcon driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;