2011-10-06 11:26:35 -07:00
/*
* Synopsys DesignWare I2C adapter driver ( master only ) .
*
* Based on the TI DAVINCI I2C adapter driver .
*
* Copyright ( C ) 2006 Texas Instruments .
* Copyright ( C ) 2007 MontaVista Software Inc .
* Copyright ( C ) 2009 Provigent Ltd .
2016-06-15 18:05:07 +03:00
* Copyright ( C ) 2011 , 2015 , 2016 Intel Corporation .
2011-10-06 11:26:35 -07:00
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
*/
2016-06-15 18:05:07 +03:00
# include <linux/acpi.h>
2011-10-06 11:26:35 -07:00
# include <linux/delay.h>
# include <linux/err.h>
2016-06-15 18:05:07 +03:00
# include <linux/errno.h>
# include <linux/i2c.h>
2011-10-06 11:26:35 -07:00
# include <linux/interrupt.h>
# include <linux/io.h>
2016-06-15 18:05:07 +03:00
# include <linux/kernel.h>
# include <linux/module.h>
2011-10-06 11:26:35 -07:00
# include <linux/pci.h>
2011-10-06 11:26:36 -07:00
# include <linux/pm_runtime.h>
2016-06-15 18:05:07 +03:00
# include <linux/sched.h>
# include <linux/slab.h>
2011-10-06 11:26:35 -07:00
# include "i2c-designware-core.h"
# define DRIVER_NAME "i2c-designware-pci"
enum dw_pci_ctl_id_t {
2016-06-15 18:05:05 +03:00
medfield ,
2016-06-15 18:05:06 +03:00
merrifield ,
2014-02-19 16:10:29 +02:00
baytrail ,
2014-05-15 17:37:24 +03:00
haswell ,
2011-10-06 11:26:35 -07:00
} ;
2014-03-11 19:33:45 +08:00
struct dw_scl_sda_cfg {
u32 ss_hcnt ;
u32 fs_hcnt ;
u32 ss_lcnt ;
u32 fs_lcnt ;
u32 sda_hold ;
} ;
2011-10-06 11:26:35 -07:00
struct dw_pci_controller {
u32 bus_num ;
u32 bus_cfg ;
u32 tx_fifo_depth ;
u32 rx_fifo_depth ;
u32 clk_khz ;
2014-03-07 22:12:50 +08:00
u32 functionality ;
2014-03-11 19:33:45 +08:00
struct dw_scl_sda_cfg * scl_sda_cfg ;
2016-06-15 18:05:05 +03:00
int ( * setup ) ( struct pci_dev * pdev , struct dw_pci_controller * c ) ;
2011-10-06 11:26:35 -07:00
} ;
# define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
DW_IC_CON_SLAVE_DISABLE | \
DW_IC_CON_RESTART_EN )
2014-03-07 22:12:50 +08:00
# define DW_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
I2C_FUNC_SMBUS_BYTE | \
I2C_FUNC_SMBUS_BYTE_DATA | \
I2C_FUNC_SMBUS_WORD_DATA | \
I2C_FUNC_SMBUS_I2C_BLOCK )
2016-06-15 18:05:06 +03:00
/* Merrifield HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg mrfld_config = {
. ss_hcnt = 0x2f8 ,
. fs_hcnt = 0x87 ,
. ss_lcnt = 0x37b ,
. fs_lcnt = 0x10a ,
} ;
2014-03-11 19:33:45 +08:00
/* BayTrail HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg byt_config = {
. ss_hcnt = 0x200 ,
. fs_hcnt = 0x55 ,
. ss_lcnt = 0x200 ,
. fs_lcnt = 0x99 ,
. sda_hold = 0x6 ,
} ;
2014-05-15 17:37:24 +03:00
/* Haswell HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg hsw_config = {
. ss_hcnt = 0x01b0 ,
. fs_hcnt = 0x48 ,
. ss_lcnt = 0x01fb ,
. fs_lcnt = 0xa0 ,
. sda_hold = 0x9 ,
} ;
2016-06-15 18:05:05 +03:00
static int mfld_setup ( struct pci_dev * pdev , struct dw_pci_controller * c )
{
switch ( pdev - > device ) {
case 0x0817 :
c - > bus_cfg & = ~ DW_IC_CON_SPEED_MASK ;
c - > bus_cfg | = DW_IC_CON_SPEED_STD ;
case 0x0818 :
case 0x0819 :
c - > bus_num = pdev - > device - 0x817 + 3 ;
return 0 ;
case 0x082C :
case 0x082D :
case 0x082E :
c - > bus_num = pdev - > device - 0x82C + 0 ;
return 0 ;
}
return - ENODEV ;
}
2016-06-15 18:05:06 +03:00
static int mrfld_setup ( struct pci_dev * pdev , struct dw_pci_controller * c )
{
/*
2016-06-20 11:58:09 +03:00
* On Intel Merrifield the user visible i2c busses are enumerated
* [ 1. .7 ] . So , we add 1 to shift the default range . Besides that the
* first PCI slot provides 4 functions , that ' s why we have to add 0 to
* the first slot and 4 to the next one .
2016-06-15 18:05:06 +03:00
*/
switch ( PCI_SLOT ( pdev - > devfn ) ) {
case 8 :
c - > bus_num = PCI_FUNC ( pdev - > devfn ) + 0 + 1 ;
return 0 ;
case 9 :
c - > bus_num = PCI_FUNC ( pdev - > devfn ) + 4 + 1 ;
return 0 ;
}
return - ENODEV ;
}
2015-02-06 13:47:02 +02:00
static struct dw_pci_controller dw_pci_controllers [ ] = {
2016-06-15 18:05:05 +03:00
[ medfield ] = {
. bus_num = - 1 ,
2011-10-06 11:26:35 -07:00
. bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST ,
. tx_fifo_depth = 32 ,
. rx_fifo_depth = 32 ,
. clk_khz = 25000 ,
2016-06-15 18:05:05 +03:00
. setup = mfld_setup ,
2011-10-06 11:26:35 -07:00
} ,
2016-06-15 18:05:06 +03:00
[ merrifield ] = {
. bus_num = - 1 ,
. bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST ,
. tx_fifo_depth = 64 ,
. rx_fifo_depth = 64 ,
. scl_sda_cfg = & mrfld_config ,
. setup = mrfld_setup ,
} ,
2014-02-19 16:10:29 +02:00
[ baytrail ] = {
. bus_num = - 1 ,
. bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST ,
. tx_fifo_depth = 32 ,
. rx_fifo_depth = 32 ,
2014-03-07 22:12:50 +08:00
. functionality = I2C_FUNC_10BIT_ADDR ,
2014-03-11 19:33:45 +08:00
. scl_sda_cfg = & byt_config ,
2014-02-19 16:10:29 +02:00
} ,
2014-05-15 17:37:24 +03:00
[ haswell ] = {
. bus_num = - 1 ,
. bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST ,
. tx_fifo_depth = 32 ,
. rx_fifo_depth = 32 ,
. functionality = I2C_FUNC_10BIT_ADDR ,
. scl_sda_cfg = & hsw_config ,
} ,
2011-10-06 11:26:35 -07:00
} ;
2014-07-23 13:06:57 +01:00
2014-02-04 14:37:07 +02:00
# ifdef CONFIG_PM
2011-10-06 11:26:37 -07:00
static int i2c_dw_pci_suspend ( struct device * dev )
2011-10-06 11:26:36 -07:00
{
2015-12-27 18:45:59 +08:00
struct pci_dev * pdev = to_pci_dev ( dev ) ;
2011-10-06 11:26:36 -07:00
2014-02-04 14:37:07 +02:00
i2c_dw_disable ( pci_get_drvdata ( pdev ) ) ;
2011-10-06 11:26:36 -07:00
return 0 ;
}
2011-10-06 11:26:37 -07:00
static int i2c_dw_pci_resume ( struct device * dev )
2011-10-06 11:26:36 -07:00
{
2015-12-27 18:45:59 +08:00
struct pci_dev * pdev = to_pci_dev ( dev ) ;
2011-10-06 11:26:36 -07:00
2014-02-04 14:37:07 +02:00
return i2c_dw_init ( pci_get_drvdata ( pdev ) ) ;
2011-10-06 11:26:36 -07:00
}
2014-02-04 14:37:07 +02:00
# endif
2011-10-06 11:26:36 -07:00
2014-02-04 14:37:07 +02:00
static UNIVERSAL_DEV_PM_OPS ( i2c_dw_pm_ops , i2c_dw_pci_suspend ,
i2c_dw_pci_resume , NULL ) ;
2011-10-06 11:26:36 -07:00
2011-10-06 11:26:35 -07:00
static u32 i2c_dw_get_clk_rate_khz ( struct dw_i2c_dev * dev )
{
return dev - > controller - > clk_khz ;
}
2012-11-27 15:59:38 -05:00
static int i2c_dw_pci_probe ( struct pci_dev * pdev ,
2013-04-10 00:36:37 +00:00
const struct pci_device_id * id )
2011-10-06 11:26:35 -07:00
{
struct dw_i2c_dev * dev ;
struct i2c_adapter * adap ;
int r ;
2016-06-15 18:05:07 +03:00
struct dw_pci_controller * controller ;
2014-03-11 19:33:45 +08:00
struct dw_scl_sda_cfg * cfg ;
2011-10-06 11:26:35 -07:00
if ( id - > driver_data > = ARRAY_SIZE ( dw_pci_controllers ) ) {
2013-04-10 00:36:37 +00:00
dev_err ( & pdev - > dev , " %s: invalid driver data %ld \n " , __func__ ,
2011-10-06 11:26:35 -07:00
id - > driver_data ) ;
return - EINVAL ;
}
controller = & dw_pci_controllers [ id - > driver_data ] ;
2013-04-10 00:36:38 +00:00
r = pcim_enable_device ( pdev ) ;
2011-10-06 11:26:35 -07:00
if ( r ) {
dev_err ( & pdev - > dev , " Failed to enable I2C PCI device (%d) \n " ,
r ) ;
2013-04-10 00:36:38 +00:00
return r ;
2011-10-06 11:26:35 -07:00
}
2013-04-10 00:36:38 +00:00
r = pcim_iomap_regions ( pdev , 1 < < 0 , pci_name ( pdev ) ) ;
2011-10-06 11:26:35 -07:00
if ( r ) {
dev_err ( & pdev - > dev , " I/O memory remapping failed \n " ) ;
2013-04-10 00:36:38 +00:00
return r ;
2011-10-06 11:26:35 -07:00
}
2013-04-10 00:36:38 +00:00
dev = devm_kzalloc ( & pdev - > dev , sizeof ( struct dw_i2c_dev ) , GFP_KERNEL ) ;
if ( ! dev )
return - ENOMEM ;
2011-10-06 11:26:35 -07:00
dev - > clk = NULL ;
dev - > controller = controller ;
dev - > get_clk_rate_khz = i2c_dw_get_clk_rate_khz ;
2013-04-10 00:36:38 +00:00
dev - > base = pcim_iomap_table ( pdev ) [ 0 ] ;
dev - > dev = & pdev - > dev ;
2015-10-12 16:55:35 +03:00
dev - > irq = pdev - > irq ;
2016-06-15 18:05:05 +03:00
if ( controller - > setup ) {
r = controller - > setup ( pdev , controller ) ;
if ( r )
return r ;
}
2014-03-07 22:12:50 +08:00
dev - > functionality = controller - > functionality |
DW_DEFAULT_FUNCTIONALITY ;
2015-02-06 13:47:02 +02:00
dev - > master_cfg = controller - > bus_cfg ;
2014-03-11 19:33:45 +08:00
if ( controller - > scl_sda_cfg ) {
cfg = controller - > scl_sda_cfg ;
dev - > ss_hcnt = cfg - > ss_hcnt ;
dev - > fs_hcnt = cfg - > fs_hcnt ;
dev - > ss_lcnt = cfg - > ss_lcnt ;
dev - > fs_lcnt = cfg - > fs_lcnt ;
dev - > sda_hold_time = cfg - > sda_hold ;
}
2011-10-06 11:26:35 -07:00
pci_set_drvdata ( pdev , dev ) ;
dev - > tx_fifo_depth = controller - > tx_fifo_depth ;
dev - > rx_fifo_depth = controller - > rx_fifo_depth ;
adap = & dev - > adapter ;
adap - > owner = THIS_MODULE ;
adap - > class = 0 ;
2015-10-23 12:27:07 -07:00
ACPI_COMPANION_SET ( & adap - > dev , ACPI_COMPANION ( & pdev - > dev ) ) ;
2011-10-06 11:26:35 -07:00
adap - > nr = controller - > bus_num ;
2014-02-19 16:10:29 +02:00
2015-10-12 16:55:35 +03:00
r = i2c_dw_probe ( dev ) ;
if ( r )
2013-04-10 00:36:38 +00:00
return r ;
2011-10-06 11:26:35 -07:00
2013-04-10 00:36:42 +00:00
pm_runtime_set_autosuspend_delay ( & pdev - > dev , 1000 ) ;
pm_runtime_use_autosuspend ( & pdev - > dev ) ;
2014-02-04 14:37:07 +02:00
pm_runtime_put_autosuspend ( & pdev - > dev ) ;
2011-10-06 11:26:36 -07:00
pm_runtime_allow ( & pdev - > dev ) ;
2011-10-06 11:26:35 -07:00
return 0 ;
}
2012-11-27 15:59:38 -05:00
static void i2c_dw_pci_remove ( struct pci_dev * pdev )
2011-10-06 11:26:35 -07:00
{
struct dw_i2c_dev * dev = pci_get_drvdata ( pdev ) ;
2011-10-06 11:26:36 -07:00
i2c_dw_disable ( dev ) ;
pm_runtime_forbid ( & pdev - > dev ) ;
pm_runtime_get_noresume ( & pdev - > dev ) ;
2011-10-06 11:26:35 -07:00
i2c_del_adapter ( & dev - > adapter ) ;
}
/* work with hotplug and coldplug */
MODULE_ALIAS ( " i2c_designware-pci " ) ;
2013-12-03 08:11:20 +09:00
static const struct pci_device_id i2_designware_pci_ids [ ] = {
2011-10-06 11:26:35 -07:00
/* Medfield */
2016-06-15 18:05:05 +03:00
{ PCI_VDEVICE ( INTEL , 0x0817 ) , medfield } ,
{ PCI_VDEVICE ( INTEL , 0x0818 ) , medfield } ,
{ PCI_VDEVICE ( INTEL , 0x0819 ) , medfield } ,
{ PCI_VDEVICE ( INTEL , 0x082C ) , medfield } ,
{ PCI_VDEVICE ( INTEL , 0x082D ) , medfield } ,
{ PCI_VDEVICE ( INTEL , 0x082E ) , medfield } ,
2016-06-15 18:05:06 +03:00
/* Merrifield */
{ PCI_VDEVICE ( INTEL , 0x1195 ) , merrifield } ,
{ PCI_VDEVICE ( INTEL , 0x1196 ) , merrifield } ,
2014-02-19 16:10:29 +02:00
/* Baytrail */
{ PCI_VDEVICE ( INTEL , 0x0F41 ) , baytrail } ,
{ PCI_VDEVICE ( INTEL , 0x0F42 ) , baytrail } ,
{ PCI_VDEVICE ( INTEL , 0x0F43 ) , baytrail } ,
{ PCI_VDEVICE ( INTEL , 0x0F44 ) , baytrail } ,
{ PCI_VDEVICE ( INTEL , 0x0F45 ) , baytrail } ,
{ PCI_VDEVICE ( INTEL , 0x0F46 ) , baytrail } ,
{ PCI_VDEVICE ( INTEL , 0x0F47 ) , baytrail } ,
2014-05-15 17:37:24 +03:00
/* Haswell */
{ PCI_VDEVICE ( INTEL , 0x9c61 ) , haswell } ,
{ PCI_VDEVICE ( INTEL , 0x9c62 ) , haswell } ,
2014-07-23 13:06:57 +01:00
/* Braswell / Cherrytrail */
2015-02-06 13:47:02 +02:00
{ PCI_VDEVICE ( INTEL , 0x22C1 ) , baytrail } ,
2014-07-23 13:06:57 +01:00
{ PCI_VDEVICE ( INTEL , 0x22C2 ) , baytrail } ,
{ PCI_VDEVICE ( INTEL , 0x22C3 ) , baytrail } ,
{ PCI_VDEVICE ( INTEL , 0x22C4 ) , baytrail } ,
{ PCI_VDEVICE ( INTEL , 0x22C5 ) , baytrail } ,
{ PCI_VDEVICE ( INTEL , 0x22C6 ) , baytrail } ,
{ PCI_VDEVICE ( INTEL , 0x22C7 ) , baytrail } ,
2011-10-06 11:26:35 -07:00
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , i2_designware_pci_ids ) ;
static struct pci_driver dw_i2c_driver = {
. name = DRIVER_NAME ,
. id_table = i2_designware_pci_ids ,
. probe = i2c_dw_pci_probe ,
2012-11-27 15:59:38 -05:00
. remove = i2c_dw_pci_remove ,
2011-10-06 11:26:36 -07:00
. driver = {
. pm = & i2c_dw_pm_ops ,
} ,
2011-10-06 11:26:35 -07:00
} ;
2012-07-24 14:13:56 +02:00
module_pci_driver ( dw_i2c_driver ) ;
2011-10-06 11:26:35 -07:00
MODULE_AUTHOR ( " Baruch Siach <baruch@tkos.co.il> " ) ;
MODULE_DESCRIPTION ( " Synopsys DesignWare PCI I2C bus adapter " ) ;
MODULE_LICENSE ( " GPL " ) ;