2018-08-10 13:26:49 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
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
*/
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>
2023-05-18 11:11:50 -05:00
# include <linux/power_supply.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"
2022-01-05 16:19:35 +02:00
# include "i2c-ccgx-ucsi.h"
2011-10-06 11:26:35 -07:00
# 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 ,
2017-02-10 11:27:58 +01:00
cherrytrail ,
2014-05-15 17:37:24 +03:00
haswell ,
2019-08-15 17:29:44 +03:00
elkhartlake ,
2021-03-31 19:37:30 +05:30
navi_amd ,
2011-10-06 11:26:35 -07:00
} ;
2021-12-15 17:12:02 +02:00
/*
* This is a legacy structure to describe the hardware counters
* to configure signal timings on the bus . For Device Tree platforms
* one should use the respective properties and for ACPI there is
* a set of ACPI methods that provide these counters . No new
* platform should use this structure .
*/
2014-03-11 19:33:45 +08:00
struct dw_scl_sda_cfg {
2021-12-15 17:12:01 +02:00
u16 ss_hcnt ;
u16 fs_hcnt ;
u16 ss_lcnt ;
u16 fs_lcnt ;
2014-03-11 19:33:45 +08:00
u32 sda_hold ;
} ;
2011-10-06 11:26:35 -07:00
struct dw_pci_controller {
u32 bus_num ;
2017-02-10 11:27:58 +01:00
u32 flags ;
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 ) ;
2020-05-19 15:50:37 +03:00
u32 ( * get_clk_rate_khz ) ( struct dw_i2c_dev * dev ) ;
2011-10-06 11:26:35 -07:00
} ;
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 ,
} ;
2021-03-31 19:37:30 +05:30
/* NAVI-AMD HCNT/LCNT/SDA hold time */
static struct dw_scl_sda_cfg navi_amd_config = {
. ss_hcnt = 0x1ae ,
. ss_lcnt = 0x23a ,
. sda_hold = 0x9 ,
} ;
2020-05-19 15:50:37 +03:00
static u32 mfld_get_clk_rate_khz ( struct dw_i2c_dev * dev )
{
return 25000 ;
}
2016-06-15 18:05:05 +03:00
static int mfld_setup ( struct pci_dev * pdev , struct dw_pci_controller * c )
{
2020-04-25 16:44:46 +03:00
struct dw_i2c_dev * dev = dev_get_drvdata ( & pdev - > dev ) ;
2016-06-15 18:05:05 +03:00
switch ( pdev - > device ) {
case 0x0817 :
2020-04-25 16:44:46 +03:00
dev - > timings . bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ ;
2020-07-21 18:05:10 -05:00
fallthrough ;
2016-06-15 18:05:05 +03:00
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 )
{
/*
2020-03-19 17:30:12 +02:00
* On Intel Merrifield the user visible i2c buses are enumerated
2016-06-20 11:58:09 +03:00
* [ 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 ;
}
2020-05-19 15:50:37 +03:00
static u32 ehl_get_clk_rate_khz ( struct dw_i2c_dev * dev )
{
return 100000 ;
}
2022-09-29 12:42:14 +03:00
static u32 navi_amd_get_clk_rate_khz ( struct dw_i2c_dev * dev )
{
return 100000 ;
}
static int navi_amd_setup ( struct pci_dev * pdev , struct dw_pci_controller * c )
{
struct dw_i2c_dev * dev = dev_get_drvdata ( & pdev - > dev ) ;
2024-02-13 14:48:42 +02:00
dev - > flags | = MODEL_AMD_NAVI_GPU | ACCESS_POLLING ;
2022-09-29 12:42:14 +03:00
dev - > timings . bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ ;
return 0 ;
}
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 ,
. setup = mfld_setup ,
2020-05-19 15:50:37 +03:00
. get_clk_rate_khz = mfld_get_clk_rate_khz ,
2011-10-06 11:26:35 -07:00
} ,
2016-06-15 18:05:06 +03:00
[ merrifield ] = {
. bus_num = - 1 ,
. scl_sda_cfg = & mrfld_config ,
. setup = mrfld_setup ,
} ,
2014-02-19 16:10:29 +02:00
[ baytrail ] = {
. bus_num = - 1 ,
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 ,
. scl_sda_cfg = & hsw_config ,
} ,
2017-02-10 11:27:58 +01:00
[ cherrytrail ] = {
. bus_num = - 1 ,
. scl_sda_cfg = & byt_config ,
} ,
2019-08-15 17:29:44 +03:00
[ elkhartlake ] = {
. bus_num = - 1 ,
2020-05-19 15:50:37 +03:00
. get_clk_rate_khz = ehl_get_clk_rate_khz ,
2019-08-15 17:29:44 +03:00
} ,
2021-03-31 19:37:30 +05:30
[ navi_amd ] = {
. bus_num = - 1 ,
. scl_sda_cfg = & navi_amd_config ,
. setup = navi_amd_setup ,
. get_clk_rate_khz = navi_amd_get_clk_rate_khz ,
} ,
2011-10-06 11:26:35 -07:00
} ;
2014-07-23 13:06:57 +01:00
2022-02-23 14:48:38 +01:00
static int __maybe_unused i2c_dw_pci_runtime_suspend ( struct device * dev )
{
struct dw_i2c_dev * i_dev = dev_get_drvdata ( dev ) ;
i_dev - > disable ( i_dev ) ;
return 0 ;
}
2021-12-15 17:12:04 +02:00
static int __maybe_unused i2c_dw_pci_suspend ( struct device * dev )
2011-10-06 11:26:36 -07:00
{
2019-07-23 19:11:10 +08:00
struct dw_i2c_dev * i_dev = dev_get_drvdata ( dev ) ;
2017-06-14 11:43:23 +01:00
2022-02-23 14:48:39 +01:00
i2c_mark_adapter_suspended ( & i_dev - > adapter ) ;
2011-10-06 11:26:36 -07:00
2022-02-23 14:48:38 +01:00
return i2c_dw_pci_runtime_suspend ( dev ) ;
}
static int __maybe_unused i2c_dw_pci_runtime_resume ( struct device * dev )
{
struct dw_i2c_dev * i_dev = dev_get_drvdata ( dev ) ;
return i_dev - > init ( i_dev ) ;
2011-10-06 11:26:36 -07:00
}
2021-12-15 17:12:04 +02:00
static int __maybe_unused i2c_dw_pci_resume ( struct device * dev )
2011-10-06 11:26:36 -07:00
{
2019-07-23 19:11:10 +08:00
struct dw_i2c_dev * i_dev = dev_get_drvdata ( dev ) ;
2019-02-22 14:08:40 +01:00
int ret ;
2011-10-06 11:26:36 -07:00
2022-02-23 14:48:38 +01:00
ret = i2c_dw_pci_runtime_resume ( dev ) ;
2022-02-23 14:48:39 +01:00
i2c_mark_adapter_resumed ( & i_dev - > adapter ) ;
2019-02-22 14:08:40 +01:00
return ret ;
2011-10-06 11:26:36 -07:00
}
2022-02-23 14:48:38 +01:00
static const struct dev_pm_ops i2c_dw_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS ( i2c_dw_pci_suspend , i2c_dw_pci_resume )
SET_RUNTIME_PM_OPS ( i2c_dw_pci_runtime_suspend , i2c_dw_pci_runtime_resume , NULL )
} ;
2011-10-06 11:26:36 -07:00
2023-05-18 11:11:50 -05:00
static const struct property_entry dgpu_properties [ ] = {
/* USB-C doesn't power the system */
PROPERTY_ENTRY_U8 ( " scope " , POWER_SUPPLY_SCOPE_DEVICE ) ,
{ }
} ;
static const struct software_node dgpu_node = {
. properties = dgpu_properties ,
} ;
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 ;
2022-09-07 21:39:20 +05:30
struct i2c_timings * t ;
2011-10-06 11:26:35 -07:00
2021-12-15 17:12:05 +02:00
if ( id - > driver_data > = ARRAY_SIZE ( dw_pci_controllers ) )
return dev_err_probe ( & pdev - > dev , - EINVAL ,
" Invalid driver data %ld \n " ,
id - > driver_data ) ;
2011-10-06 11:26:35 -07:00
controller = & dw_pci_controllers [ id - > driver_data ] ;
2013-04-10 00:36:38 +00:00
r = pcim_enable_device ( pdev ) ;
2021-12-15 17:12:05 +02:00
if ( r )
return dev_err_probe ( & pdev - > dev , r ,
" Failed to enable I2C PCI device \n " ) ;
2011-10-06 11:26:35 -07:00
2019-08-15 17:29:43 +03:00
pci_set_master ( pdev ) ;
2013-04-10 00:36:38 +00:00
r = pcim_iomap_regions ( pdev , 1 < < 0 , pci_name ( pdev ) ) ;
2021-12-15 17:12:05 +02:00
if ( r )
return dev_err_probe ( & pdev - > dev , r ,
" I/O memory remapping failed \n " ) ;
2011-10-06 11:26:35 -07:00
2022-09-29 12:42:15 +03:00
dev = devm_kzalloc ( & pdev - > dev , sizeof ( * dev ) , GFP_KERNEL ) ;
2013-04-10 00:36:38 +00:00
if ( ! dev )
return - ENOMEM ;
2011-10-06 11:26:35 -07:00
2019-08-15 17:29:43 +03:00
r = pci_alloc_irq_vectors ( pdev , 1 , 1 , PCI_IRQ_ALL_TYPES ) ;
if ( r < 0 )
return r ;
2020-05-19 15:50:37 +03:00
dev - > get_clk_rate_khz = controller - > get_clk_rate_khz ;
2013-04-10 00:36:38 +00:00
dev - > base = pcim_iomap_table ( pdev ) [ 0 ] ;
dev - > dev = & pdev - > dev ;
2019-08-15 17:29:43 +03:00
dev - > irq = pci_irq_vector ( pdev , 0 ) ;
2017-02-10 11:27:58 +01:00
dev - > flags | = controller - > flags ;
2016-06-15 18:05:05 +03:00
2022-09-07 21:39:20 +05:30
t = & dev - > timings ;
i2c_parse_fw_timings ( & pdev - > dev , t , false ) ;
2020-04-25 16:44:46 +03:00
pci_set_drvdata ( pdev , dev ) ;
2016-06-15 18:05:05 +03:00
if ( controller - > setup ) {
r = controller - > setup ( pdev , controller ) ;
2019-08-15 17:29:43 +03:00
if ( r ) {
pci_free_irq_vectors ( pdev ) ;
2016-06-15 18:05:05 +03:00
return r ;
2019-08-15 17:29:43 +03:00
}
2016-06-15 18:05:05 +03:00
}
2020-06-23 12:15:01 +03:00
i2c_dw_adjust_bus_speed ( dev ) ;
2020-05-19 15:50:42 +03:00
if ( has_acpi_companion ( & pdev - > dev ) )
i2c_dw_acpi_configure ( & pdev - > dev ) ;
r = i2c_dw_validate_speed ( dev ) ;
if ( r ) {
pci_free_irq_vectors ( pdev ) ;
return r ;
}
2020-04-25 16:44:48 +03:00
i2c_dw_configure ( dev ) ;
2014-03-07 22:12:50 +08:00
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
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
2020-04-25 16:44:48 +03:00
r = i2c_dw_probe ( dev ) ;
2019-08-15 17:29:43 +03:00
if ( r ) {
pci_free_irq_vectors ( pdev ) ;
2013-04-10 00:36:38 +00:00
return r ;
2019-08-15 17:29:43 +03:00
}
2011-10-06 11:26:35 -07:00
2021-03-31 19:37:30 +05:30
if ( ( dev - > flags & MODEL_MASK ) = = MODEL_AMD_NAVI_GPU ) {
2023-05-18 11:11:50 -05:00
dev - > slave = i2c_new_ccgx_ucsi ( & dev - > adapter , dev - > irq , & dgpu_node ) ;
2022-01-05 16:19:35 +02:00
if ( IS_ERR ( dev - > slave ) )
return dev_err_probe ( dev - > dev , PTR_ERR ( dev - > slave ) ,
" register UCSI failed \n " ) ;
2021-03-31 19:37:30 +05:30
}
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 ) ;
2017-06-14 11:43:23 +01:00
dev - > disable ( dev ) ;
2011-10-06 11:26:36 -07:00
pm_runtime_forbid ( & pdev - > dev ) ;
pm_runtime_get_noresume ( & pdev - > dev ) ;
2011-10-06 11:26:35 -07:00
i2c_del_adapter ( & dev - > adapter ) ;
2020-02-13 17:15:03 +02:00
devm_free_irq ( & pdev - > dev , dev - > irq , dev ) ;
2019-08-15 17:29:43 +03:00
pci_free_irq_vectors ( pdev ) ;
2011-10-06 11:26:35 -07:00
}
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 */
2017-02-10 11:27:58 +01:00
{ PCI_VDEVICE ( INTEL , 0x22C1 ) , cherrytrail } ,
{ PCI_VDEVICE ( INTEL , 0x22C2 ) , cherrytrail } ,
{ PCI_VDEVICE ( INTEL , 0x22C3 ) , cherrytrail } ,
{ PCI_VDEVICE ( INTEL , 0x22C4 ) , cherrytrail } ,
{ PCI_VDEVICE ( INTEL , 0x22C5 ) , cherrytrail } ,
{ PCI_VDEVICE ( INTEL , 0x22C6 ) , cherrytrail } ,
{ PCI_VDEVICE ( INTEL , 0x22C7 ) , cherrytrail } ,
2019-08-15 17:29:44 +03:00
/* Elkhart Lake (PSE I2C) */
{ PCI_VDEVICE ( INTEL , 0x4bb9 ) , elkhartlake } ,
{ PCI_VDEVICE ( INTEL , 0x4bba ) , elkhartlake } ,
{ PCI_VDEVICE ( INTEL , 0x4bbb ) , elkhartlake } ,
{ PCI_VDEVICE ( INTEL , 0x4bbc ) , elkhartlake } ,
{ PCI_VDEVICE ( INTEL , 0x4bbd ) , elkhartlake } ,
{ PCI_VDEVICE ( INTEL , 0x4bbe ) , elkhartlake } ,
{ PCI_VDEVICE ( INTEL , 0x4bbf ) , elkhartlake } ,
{ PCI_VDEVICE ( INTEL , 0x4bc0 ) , elkhartlake } ,
2022-09-29 12:42:14 +03:00
/* AMD NAVI */
2021-03-31 19:37:30 +05:30
{ PCI_VDEVICE ( ATI , 0x7314 ) , navi_amd } ,
{ PCI_VDEVICE ( ATI , 0x73a4 ) , navi_amd } ,
{ PCI_VDEVICE ( ATI , 0x73e4 ) , navi_amd } ,
{ PCI_VDEVICE ( ATI , 0x73c4 ) , navi_amd } ,
2023-01-02 22:39:55 +05:30
{ PCI_VDEVICE ( ATI , 0x7444 ) , navi_amd } ,
{ PCI_VDEVICE ( ATI , 0x7464 ) , navi_amd } ,
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
2021-12-15 17:12:03 +02:00
/* Work with hotplug and coldplug */
MODULE_ALIAS ( " i2c_designware-pci " ) ;
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 " ) ;