diff mbox

[Trusty,2/2] mfd: rtsx: Add support for card reader rtl8402

Message ID 1409034650-17580-2-git-send-email-adam.lee@canonical.com
State New
Headers show

Commit Message

Adam Lee Aug. 26, 2014, 6:30 a.m. UTC
From: Micky Ching <micky_ching@realsil.com.cn>

BugLink: http://bugs.launchpad.net/bugs/1361086

rtl8402 is much like rtl8411, so just add it to rtl8411.c

Signed-off-by: Micky Ching <micky_ching@realsil.com.cn>
Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
(cherry picked from commit 56cb3cc1872923b69fdeeb00362b7da4d6cf5590)
Signed-off-by: Adam Lee <adam.lee@canonical.com>
---
 drivers/mfd/rtl8411.c  | 44 ++++++++++++++++++++++++++++++++++++++++----
 drivers/mfd/rtsx_pcr.c |  5 +++++
 drivers/mfd/rtsx_pcr.h |  1 +
 3 files changed, 46 insertions(+), 4 deletions(-)

Comments

Chris J Arges Aug. 26, 2014, 1:27 p.m. UTC | #1
Looks like clean cherry-picks to an already upstream patch.
And this is a hardware enablement patch.

Adam,
Can you please complete the SRU template found here:
https://wiki.ubuntu.com/KernelTeam/KernelUpdates
And update the information in the bug?

Pending this, I'll ACK it.

Thanks,
--chris

On 08/26/2014 01:30 AM, Adam Lee wrote:
> From: Micky Ching <micky_ching@realsil.com.cn>
> 
> BugLink: http://bugs.launchpad.net/bugs/1361086
> 
> rtl8402 is much like rtl8411, so just add it to rtl8411.c
> 
> Signed-off-by: Micky Ching <micky_ching@realsil.com.cn>
> Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com>
> Signed-off-by: Lee Jones <lee.jones@linaro.org>
> (cherry picked from commit 56cb3cc1872923b69fdeeb00362b7da4d6cf5590)
> Signed-off-by: Adam Lee <adam.lee@canonical.com>
> ---
>  drivers/mfd/rtl8411.c  | 44 ++++++++++++++++++++++++++++++++++++++++----
>  drivers/mfd/rtsx_pcr.c |  5 +++++
>  drivers/mfd/rtsx_pcr.h |  1 +
>  3 files changed, 46 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c
> index 00ecf6b..2d96552 100644
> --- a/drivers/mfd/rtl8411.c
> +++ b/drivers/mfd/rtl8411.c
> @@ -191,24 +191,25 @@ static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card)
>  			BPP_LDO_POWB, BPP_LDO_SUSPEND);
>  }
>  
> -static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
> +static int rtl8411_do_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage,
> +		int bpp_tuned18_shift, int bpp_asic_1v8)
>  {
>  	u8 mask, val;
>  	int err;
>  
> -	mask = (BPP_REG_TUNED18 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_MASK;
> +	mask = (BPP_REG_TUNED18 << bpp_tuned18_shift) | BPP_PAD_MASK;
>  	if (voltage == OUTPUT_3V3) {
>  		err = rtsx_pci_write_register(pcr,
>  				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
>  		if (err < 0)
>  			return err;
> -		val = (BPP_ASIC_3V3 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_3V3;
> +		val = (BPP_ASIC_3V3 << bpp_tuned18_shift) | BPP_PAD_3V3;
>  	} else if (voltage == OUTPUT_1V8) {
>  		err = rtsx_pci_write_register(pcr,
>  				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
>  		if (err < 0)
>  			return err;
> -		val = (BPP_ASIC_1V8 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_1V8;
> +		val = (bpp_asic_1v8 << bpp_tuned18_shift) | BPP_PAD_1V8;
>  	} else {
>  		return -EINVAL;
>  	}
> @@ -216,6 +217,18 @@ static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
>  	return rtsx_pci_write_register(pcr, LDO_CTL, mask, val);
>  }
>  
> +static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
> +{
> +	return rtl8411_do_switch_output_voltage(pcr, voltage,
> +			BPP_TUNED18_SHIFT_8411, BPP_ASIC_1V8);
> +}
> +
> +static int rtl8402_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
> +{
> +	return rtl8411_do_switch_output_voltage(pcr, voltage,
> +			BPP_TUNED18_SHIFT_8402, BPP_ASIC_2V0);
> +}
> +
>  static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr)
>  {
>  	unsigned int card_exist;
> @@ -295,6 +308,22 @@ static const struct pcr_ops rtl8411_pcr_ops = {
>  	.force_power_down = rtl8411_force_power_down,
>  };
>  
> +static const struct pcr_ops rtl8402_pcr_ops = {
> +	.fetch_vendor_settings = rtl8411_fetch_vendor_settings,
> +	.extra_init_hw = rtl8411_extra_init_hw,
> +	.optimize_phy = NULL,
> +	.turn_on_led = rtl8411_turn_on_led,
> +	.turn_off_led = rtl8411_turn_off_led,
> +	.enable_auto_blink = rtl8411_enable_auto_blink,
> +	.disable_auto_blink = rtl8411_disable_auto_blink,
> +	.card_power_on = rtl8411_card_power_on,
> +	.card_power_off = rtl8411_card_power_off,
> +	.switch_output_voltage = rtl8402_switch_output_voltage,
> +	.cd_deglitch = rtl8411_cd_deglitch,
> +	.conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
> +	.force_power_down = rtl8411_force_power_down,
> +};
> +
>  static const struct pcr_ops rtl8411b_pcr_ops = {
>  	.fetch_vendor_settings = rtl8411b_fetch_vendor_settings,
>  	.extra_init_hw = rtl8411b_extra_init_hw,
> @@ -471,3 +500,10 @@ void rtl8411b_init_params(struct rtsx_pcr *pcr)
>  	else
>  		set_pull_ctrl_tables(pcr, rtl8411b_qfn64);
>  }
> +
> +void rtl8402_init_params(struct rtsx_pcr *pcr)
> +{
> +	rtl8411_init_common_params(pcr);
> +	pcr->ops = &rtl8402_pcr_ops;
> +	set_pull_ctrl_tables(pcr, rtl8411);
> +}
> diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c
> index 705698f..d8ab56d 100644
> --- a/drivers/mfd/rtsx_pcr.c
> +++ b/drivers/mfd/rtsx_pcr.c
> @@ -57,6 +57,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = {
>  	{ PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 },
>  	{ PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 },
>  	{ PCI_DEVICE(0x10EC, 0x5287), PCI_CLASS_OTHERS << 16, 0xFF0000 },
> +	{ PCI_DEVICE(0x10EC, 0x5286), PCI_CLASS_OTHERS << 16, 0xFF0000 },
>  	{ 0, }
>  };
>  
> @@ -1061,6 +1062,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
>  	case 0x5287:
>  		rtl8411b_init_params(pcr);
>  		break;
> +
> +	case 0x5286:
> +		rtl8402_init_params(pcr);
> +		break;
>  	}
>  
>  	dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n",
> diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h
> index e9feadb..07e4c2e 100644
> --- a/drivers/mfd/rtsx_pcr.h
> +++ b/drivers/mfd/rtsx_pcr.h
> @@ -30,6 +30,7 @@
>  void rts5209_init_params(struct rtsx_pcr *pcr);
>  void rts5229_init_params(struct rtsx_pcr *pcr);
>  void rtl8411_init_params(struct rtsx_pcr *pcr);
> +void rtl8402_init_params(struct rtsx_pcr *pcr);
>  void rts5227_init_params(struct rtsx_pcr *pcr);
>  void rts5249_init_params(struct rtsx_pcr *pcr);
>  void rtl8411b_init_params(struct rtsx_pcr *pcr);
>
Tim Gardner Aug. 26, 2014, 1:45 p.m. UTC | #2
In particular I would like to see regression test results. Regressions
are more important then new features. So, some testing on an rtl8411
would be nice.

rtg

On 08/26/2014 07:27 AM, Chris J Arges wrote:
> Looks like clean cherry-picks to an already upstream patch.
> And this is a hardware enablement patch.
> 
> Adam,
> Can you please complete the SRU template found here:
> https://wiki.ubuntu.com/KernelTeam/KernelUpdates
> And update the information in the bug?
> 
> Pending this, I'll ACK it.
> 
> Thanks,
> --chris
> 
> On 08/26/2014 01:30 AM, Adam Lee wrote:
>> From: Micky Ching <micky_ching@realsil.com.cn>
>>
>> BugLink: http://bugs.launchpad.net/bugs/1361086
>>
>> rtl8402 is much like rtl8411, so just add it to rtl8411.c
>>
>> Signed-off-by: Micky Ching <micky_ching@realsil.com.cn>
>> Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com>
>> Signed-off-by: Lee Jones <lee.jones@linaro.org>
>> (cherry picked from commit 56cb3cc1872923b69fdeeb00362b7da4d6cf5590)
>> Signed-off-by: Adam Lee <adam.lee@canonical.com>
>> ---
>>  drivers/mfd/rtl8411.c  | 44 ++++++++++++++++++++++++++++++++++++++++----
>>  drivers/mfd/rtsx_pcr.c |  5 +++++
>>  drivers/mfd/rtsx_pcr.h |  1 +
>>  3 files changed, 46 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c
>> index 00ecf6b..2d96552 100644
>> --- a/drivers/mfd/rtl8411.c
>> +++ b/drivers/mfd/rtl8411.c
>> @@ -191,24 +191,25 @@ static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card)
>>  			BPP_LDO_POWB, BPP_LDO_SUSPEND);
>>  }
>>  
>> -static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
>> +static int rtl8411_do_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage,
>> +		int bpp_tuned18_shift, int bpp_asic_1v8)
>>  {
>>  	u8 mask, val;
>>  	int err;
>>  
>> -	mask = (BPP_REG_TUNED18 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_MASK;
>> +	mask = (BPP_REG_TUNED18 << bpp_tuned18_shift) | BPP_PAD_MASK;
>>  	if (voltage == OUTPUT_3V3) {
>>  		err = rtsx_pci_write_register(pcr,
>>  				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
>>  		if (err < 0)
>>  			return err;
>> -		val = (BPP_ASIC_3V3 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_3V3;
>> +		val = (BPP_ASIC_3V3 << bpp_tuned18_shift) | BPP_PAD_3V3;
>>  	} else if (voltage == OUTPUT_1V8) {
>>  		err = rtsx_pci_write_register(pcr,
>>  				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
>>  		if (err < 0)
>>  			return err;
>> -		val = (BPP_ASIC_1V8 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_1V8;
>> +		val = (bpp_asic_1v8 << bpp_tuned18_shift) | BPP_PAD_1V8;
>>  	} else {
>>  		return -EINVAL;
>>  	}
>> @@ -216,6 +217,18 @@ static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
>>  	return rtsx_pci_write_register(pcr, LDO_CTL, mask, val);
>>  }
>>  
>> +static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
>> +{
>> +	return rtl8411_do_switch_output_voltage(pcr, voltage,
>> +			BPP_TUNED18_SHIFT_8411, BPP_ASIC_1V8);
>> +}
>> +
>> +static int rtl8402_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
>> +{
>> +	return rtl8411_do_switch_output_voltage(pcr, voltage,
>> +			BPP_TUNED18_SHIFT_8402, BPP_ASIC_2V0);
>> +}
>> +
>>  static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr)
>>  {
>>  	unsigned int card_exist;
>> @@ -295,6 +308,22 @@ static const struct pcr_ops rtl8411_pcr_ops = {
>>  	.force_power_down = rtl8411_force_power_down,
>>  };
>>  
>> +static const struct pcr_ops rtl8402_pcr_ops = {
>> +	.fetch_vendor_settings = rtl8411_fetch_vendor_settings,
>> +	.extra_init_hw = rtl8411_extra_init_hw,
>> +	.optimize_phy = NULL,
>> +	.turn_on_led = rtl8411_turn_on_led,
>> +	.turn_off_led = rtl8411_turn_off_led,
>> +	.enable_auto_blink = rtl8411_enable_auto_blink,
>> +	.disable_auto_blink = rtl8411_disable_auto_blink,
>> +	.card_power_on = rtl8411_card_power_on,
>> +	.card_power_off = rtl8411_card_power_off,
>> +	.switch_output_voltage = rtl8402_switch_output_voltage,
>> +	.cd_deglitch = rtl8411_cd_deglitch,
>> +	.conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
>> +	.force_power_down = rtl8411_force_power_down,
>> +};
>> +
>>  static const struct pcr_ops rtl8411b_pcr_ops = {
>>  	.fetch_vendor_settings = rtl8411b_fetch_vendor_settings,
>>  	.extra_init_hw = rtl8411b_extra_init_hw,
>> @@ -471,3 +500,10 @@ void rtl8411b_init_params(struct rtsx_pcr *pcr)
>>  	else
>>  		set_pull_ctrl_tables(pcr, rtl8411b_qfn64);
>>  }
>> +
>> +void rtl8402_init_params(struct rtsx_pcr *pcr)
>> +{
>> +	rtl8411_init_common_params(pcr);
>> +	pcr->ops = &rtl8402_pcr_ops;
>> +	set_pull_ctrl_tables(pcr, rtl8411);
>> +}
>> diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c
>> index 705698f..d8ab56d 100644
>> --- a/drivers/mfd/rtsx_pcr.c
>> +++ b/drivers/mfd/rtsx_pcr.c
>> @@ -57,6 +57,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = {
>>  	{ PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 },
>>  	{ PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 },
>>  	{ PCI_DEVICE(0x10EC, 0x5287), PCI_CLASS_OTHERS << 16, 0xFF0000 },
>> +	{ PCI_DEVICE(0x10EC, 0x5286), PCI_CLASS_OTHERS << 16, 0xFF0000 },
>>  	{ 0, }
>>  };
>>  
>> @@ -1061,6 +1062,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
>>  	case 0x5287:
>>  		rtl8411b_init_params(pcr);
>>  		break;
>> +
>> +	case 0x5286:
>> +		rtl8402_init_params(pcr);
>> +		break;
>>  	}
>>  
>>  	dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n",
>> diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h
>> index e9feadb..07e4c2e 100644
>> --- a/drivers/mfd/rtsx_pcr.h
>> +++ b/drivers/mfd/rtsx_pcr.h
>> @@ -30,6 +30,7 @@
>>  void rts5209_init_params(struct rtsx_pcr *pcr);
>>  void rts5229_init_params(struct rtsx_pcr *pcr);
>>  void rtl8411_init_params(struct rtsx_pcr *pcr);
>> +void rtl8402_init_params(struct rtsx_pcr *pcr);
>>  void rts5227_init_params(struct rtsx_pcr *pcr);
>>  void rts5249_init_params(struct rtsx_pcr *pcr);
>>  void rtl8411b_init_params(struct rtsx_pcr *pcr);
>>
>
Adam Lee Aug. 27, 2014, 5:49 a.m. UTC | #3
On Tue, Aug 26, 2014 at 07:45:19AM -0600, Tim Gardner wrote:
> In particular I would like to see regression test results. Regressions
> are more important then new features. So, some testing on an rtl8411
> would be nice.
> 
> rtg
> 
> On 08/26/2014 07:27 AM, Chris J Arges wrote:
> > Looks like clean cherry-picks to an already upstream patch.
> > And this is a hardware enablement patch.
> > 
> > Adam,
> > Can you please complete the SRU template found here:
> > https://wiki.ubuntu.com/KernelTeam/KernelUpdates
> > And update the information in the bug?
> > 
> > Pending this, I'll ACK it.
> > 
> > Thanks,
> > --chris

Tim and Chris,

We have tested and delivered this fix by dkms in OEM projects, works
well, but we haven't done regression tests on RTL8411 because don't have
that module in house. Please judge, thanks.

Here is the SRU Justification, which is also pasted in bug description:

Impact: Realtek RTL8402 [ff00:5286], which is widely used by PC vendors, won't work without this fix.
Fix: two patches below coming from upstream, clean cherry-picks.
Testcase: we have already tested and delivered the fix by dkms in OEM projects, works well.
Andy Whitcroft Aug. 27, 2014, 10:56 a.m. UTC | #4
On Wed, Aug 27, 2014 at 01:49:19PM +0800, Adam Lee wrote:
> On Tue, Aug 26, 2014 at 07:45:19AM -0600, Tim Gardner wrote:
> > In particular I would like to see regression test results. Regressions
> > are more important then new features. So, some testing on an rtl8411
> > would be nice.
> > 
> > rtg
> > 
> > On 08/26/2014 07:27 AM, Chris J Arges wrote:
> > > Looks like clean cherry-picks to an already upstream patch.
> > > And this is a hardware enablement patch.
> > > 
> > > Adam,
> > > Can you please complete the SRU template found here:
> > > https://wiki.ubuntu.com/KernelTeam/KernelUpdates
> > > And update the information in the bug?
> > > 
> > > Pending this, I'll ACK it.
> > > 
> > > Thanks,
> > > --chris
> 
> Tim and Chris,
> 
> We have tested and delivered this fix by dkms in OEM projects, works
> well, but we haven't done regression tests on RTL8411 because don't have
> that module in house. Please judge, thanks.
> 
> Here is the SRU Justification, which is also pasted in bug description:
> 
> Impact: Realtek RTL8402 [ff00:5286], which is widely used by PC vendors, won't work without this fix.
> Fix: two patches below coming from upstream, clean cherry-picks.
> Testcase: we have already tested and delivered the fix by dkms in OEM projects, works well.

These two were both merged to mainline in v3.14-rc1, so they are in the
Utopic kernel as well.  I wonder if we have had any bug reports on
RTL8411 kit, I wonder if launchpad can help us there.

-apw
diff mbox

Patch

diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c
index 00ecf6b..2d96552 100644
--- a/drivers/mfd/rtl8411.c
+++ b/drivers/mfd/rtl8411.c
@@ -191,24 +191,25 @@  static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card)
 			BPP_LDO_POWB, BPP_LDO_SUSPEND);
 }
 
-static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+static int rtl8411_do_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage,
+		int bpp_tuned18_shift, int bpp_asic_1v8)
 {
 	u8 mask, val;
 	int err;
 
-	mask = (BPP_REG_TUNED18 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_MASK;
+	mask = (BPP_REG_TUNED18 << bpp_tuned18_shift) | BPP_PAD_MASK;
 	if (voltage == OUTPUT_3V3) {
 		err = rtsx_pci_write_register(pcr,
 				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
 		if (err < 0)
 			return err;
-		val = (BPP_ASIC_3V3 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_3V3;
+		val = (BPP_ASIC_3V3 << bpp_tuned18_shift) | BPP_PAD_3V3;
 	} else if (voltage == OUTPUT_1V8) {
 		err = rtsx_pci_write_register(pcr,
 				SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
 		if (err < 0)
 			return err;
-		val = (BPP_ASIC_1V8 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_1V8;
+		val = (bpp_asic_1v8 << bpp_tuned18_shift) | BPP_PAD_1V8;
 	} else {
 		return -EINVAL;
 	}
@@ -216,6 +217,18 @@  static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
 	return rtsx_pci_write_register(pcr, LDO_CTL, mask, val);
 }
 
+static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+	return rtl8411_do_switch_output_voltage(pcr, voltage,
+			BPP_TUNED18_SHIFT_8411, BPP_ASIC_1V8);
+}
+
+static int rtl8402_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
+{
+	return rtl8411_do_switch_output_voltage(pcr, voltage,
+			BPP_TUNED18_SHIFT_8402, BPP_ASIC_2V0);
+}
+
 static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr)
 {
 	unsigned int card_exist;
@@ -295,6 +308,22 @@  static const struct pcr_ops rtl8411_pcr_ops = {
 	.force_power_down = rtl8411_force_power_down,
 };
 
+static const struct pcr_ops rtl8402_pcr_ops = {
+	.fetch_vendor_settings = rtl8411_fetch_vendor_settings,
+	.extra_init_hw = rtl8411_extra_init_hw,
+	.optimize_phy = NULL,
+	.turn_on_led = rtl8411_turn_on_led,
+	.turn_off_led = rtl8411_turn_off_led,
+	.enable_auto_blink = rtl8411_enable_auto_blink,
+	.disable_auto_blink = rtl8411_disable_auto_blink,
+	.card_power_on = rtl8411_card_power_on,
+	.card_power_off = rtl8411_card_power_off,
+	.switch_output_voltage = rtl8402_switch_output_voltage,
+	.cd_deglitch = rtl8411_cd_deglitch,
+	.conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
+	.force_power_down = rtl8411_force_power_down,
+};
+
 static const struct pcr_ops rtl8411b_pcr_ops = {
 	.fetch_vendor_settings = rtl8411b_fetch_vendor_settings,
 	.extra_init_hw = rtl8411b_extra_init_hw,
@@ -471,3 +500,10 @@  void rtl8411b_init_params(struct rtsx_pcr *pcr)
 	else
 		set_pull_ctrl_tables(pcr, rtl8411b_qfn64);
 }
+
+void rtl8402_init_params(struct rtsx_pcr *pcr)
+{
+	rtl8411_init_common_params(pcr);
+	pcr->ops = &rtl8402_pcr_ops;
+	set_pull_ctrl_tables(pcr, rtl8411);
+}
diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c
index 705698f..d8ab56d 100644
--- a/drivers/mfd/rtsx_pcr.c
+++ b/drivers/mfd/rtsx_pcr.c
@@ -57,6 +57,7 @@  static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = {
 	{ PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 },
 	{ PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 },
 	{ PCI_DEVICE(0x10EC, 0x5287), PCI_CLASS_OTHERS << 16, 0xFF0000 },
+	{ PCI_DEVICE(0x10EC, 0x5286), PCI_CLASS_OTHERS << 16, 0xFF0000 },
 	{ 0, }
 };
 
@@ -1061,6 +1062,10 @@  static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
 	case 0x5287:
 		rtl8411b_init_params(pcr);
 		break;
+
+	case 0x5286:
+		rtl8402_init_params(pcr);
+		break;
 	}
 
 	dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n",
diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h
index e9feadb..07e4c2e 100644
--- a/drivers/mfd/rtsx_pcr.h
+++ b/drivers/mfd/rtsx_pcr.h
@@ -30,6 +30,7 @@ 
 void rts5209_init_params(struct rtsx_pcr *pcr);
 void rts5229_init_params(struct rtsx_pcr *pcr);
 void rtl8411_init_params(struct rtsx_pcr *pcr);
+void rtl8402_init_params(struct rtsx_pcr *pcr);
 void rts5227_init_params(struct rtsx_pcr *pcr);
 void rts5249_init_params(struct rtsx_pcr *pcr);
 void rtl8411b_init_params(struct rtsx_pcr *pcr);