2010-11-26 13:52:35 +03:00
/*
* cs5535 - mfd . c - core MFD driver for CS5535 / CS5536 southbridges
*
* The CS5535 and CS5536 has an ISA bridge on the PCI bus that is
* used for accessing GPIOs , MFGPTs , ACPI , etc . Each subdevice has
* an IO range that ' s specified in a single BAR . The BAR order is
* hardcoded in the CS553x specifications .
*
* Copyright ( c ) 2010 Andres Salomon < dilinger @ queued . net >
*
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/mfd/core.h>
# include <linux/module.h>
# include <linux/pci.h>
2011-03-22 05:19:35 +03:00
# include <asm/olpc.h>
2010-11-26 13:52:35 +03:00
# define DRV_NAME "cs5535-mfd"
enum cs5535_mfd_bars {
SMB_BAR = 0 ,
GPIO_BAR = 1 ,
MFGPT_BAR = 2 ,
PMS_BAR = 4 ,
ACPI_BAR = 5 ,
NR_BARS ,
} ;
2011-02-18 06:07:36 +03:00
static int cs5535_mfd_res_enable ( struct platform_device * pdev )
{
struct resource * res ;
res = platform_get_resource ( pdev , IORESOURCE_IO , 0 ) ;
if ( ! res ) {
dev_err ( & pdev - > dev , " can't fetch device resource info \n " ) ;
return - EIO ;
}
if ( ! request_region ( res - > start , resource_size ( res ) , DRV_NAME ) ) {
dev_err ( & pdev - > dev , " can't request region \n " ) ;
return - EIO ;
}
return 0 ;
}
static int cs5535_mfd_res_disable ( struct platform_device * pdev )
{
struct resource * res ;
res = platform_get_resource ( pdev , IORESOURCE_IO , 0 ) ;
if ( ! res ) {
dev_err ( & pdev - > dev , " can't fetch device resource info \n " ) ;
return - EIO ;
}
release_region ( res - > start , resource_size ( res ) ) ;
return 0 ;
}
2012-11-19 22:24:21 +04:00
static struct resource cs5535_mfd_resources [ NR_BARS ] ;
2010-11-26 13:52:35 +03:00
2012-11-19 22:24:21 +04:00
static struct mfd_cell cs5535_mfd_cells [ ] = {
2010-11-26 13:52:35 +03:00
{
. id = SMB_BAR ,
. name = " cs5535-smb " ,
. num_resources = 1 ,
. resources = & cs5535_mfd_resources [ SMB_BAR ] ,
} ,
{
. id = GPIO_BAR ,
. name = " cs5535-gpio " ,
. num_resources = 1 ,
. resources = & cs5535_mfd_resources [ GPIO_BAR ] ,
} ,
{
. id = MFGPT_BAR ,
. name = " cs5535-mfgpt " ,
. num_resources = 1 ,
. resources = & cs5535_mfd_resources [ MFGPT_BAR ] ,
} ,
{
. id = PMS_BAR ,
. name = " cs5535-pms " ,
. num_resources = 1 ,
. resources = & cs5535_mfd_resources [ PMS_BAR ] ,
2011-02-18 06:07:36 +03:00
. enable = cs5535_mfd_res_enable ,
. disable = cs5535_mfd_res_disable ,
2010-11-26 13:52:35 +03:00
} ,
{
. id = ACPI_BAR ,
. name = " cs5535-acpi " ,
. num_resources = 1 ,
. resources = & cs5535_mfd_resources [ ACPI_BAR ] ,
2011-02-18 06:07:36 +03:00
. enable = cs5535_mfd_res_enable ,
. disable = cs5535_mfd_res_disable ,
2010-11-26 13:52:35 +03:00
} ,
} ;
2011-03-22 05:19:35 +03:00
# ifdef CONFIG_OLPC
2012-11-19 22:23:04 +04:00
static void cs5535_clone_olpc_cells ( void )
2011-03-22 05:19:35 +03:00
{
2011-03-22 23:50:39 +03:00
const char * acpi_clones [ ] = { " olpc-xo1-pm-acpi " , " olpc-xo1-sci-acpi " } ;
2011-03-22 05:19:35 +03:00
if ( ! machine_is_olpc ( ) )
return ;
mfd_clone_cell ( " cs5535-acpi " , acpi_clones , ARRAY_SIZE ( acpi_clones ) ) ;
}
# else
static void cs5535_clone_olpc_cells ( void ) { }
# endif
2012-11-19 22:23:04 +04:00
static int cs5535_mfd_probe ( struct pci_dev * pdev ,
2010-11-26 13:52:35 +03:00
const struct pci_device_id * id )
{
int err , i ;
err = pci_enable_device ( pdev ) ;
if ( err )
return err ;
/* fill in IO range for each cell; subdrivers handle the region */
for ( i = 0 ; i < ARRAY_SIZE ( cs5535_mfd_cells ) ; i + + ) {
int bar = cs5535_mfd_cells [ i ] . id ;
struct resource * r = & cs5535_mfd_resources [ bar ] ;
r - > flags = IORESOURCE_IO ;
r - > start = pci_resource_start ( pdev , bar ) ;
r - > end = pci_resource_end ( pdev , bar ) ;
/* id is used for temporarily storing BAR; unset it now */
cs5535_mfd_cells [ i ] . id = 0 ;
}
err = mfd_add_devices ( & pdev - > dev , - 1 , cs5535_mfd_cells ,
2012-09-11 11:16:36 +04:00
ARRAY_SIZE ( cs5535_mfd_cells ) , NULL , 0 , NULL ) ;
2010-11-26 13:52:35 +03:00
if ( err ) {
dev_err ( & pdev - > dev , " MFD add devices failed: %d \n " , err ) ;
goto err_disable ;
}
2011-03-22 05:19:35 +03:00
cs5535_clone_olpc_cells ( ) ;
2010-11-26 13:52:35 +03:00
2010-12-01 00:54:39 +03:00
dev_info ( & pdev - > dev , " %zu devices registered. \n " ,
2010-11-26 13:52:35 +03:00
ARRAY_SIZE ( cs5535_mfd_cells ) ) ;
return 0 ;
err_disable :
pci_disable_device ( pdev ) ;
return err ;
}
2012-11-19 22:26:01 +04:00
static void cs5535_mfd_remove ( struct pci_dev * pdev )
2010-11-26 13:52:35 +03:00
{
mfd_remove_devices ( & pdev - > dev ) ;
pci_disable_device ( pdev ) ;
}
2013-12-03 03:15:39 +04:00
static const struct pci_device_id cs5535_mfd_pci_tbl [ ] = {
2010-11-26 13:52:35 +03:00
{ PCI_DEVICE ( PCI_VENDOR_ID_NS , PCI_DEVICE_ID_NS_CS5535_ISA ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_AMD , PCI_DEVICE_ID_AMD_CS5536_ISA ) } ,
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , cs5535_mfd_pci_tbl ) ;
mfd: Fix cs5535 section mismatch
Silence following warnings:
WARNING: drivers/mfd/cs5535-mfd.o(.data+0x20): Section mismatch in
reference from the variable cs5535_mfd_drv to the function
.devinit.text:cs5535_mfd_probe()
The variable cs5535_mfd_drv references
the function __devinit cs5535_mfd_probe()
If the reference is valid then annotate the
variable with __init* or __refdata (see linux/init.h) or name the variable:
*driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console
WARNING: drivers/mfd/cs5535-mfd.o(.data+0x28): Section mismatch in
reference from the variable cs5535_mfd_drv to the function
.devexit.text:cs5535_mfd_remove()
The variable cs5535_mfd_drv references
the function __devexit cs5535_mfd_remove()
If the reference is valid then annotate the
variable with __exit* (see linux/init.h) or name the variable:
*driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console
Rename the variable from *_drv to *_driver so
modpost ignore the OK references to __devinit/__devexit
functions.
Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com>
Acked-by: Andres Salomon <dilinger@queued.net>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
2011-12-14 00:30:04 +04:00
static struct pci_driver cs5535_mfd_driver = {
2010-11-26 13:52:35 +03:00
. name = DRV_NAME ,
. id_table = cs5535_mfd_pci_tbl ,
. probe = cs5535_mfd_probe ,
2012-11-19 22:20:24 +04:00
. remove = cs5535_mfd_remove ,
2010-11-26 13:52:35 +03:00
} ;
2012-04-03 05:09:19 +04:00
module_pci_driver ( cs5535_mfd_driver ) ;
2010-11-26 13:52:35 +03:00
MODULE_AUTHOR ( " Andres Salomon <dilinger@queued.net> " ) ;
MODULE_DESCRIPTION ( " MFD driver for CS5535/CS5536 southbridge's ISA PCI device " ) ;
MODULE_LICENSE ( " GPL " ) ;