2012-11-23 15:23:40 +04:00
/*
* ACPI I2C enumeration support
*
* Copyright ( C ) 2012 , Intel Corporation
* Author : Mika Westerberg < mika . westerberg @ linux . intel . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/acpi.h>
# include <linux/device.h>
# include <linux/export.h>
# include <linux/i2c.h>
# include <linux/ioport.h>
ACPI_MODULE_NAME ( " i2c " ) ;
static int acpi_i2c_add_resource ( struct acpi_resource * ares , void * data )
{
struct i2c_board_info * info = data ;
if ( ares - > type = = ACPI_RESOURCE_TYPE_SERIAL_BUS ) {
struct acpi_resource_i2c_serialbus * sb ;
sb = & ares - > data . i2c_serial_bus ;
if ( sb - > type = = ACPI_RESOURCE_SERIAL_TYPE_I2C ) {
info - > addr = sb - > slave_address ;
if ( sb - > access_mode = = ACPI_I2C_10BIT_MODE )
info - > flags | = I2C_CLIENT_TEN ;
}
} else if ( info - > irq < 0 ) {
struct resource r ;
if ( acpi_dev_resource_interrupt ( ares , 0 , & r ) )
info - > irq = r . start ;
}
/* Tell the ACPI core to skip this resource */
return 1 ;
}
static acpi_status acpi_i2c_add_device ( acpi_handle handle , u32 level ,
void * data , void * * return_value )
{
struct i2c_adapter * adapter = data ;
struct list_head resource_list ;
struct i2c_board_info info ;
struct acpi_device * adev ;
int ret ;
if ( acpi_bus_get_device ( handle , & adev ) )
return AE_OK ;
if ( acpi_bus_get_status ( adev ) | | ! adev - > status . present )
return AE_OK ;
memset ( & info , 0 , sizeof ( info ) ) ;
info . acpi_node . handle = handle ;
info . irq = - 1 ;
INIT_LIST_HEAD ( & resource_list ) ;
ret = acpi_dev_get_resources ( adev , & resource_list ,
acpi_i2c_add_resource , & info ) ;
acpi_dev_free_resource_list ( & resource_list ) ;
if ( ret < 0 | | ! info . addr )
return AE_OK ;
strlcpy ( info . type , dev_name ( & adev - > dev ) , sizeof ( info . type ) ) ;
if ( ! i2c_new_device ( adapter , & info ) ) {
dev_err ( & adapter - > dev ,
" failed to add I2C device %s from ACPI \n " ,
dev_name ( & adev - > dev ) ) ;
}
return AE_OK ;
}
/**
* acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
* @ adapter : pointer to adapter
*
* Enumerate all I2C slave devices behind this adapter by walking the ACPI
* namespace . When a device is found it will be added to the Linux device
* model and bound to the corresponding ACPI handle .
*/
void acpi_i2c_register_devices ( struct i2c_adapter * adapter )
{
acpi_handle handle ;
acpi_status status ;
2013-04-01 04:25:03 +04:00
handle = ACPI_HANDLE ( adapter - > dev . parent ) ;
2012-11-23 15:23:40 +04:00
if ( ! handle )
return ;
status = acpi_walk_namespace ( ACPI_TYPE_DEVICE , handle , 1 ,
acpi_i2c_add_device , NULL ,
adapter , NULL ) ;
if ( ACPI_FAILURE ( status ) )
dev_warn ( & adapter - > dev , " failed to enumerate I2C slaves \n " ) ;
}
EXPORT_SYMBOL_GPL ( acpi_i2c_register_devices ) ;