2019-08-15 19:48:03 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* v4l2 - i2c - I2C helpers for Video4Linux2
*/
# include <linux/i2c.h>
# include <linux/module.h>
# include <media/v4l2-common.h>
# include <media/v4l2-device.h>
2019-08-15 19:48:05 +03:00
void v4l2_i2c_subdev_unregister ( struct v4l2_subdev * sd )
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
/*
* We need to unregister the i2c client
* explicitly . We cannot rely on
* i2c_del_adapter to always unregister
* clients for us , since if the i2c bus is a
* platform bus , then it is never deleted .
*
* Device tree or ACPI based devices must not
* be unregistered as they have not been
* registered by us , and would not be
* re - created by just probing the V4L2 driver .
*/
if ( client & & ! client - > dev . of_node & & ! client - > dev . fwnode )
i2c_unregister_device ( client ) ;
}
2019-08-26 17:01:25 +03:00
void v4l2_i2c_subdev_set_name ( struct v4l2_subdev * sd ,
struct i2c_client * client ,
2019-08-15 19:48:03 +03:00
const char * devname , const char * postfix )
{
if ( ! devname )
devname = client - > dev . driver - > name ;
if ( ! postfix )
postfix = " " ;
snprintf ( sd - > name , sizeof ( sd - > name ) , " %s%s %d-%04x " , devname , postfix ,
i2c_adapter_id ( client - > adapter ) , client - > addr ) ;
}
EXPORT_SYMBOL_GPL ( v4l2_i2c_subdev_set_name ) ;
void v4l2_i2c_subdev_init ( struct v4l2_subdev * sd , struct i2c_client * client ,
2019-08-26 17:01:25 +03:00
const struct v4l2_subdev_ops * ops )
2019-08-15 19:48:03 +03:00
{
v4l2_subdev_init ( sd , ops ) ;
sd - > flags | = V4L2_SUBDEV_FL_IS_I2C ;
/* the owner is the same as the i2c_client's driver owner */
sd - > owner = client - > dev . driver - > owner ;
sd - > dev = & client - > dev ;
/* i2c_client and v4l2_subdev point to one another */
v4l2_set_subdevdata ( sd , client ) ;
i2c_set_clientdata ( client , sd ) ;
v4l2_i2c_subdev_set_name ( sd , client , NULL , NULL ) ;
}
EXPORT_SYMBOL_GPL ( v4l2_i2c_subdev_init ) ;
/* Load an i2c sub-device. */
2019-08-26 17:01:25 +03:00
struct v4l2_subdev
* v4l2_i2c_new_subdev_board ( struct v4l2_device * v4l2_dev ,
struct i2c_adapter * adapter ,
struct i2c_board_info * info ,
const unsigned short * probe_addrs )
2019-08-15 19:48:03 +03:00
{
struct v4l2_subdev * sd = NULL ;
struct i2c_client * client ;
2019-08-15 19:48:06 +03:00
if ( ! v4l2_dev )
return NULL ;
2019-08-15 19:48:03 +03:00
request_module ( I2C_MODULE_PREFIX " %s " , info - > type ) ;
/* Create the i2c client */
if ( info - > addr = = 0 & & probe_addrs )
2019-12-16 18:51:43 +03:00
client = i2c_new_scanned_device ( adapter , info , probe_addrs ,
NULL ) ;
2019-08-15 19:48:03 +03:00
else
2019-12-16 18:51:43 +03:00
client = i2c_new_client_device ( adapter , info ) ;
2019-08-15 19:48:03 +03:00
2019-08-26 17:01:25 +03:00
/*
* Note : by loading the module first we are certain that c - > driver
* will be set if the driver was found . If the module was not loaded
* first , then the i2c core tries to delay - load the module for us ,
* and then c - > driver is still NULL until the module is finally
* loaded . This delay - load mechanism doesn ' t work if other drivers
* want to use the i2c device , so explicitly loading the module
* is the best alternative .
*/
2019-12-16 18:51:43 +03:00
if ( ! i2c_client_has_driver ( client ) )
2019-08-15 19:48:03 +03:00
goto error ;
/* Lock the module so we can safely get the v4l2_subdev pointer */
if ( ! try_module_get ( client - > dev . driver - > owner ) )
goto error ;
sd = i2c_get_clientdata ( client ) ;
2019-08-26 17:01:25 +03:00
/*
* Register with the v4l2_device which increases the module ' s
* use count as well .
*/
2019-08-15 19:48:03 +03:00
if ( v4l2_device_register_subdev ( v4l2_dev , sd ) )
sd = NULL ;
/* Decrease the module use count to match the first try_module_get. */
module_put ( client - > dev . driver - > owner ) ;
error :
2019-08-26 17:01:25 +03:00
/*
* If we have a client but no subdev , then something went wrong and
* we must unregister the client .
*/
2019-12-16 18:51:43 +03:00
if ( ! IS_ERR ( client ) & & ! sd )
2019-08-15 19:48:03 +03:00
i2c_unregister_device ( client ) ;
return sd ;
}
EXPORT_SYMBOL_GPL ( v4l2_i2c_new_subdev_board ) ;
struct v4l2_subdev * v4l2_i2c_new_subdev ( struct v4l2_device * v4l2_dev ,
2019-08-26 17:01:25 +03:00
struct i2c_adapter * adapter ,
const char * client_type ,
u8 addr ,
const unsigned short * probe_addrs )
2019-08-15 19:48:03 +03:00
{
struct i2c_board_info info ;
2019-08-26 17:01:25 +03:00
/*
* Setup the i2c board info with the device type and
* the device address .
*/
2019-08-15 19:48:03 +03:00
memset ( & info , 0 , sizeof ( info ) ) ;
strscpy ( info . type , client_type , sizeof ( info . type ) ) ;
info . addr = addr ;
2019-08-26 17:01:25 +03:00
return v4l2_i2c_new_subdev_board ( v4l2_dev , adapter , & info ,
probe_addrs ) ;
2019-08-15 19:48:03 +03:00
}
EXPORT_SYMBOL_GPL ( v4l2_i2c_new_subdev ) ;
/* Return i2c client address of v4l2_subdev. */
unsigned short v4l2_i2c_subdev_addr ( struct v4l2_subdev * sd )
{
struct i2c_client * client = v4l2_get_subdevdata ( sd ) ;
return client ? client - > addr : I2C_CLIENT_END ;
}
EXPORT_SYMBOL_GPL ( v4l2_i2c_subdev_addr ) ;
2019-08-26 17:01:25 +03:00
/*
* Return a list of I2C tuner addresses to probe . Use only if the tuner
* addresses are unknown .
*/
2019-08-15 19:48:03 +03:00
const unsigned short * v4l2_i2c_tuner_addrs ( enum v4l2_i2c_tuner_type type )
{
static const unsigned short radio_addrs [ ] = {
# if IS_ENABLED(CONFIG_MEDIA_TUNER_TEA5761)
0x10 ,
# endif
0x60 ,
I2C_CLIENT_END
} ;
static const unsigned short demod_addrs [ ] = {
0x42 , 0x43 , 0x4a , 0x4b ,
I2C_CLIENT_END
} ;
static const unsigned short tv_addrs [ ] = {
0x42 , 0x43 , 0x4a , 0x4b , /* tda8290 */
0x60 , 0x61 , 0x62 , 0x63 , 0x64 ,
I2C_CLIENT_END
} ;
switch ( type ) {
case ADDRS_RADIO :
return radio_addrs ;
case ADDRS_DEMOD :
return demod_addrs ;
case ADDRS_TV :
return tv_addrs ;
case ADDRS_TV_WITH_DEMOD :
return tv_addrs + 4 ;
}
return NULL ;
}
EXPORT_SYMBOL_GPL ( v4l2_i2c_tuner_addrs ) ;