From e455b69ddf9b69326d0cab28d374faf3325489c9 Mon Sep 17 00:00:00 2001 From: Rui Feng Date: Wed, 29 Nov 2017 17:08:03 +0800 Subject: misc: rtsx: Move Realtek Card Reader Driver to misc Because Realtek card reader drivers are pcie and usb drivers, and they bridge mmc subsystem and memstick subsystem, they are not mfd drivers. Greg and Lee Jones had a discussion about where to put the drivers, the result is that misc is a good place for them, so I move all files to misc. If I don't move them to a right place, I can't add any patch for this driver. Signed-off-by: Rui Feng Reviewed-by: Daniel Bristot de Oliveira Acked-by: Arnd Bergmann Acked-by: Ulf Hansson Acked-by: Greg Kroah-Hartman Tested-by: Perry Yuan Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 21 - drivers/mfd/Makefile | 4 - drivers/mfd/rtl8411.c | 508 ---------------- drivers/mfd/rts5209.c | 277 --------- drivers/mfd/rts5227.c | 374 ------------ drivers/mfd/rts5229.c | 273 --------- drivers/mfd/rts5249.c | 741 ----------------------- drivers/mfd/rtsx_pcr.c | 1569 ------------------------------------------------ drivers/mfd/rtsx_pcr.h | 103 ---- drivers/mfd/rtsx_usb.c | 791 ------------------------ 10 files changed, 4661 deletions(-) delete mode 100644 drivers/mfd/rtl8411.c delete mode 100644 drivers/mfd/rts5209.c delete mode 100644 drivers/mfd/rts5227.c delete mode 100644 drivers/mfd/rts5229.c delete mode 100644 drivers/mfd/rts5249.c delete mode 100644 drivers/mfd/rtsx_pcr.c delete mode 100644 drivers/mfd/rtsx_pcr.h delete mode 100644 drivers/mfd/rtsx_usb.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1d20a800e967..1246ba1832d7 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -929,17 +929,6 @@ config MFD_RDC321X southbridge which provides access to GPIOs and Watchdog using the southbridge PCI device configuration space. -config MFD_RTSX_PCI - tristate "Realtek PCI-E card reader" - depends on PCI - select MFD_CORE - help - This supports for Realtek PCI-Express card reader including rts5209, - rts5227, rts522A, rts5229, rts5249, rts524A, rts525A, rtl8411, etc. - Realtek card reader supports access to many types of memory cards, - such as Memory Stick, Memory Stick Pro, Secure Digital and - MultiMediaCard. - config MFD_RT5033 tristate "Richtek RT5033 Power Management IC" depends on I2C @@ -953,16 +942,6 @@ config MFD_RT5033 sub-devices like charger, fuel gauge, flash LED, current source, LDO and Buck. -config MFD_RTSX_USB - tristate "Realtek USB card reader" - depends on USB - select MFD_CORE - help - Select this option to get support for Realtek USB 2.0 card readers - including RTS5129, RTS5139, RTS5179 and RTS5170. - Realtek card reader supports access to many types of memory cards, - such as Memory Stick Pro, Secure Digital and MultiMediaCard. - config MFD_RC5T583 bool "Ricoh RC5T583 Power Management system device" depends on I2C=y diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d9474ade32e6..293e223c373d 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -19,10 +19,6 @@ obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o -rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o -obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o -obj-$(CONFIG_MFD_RTSX_USB) += rtsx_usb.o - obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c deleted file mode 100644 index b3ae6592014a..000000000000 --- a/drivers/mfd/rtl8411.c +++ /dev/null @@ -1,508 +0,0 @@ -/* Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * 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, 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Author: - * Wei WANG - * Roger Tseng - */ - -#include -#include -#include -#include - -#include "rtsx_pcr.h" - -static u8 rtl8411_get_ic_version(struct rtsx_pcr *pcr) -{ - u8 val; - - rtsx_pci_read_register(pcr, SYS_VER, &val); - return val & 0x0F; -} - -static int rtl8411b_is_qfn48(struct rtsx_pcr *pcr) -{ - u8 val = 0; - - rtsx_pci_read_register(pcr, RTL8411B_PACKAGE_MODE, &val); - - if (val & 0x2) - return 1; - else - return 0; -} - -static void rtl8411_fetch_vendor_settings(struct rtsx_pcr *pcr) -{ - u32 reg1 = 0; - u8 reg3 = 0; - - rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®1); - pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg1); - - if (!rtsx_vendor_setting_valid(reg1)) - return; - - pcr->aspm_en = rtsx_reg_to_aspm(reg1); - pcr->sd30_drive_sel_1v8 = - map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg1)); - pcr->card_drive_sel &= 0x3F; - pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg1); - - rtsx_pci_read_config_byte(pcr, PCR_SETTING_REG3, ®3); - pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG3, reg3); - pcr->sd30_drive_sel_3v3 = rtl8411_reg_to_sd30_drive_sel_3v3(reg3); -} - -static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr) -{ - u32 reg = 0; - - rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); - pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); - - if (!rtsx_vendor_setting_valid(reg)) - return; - - pcr->aspm_en = rtsx_reg_to_aspm(reg); - pcr->sd30_drive_sel_1v8 = - map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg)); - pcr->sd30_drive_sel_3v3 = - map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg)); -} - -static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) -{ - rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07); -} - -static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr) -{ - rtsx_pci_init_cmd(pcr); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, - 0xFF, pcr->sd30_drive_sel_3v3); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CD_PAD_CTL, - CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE); - - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rtl8411b_extra_init_hw(struct rtsx_pcr *pcr) -{ - rtsx_pci_init_cmd(pcr); - - if (rtl8411b_is_qfn48(pcr)) - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - CARD_PULL_CTL3, 0xFF, 0xF5); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, - 0xFF, pcr->sd30_drive_sel_3v3); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CD_PAD_CTL, - CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, FUNC_FORCE_CTL, - 0x06, 0x00); - - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rtl8411_turn_on_led(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00); -} - -static int rtl8411_turn_off_led(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01); -} - -static int rtl8411_enable_auto_blink(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D); -} - -static int rtl8411_disable_auto_blink(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00); -} - -static int rtl8411_card_power_on(struct rtsx_pcr *pcr, int card) -{ - int err; - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CTL, - BPP_LDO_POWB, BPP_LDO_SUSPEND); - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - /* To avoid too large in-rush current */ - udelay(150); - - err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, - BPP_POWER_MASK, BPP_POWER_10_PERCENT_ON); - if (err < 0) - return err; - - udelay(150); - - err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, - BPP_POWER_MASK, BPP_POWER_15_PERCENT_ON); - if (err < 0) - return err; - - udelay(150); - - err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, - BPP_POWER_MASK, BPP_POWER_ON); - if (err < 0) - return err; - - return rtsx_pci_write_register(pcr, LDO_CTL, BPP_LDO_POWB, BPP_LDO_ON); -} - -static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card) -{ - int err; - - err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, - BPP_POWER_MASK, BPP_POWER_OFF); - if (err < 0) - return err; - - return rtsx_pci_write_register(pcr, LDO_CTL, - BPP_LDO_POWB, BPP_LDO_SUSPEND); -} - -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) | 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) | 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) | BPP_PAD_1V8; - } else { - return -EINVAL; - } - - 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; - - card_exist = rtsx_pci_readl(pcr, RTSX_BIPR); - card_exist &= CARD_EXIST; - if (!card_exist) { - /* Enable card CD */ - rtsx_pci_write_register(pcr, CD_PAD_CTL, - CD_DISABLE_MASK, CD_ENABLE); - /* Enable card interrupt */ - rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x00); - return 0; - } - - if (hweight32(card_exist) > 1) { - rtsx_pci_write_register(pcr, CARD_PWR_CTL, - BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON); - msleep(100); - - card_exist = rtsx_pci_readl(pcr, RTSX_BIPR); - if (card_exist & MS_EXIST) - card_exist = MS_EXIST; - else if (card_exist & SD_EXIST) - card_exist = SD_EXIST; - else - card_exist = 0; - - rtsx_pci_write_register(pcr, CARD_PWR_CTL, - BPP_POWER_MASK, BPP_POWER_OFF); - - pcr_dbg(pcr, "After CD deglitch, card_exist = 0x%x\n", - card_exist); - } - - if (card_exist & MS_EXIST) { - /* Disable SD interrupt */ - rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x40); - rtsx_pci_write_register(pcr, CD_PAD_CTL, - CD_DISABLE_MASK, MS_CD_EN_ONLY); - } else if (card_exist & SD_EXIST) { - /* Disable MS interrupt */ - rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x80); - rtsx_pci_write_register(pcr, CD_PAD_CTL, - CD_DISABLE_MASK, SD_CD_EN_ONLY); - } - - return card_exist; -} - -static int rtl8411_conv_clk_and_div_n(int input, int dir) -{ - int output; - - if (dir == CLK_TO_DIV_N) - output = input * 4 / 5 - 2; - else - output = (input + 2) * 5 / 4; - - return output; -} - -static const struct pcr_ops rtl8411_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 = rtl8411_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 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, - .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 = rtl8411_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, -}; - -/* SD Pull Control Enable: - * SD_DAT[3:0] ==> pull up - * SD_CD ==> pull up - * SD_WP ==> pull up - * SD_CMD ==> pull up - * SD_CLK ==> pull down - */ -static const u32 rtl8411_sd_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0xA9), - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x09), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), - 0, -}; - -/* SD Pull Control Disable: - * SD_DAT[3:0] ==> pull down - * SD_CD ==> pull up - * SD_WP ==> pull down - * SD_CMD ==> pull down - * SD_CLK ==> pull down - */ -static const u32 rtl8411_sd_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), - 0, -}; - -/* MS Pull Control Enable: - * MS CD ==> pull up - * others ==> pull down - */ -static const u32 rtl8411_ms_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), - 0, -}; - -/* MS Pull Control Disable: - * MS CD ==> pull up - * others ==> pull down - */ -static const u32 rtl8411_ms_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), - 0, -}; - -static const u32 rtl8411b_qfn64_sd_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0x09 | 0xD0), - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), - 0, -}; - -static const u32 rtl8411b_qfn48_sd_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0x69 | 0x90), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x08 | 0x11), - 0, -}; - -static const u32 rtl8411b_qfn64_sd_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0), - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), - 0, -}; - -static const u32 rtl8411b_qfn48_sd_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), - 0, -}; - -static const u32 rtl8411b_qfn64_ms_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0), - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05 | 0x50), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), - 0, -}; - -static const u32 rtl8411b_qfn48_ms_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), - 0, -}; - -static const u32 rtl8411b_qfn64_ms_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0), - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), - 0, -}; - -static const u32 rtl8411b_qfn48_ms_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), - 0, -}; - -static void rtl8411_init_common_params(struct rtsx_pcr *pcr) -{ - pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; - pcr->num_slots = 2; - pcr->flags = 0; - pcr->card_drive_sel = RTL8411_CARD_DRIVE_DEFAULT; - pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; - pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; - pcr->aspm_en = ASPM_L1_EN; - pcr->tx_initial_phase = SET_CLOCK_PHASE(23, 7, 14); - pcr->rx_initial_phase = SET_CLOCK_PHASE(4, 3, 10); - pcr->ic_version = rtl8411_get_ic_version(pcr); -} - -void rtl8411_init_params(struct rtsx_pcr *pcr) -{ - rtl8411_init_common_params(pcr); - pcr->ops = &rtl8411_pcr_ops; - set_pull_ctrl_tables(pcr, rtl8411); -} - -void rtl8411b_init_params(struct rtsx_pcr *pcr) -{ - rtl8411_init_common_params(pcr); - pcr->ops = &rtl8411b_pcr_ops; - if (rtl8411b_is_qfn48(pcr)) - set_pull_ctrl_tables(pcr, rtl8411b_qfn48); - 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/rts5209.c b/drivers/mfd/rts5209.c deleted file mode 100644 index b95beecf767f..000000000000 --- a/drivers/mfd/rts5209.c +++ /dev/null @@ -1,277 +0,0 @@ -/* Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * 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, 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Author: - * Wei WANG - */ - -#include -#include -#include - -#include "rtsx_pcr.h" - -static u8 rts5209_get_ic_version(struct rtsx_pcr *pcr) -{ - u8 val; - - val = rtsx_pci_readb(pcr, 0x1C); - return val & 0x0F; -} - -static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr) -{ - u32 reg; - - rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); - pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); - - if (rts5209_vendor_setting1_valid(reg)) { - if (rts5209_reg_check_ms_pmos(reg)) - pcr->flags |= PCR_MS_PMOS; - pcr->aspm_en = rts5209_reg_to_aspm(reg); - } - - rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®); - pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); - - if (rts5209_vendor_setting2_valid(reg)) { - pcr->sd30_drive_sel_1v8 = - rts5209_reg_to_sd30_drive_sel_1v8(reg); - pcr->sd30_drive_sel_3v3 = - rts5209_reg_to_sd30_drive_sel_3v3(reg); - pcr->card_drive_sel = rts5209_reg_to_card_drive_sel(reg); - } -} - -static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) -{ - rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07); -} - -static int rts5209_extra_init_hw(struct rtsx_pcr *pcr) -{ - rtsx_pci_init_cmd(pcr); - - /* Turn off LED */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO, 0xFF, 0x03); - /* Reset ASPM state to default value */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); - /* Force CLKREQ# PIN to drive 0 to request clock */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08); - /* Configure GPIO as output */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO_DIR, 0xFF, 0x03); - /* Configure driving */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, - 0xFF, pcr->sd30_drive_sel_3v3); - - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rts5209_optimize_phy(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_phy_register(pcr, 0x00, 0xB966); -} - -static int rts5209_turn_on_led(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00); -} - -static int rts5209_turn_off_led(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01); -} - -static int rts5209_enable_auto_blink(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D); -} - -static int rts5209_disable_auto_blink(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00); -} - -static int rts5209_card_power_on(struct rtsx_pcr *pcr, int card) -{ - int err; - u8 pwr_mask, partial_pwr_on, pwr_on; - - pwr_mask = SD_POWER_MASK; - partial_pwr_on = SD_PARTIAL_POWER_ON; - pwr_on = SD_POWER_ON; - - if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) { - pwr_mask = MS_POWER_MASK; - partial_pwr_on = MS_PARTIAL_POWER_ON; - pwr_on = MS_POWER_ON; - } - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - pwr_mask, partial_pwr_on); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x04); - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - /* To avoid too large in-rush current */ - udelay(150); - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, pwr_mask, pwr_on); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x00); - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card) -{ - u8 pwr_mask, pwr_off; - - pwr_mask = SD_POWER_MASK; - pwr_off = SD_POWER_OFF; - - if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) { - pwr_mask = MS_POWER_MASK; - pwr_off = MS_POWER_OFF; - } - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - pwr_mask | PMOS_STRG_MASK, pwr_off | PMOS_STRG_400mA); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x06); - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) -{ - int err; - - if (voltage == OUTPUT_3V3) { - err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3); - if (err < 0) - return err; - err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); - if (err < 0) - return err; - } 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; - err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); - if (err < 0) - return err; - } else { - return -EINVAL; - } - - return 0; -} - -static const struct pcr_ops rts5209_pcr_ops = { - .fetch_vendor_settings = rts5209_fetch_vendor_settings, - .extra_init_hw = rts5209_extra_init_hw, - .optimize_phy = rts5209_optimize_phy, - .turn_on_led = rts5209_turn_on_led, - .turn_off_led = rts5209_turn_off_led, - .enable_auto_blink = rts5209_enable_auto_blink, - .disable_auto_blink = rts5209_disable_auto_blink, - .card_power_on = rts5209_card_power_on, - .card_power_off = rts5209_card_power_off, - .switch_output_voltage = rts5209_switch_output_voltage, - .cd_deglitch = NULL, - .conv_clk_and_div_n = NULL, - .force_power_down = rts5209_force_power_down, -}; - -/* SD Pull Control Enable: - * SD_DAT[3:0] ==> pull up - * SD_CD ==> pull up - * SD_WP ==> pull up - * SD_CMD ==> pull up - * SD_CLK ==> pull down - */ -static const u32 rts5209_sd_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), - 0, -}; - -/* SD Pull Control Disable: - * SD_DAT[3:0] ==> pull down - * SD_CD ==> pull up - * SD_WP ==> pull down - * SD_CMD ==> pull down - * SD_CLK ==> pull down - */ -static const u32 rts5209_sd_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), - 0, -}; - -/* MS Pull Control Enable: - * MS CD ==> pull up - * others ==> pull down - */ -static const u32 rts5209_ms_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), - 0, -}; - -/* MS Pull Control Disable: - * MS CD ==> pull up - * others ==> pull down - */ -static const u32 rts5209_ms_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), - 0, -}; - -void rts5209_init_params(struct rtsx_pcr *pcr) -{ - pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | - EXTRA_CAPS_SD_SDR104 | EXTRA_CAPS_MMC_8BIT; - pcr->num_slots = 2; - pcr->ops = &rts5209_pcr_ops; - - pcr->flags = 0; - pcr->card_drive_sel = RTS5209_CARD_DRIVE_DEFAULT; - pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; - pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; - pcr->aspm_en = ASPM_L1_EN; - pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 16); - pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5); - - pcr->ic_version = rts5209_get_ic_version(pcr); - pcr->sd_pull_ctl_enable_tbl = rts5209_sd_pull_ctl_enable_tbl; - pcr->sd_pull_ctl_disable_tbl = rts5209_sd_pull_ctl_disable_tbl; - pcr->ms_pull_ctl_enable_tbl = rts5209_ms_pull_ctl_enable_tbl; - pcr->ms_pull_ctl_disable_tbl = rts5209_ms_pull_ctl_disable_tbl; -} diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c deleted file mode 100644 index ff296a4bf3d2..000000000000 --- a/drivers/mfd/rts5227.c +++ /dev/null @@ -1,374 +0,0 @@ -/* Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * 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, 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Author: - * Wei WANG - * Roger Tseng - */ - -#include -#include -#include - -#include "rtsx_pcr.h" - -static u8 rts5227_get_ic_version(struct rtsx_pcr *pcr) -{ - u8 val; - - rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val); - return val & 0x0F; -} - -static void rts5227_fill_driving(struct rtsx_pcr *pcr, u8 voltage) -{ - u8 driving_3v3[4][3] = { - {0x13, 0x13, 0x13}, - {0x96, 0x96, 0x96}, - {0x7F, 0x7F, 0x7F}, - {0x96, 0x96, 0x96}, - }; - u8 driving_1v8[4][3] = { - {0x99, 0x99, 0x99}, - {0xAA, 0xAA, 0xAA}, - {0xFE, 0xFE, 0xFE}, - {0xB3, 0xB3, 0xB3}, - }; - u8 (*driving)[3], drive_sel; - - if (voltage == OUTPUT_3V3) { - driving = driving_3v3; - drive_sel = pcr->sd30_drive_sel_3v3; - } else { - driving = driving_1v8; - drive_sel = pcr->sd30_drive_sel_1v8; - } - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL, - 0xFF, driving[drive_sel][0]); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL, - 0xFF, driving[drive_sel][1]); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL, - 0xFF, driving[drive_sel][2]); -} - -static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr) -{ - u32 reg; - - rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); - pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); - - if (!rtsx_vendor_setting_valid(reg)) - return; - - pcr->aspm_en = rtsx_reg_to_aspm(reg); - pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg); - pcr->card_drive_sel &= 0x3F; - pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg); - - rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®); - pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); - pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg); - if (rtsx_reg_check_reverse_socket(reg)) - pcr->flags |= PCR_REVERSE_SOCKET; -} - -static void rts5227_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) -{ - /* Set relink_time to 0 */ - rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0); - rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0); - rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0); - - if (pm_state == HOST_ENTER_S3) - rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x10); - - rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); -} - -static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) -{ - u16 cap; - - rtsx_pci_init_cmd(pcr); - - /* Configure GPIO as output */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); - /* Reset ASPM state to default value */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); - /* Switch LDO3318 source from DV33 to card_3v3 */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); - /* LED shine disabled, set initial shine cycle period */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); - /* Configure LTR */ - pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &cap); - if (cap & PCI_EXP_DEVCTL2_LTR_EN) - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LTR_CTL, 0xFF, 0xA3); - /* Configure OBFF */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OBFF_CFG, 0x03, 0x03); - /* Configure driving */ - rts5227_fill_driving(pcr, OUTPUT_3V3); - /* Configure force_clock_req */ - if (pcr->flags & PCR_REVERSE_SOCKET) - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB8, 0xB8); - else - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB8, 0x88); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, pcr->reg_pm_ctrl3, 0x10, 0x00); - - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rts5227_optimize_phy(struct rtsx_pcr *pcr) -{ - int err; - - err = rtsx_pci_write_register(pcr, PM_CTRL3, D3_DELINK_MODE_EN, 0x00); - if (err < 0) - return err; - - /* Optimize RX sensitivity */ - return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42); -} - -static int rts5227_turn_on_led(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02); -} - -static int rts5227_turn_off_led(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00); -} - -static int rts5227_enable_auto_blink(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08); -} - -static int rts5227_disable_auto_blink(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00); -} - -static int rts5227_card_power_on(struct rtsx_pcr *pcr, int card) -{ - int err; - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - SD_POWER_MASK, SD_PARTIAL_POWER_ON); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x02); - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - /* To avoid too large in-rush current */ - udelay(150); - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - SD_POWER_MASK, SD_POWER_ON); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x06); - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rts5227_card_power_off(struct rtsx_pcr *pcr, int card) -{ - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - SD_POWER_MASK | PMOS_STRG_MASK, - SD_POWER_OFF | PMOS_STRG_400mA); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0X00); - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rts5227_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) -{ - int err; - - if (voltage == OUTPUT_3V3) { - err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); - if (err < 0) - return err; - } else if (voltage == OUTPUT_1V8) { - err = rtsx_pci_write_phy_register(pcr, 0x11, 0x3C02); - if (err < 0) - return err; - err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C80 | 0x24); - if (err < 0) - return err; - } else { - return -EINVAL; - } - - /* set pad drive */ - rtsx_pci_init_cmd(pcr); - rts5227_fill_driving(pcr, voltage); - return rtsx_pci_send_cmd(pcr, 100); -} - -static const struct pcr_ops rts5227_pcr_ops = { - .fetch_vendor_settings = rts5227_fetch_vendor_settings, - .extra_init_hw = rts5227_extra_init_hw, - .optimize_phy = rts5227_optimize_phy, - .turn_on_led = rts5227_turn_on_led, - .turn_off_led = rts5227_turn_off_led, - .enable_auto_blink = rts5227_enable_auto_blink, - .disable_auto_blink = rts5227_disable_auto_blink, - .card_power_on = rts5227_card_power_on, - .card_power_off = rts5227_card_power_off, - .switch_output_voltage = rts5227_switch_output_voltage, - .cd_deglitch = NULL, - .conv_clk_and_div_n = NULL, - .force_power_down = rts5227_force_power_down, -}; - -/* SD Pull Control Enable: - * SD_DAT[3:0] ==> pull up - * SD_CD ==> pull up - * SD_WP ==> pull up - * SD_CMD ==> pull up - * SD_CLK ==> pull down - */ -static const u32 rts5227_sd_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), - 0, -}; - -/* SD Pull Control Disable: - * SD_DAT[3:0] ==> pull down - * SD_CD ==> pull up - * SD_WP ==> pull down - * SD_CMD ==> pull down - * SD_CLK ==> pull down - */ -static const u32 rts5227_sd_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), - 0, -}; - -/* MS Pull Control Enable: - * MS CD ==> pull up - * others ==> pull down - */ -static const u32 rts5227_ms_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), - 0, -}; - -/* MS Pull Control Disable: - * MS CD ==> pull up - * others ==> pull down - */ -static const u32 rts5227_ms_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), - 0, -}; - -void rts5227_init_params(struct rtsx_pcr *pcr) -{ - pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; - pcr->num_slots = 2; - pcr->ops = &rts5227_pcr_ops; - - pcr->flags = 0; - pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT; - pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B; - pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B; - pcr->aspm_en = ASPM_L1_EN; - pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15); - pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 7, 7); - - pcr->ic_version = rts5227_get_ic_version(pcr); - pcr->sd_pull_ctl_enable_tbl = rts5227_sd_pull_ctl_enable_tbl; - pcr->sd_pull_ctl_disable_tbl = rts5227_sd_pull_ctl_disable_tbl; - pcr->ms_pull_ctl_enable_tbl = rts5227_ms_pull_ctl_enable_tbl; - pcr->ms_pull_ctl_disable_tbl = rts5227_ms_pull_ctl_disable_tbl; - - pcr->reg_pm_ctrl3 = PM_CTRL3; -} - -static int rts522a_optimize_phy(struct rtsx_pcr *pcr) -{ - int err; - - err = rtsx_pci_write_register(pcr, RTS522A_PM_CTRL3, D3_DELINK_MODE_EN, - 0x00); - if (err < 0) - return err; - - if (is_version(pcr, 0x522A, IC_VER_A)) { - err = rtsx_pci_write_phy_register(pcr, PHY_RCR2, - PHY_RCR2_INIT_27S); - if (err) - return err; - - rtsx_pci_write_phy_register(pcr, PHY_RCR1, PHY_RCR1_INIT_27S); - rtsx_pci_write_phy_register(pcr, PHY_FLD0, PHY_FLD0_INIT_27S); - rtsx_pci_write_phy_register(pcr, PHY_FLD3, PHY_FLD3_INIT_27S); - rtsx_pci_write_phy_register(pcr, PHY_FLD4, PHY_FLD4_INIT_27S); - } - - return 0; -} - -static int rts522a_extra_init_hw(struct rtsx_pcr *pcr) -{ - rts5227_extra_init_hw(pcr); - - rtsx_pci_write_register(pcr, FUNC_FORCE_CTL, FUNC_FORCE_UPME_XMT_DBG, - FUNC_FORCE_UPME_XMT_DBG); - rtsx_pci_write_register(pcr, PCLK_CTL, 0x04, 0x04); - rtsx_pci_write_register(pcr, PM_EVENT_DEBUG, PME_DEBUG_0, PME_DEBUG_0); - rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 0xFF, 0x11); - - return 0; -} - -/* rts522a operations mainly derived from rts5227, except phy/hw init setting. - */ -static const struct pcr_ops rts522a_pcr_ops = { - .fetch_vendor_settings = rts5227_fetch_vendor_settings, - .extra_init_hw = rts522a_extra_init_hw, - .optimize_phy = rts522a_optimize_phy, - .turn_on_led = rts5227_turn_on_led, - .turn_off_led = rts5227_turn_off_led, - .enable_auto_blink = rts5227_enable_auto_blink, - .disable_auto_blink = rts5227_disable_auto_blink, - .card_power_on = rts5227_card_power_on, - .card_power_off = rts5227_card_power_off, - .switch_output_voltage = rts5227_switch_output_voltage, - .cd_deglitch = NULL, - .conv_clk_and_div_n = NULL, - .force_power_down = rts5227_force_power_down, -}; - -void rts522a_init_params(struct rtsx_pcr *pcr) -{ - rts5227_init_params(pcr); - - pcr->reg_pm_ctrl3 = RTS522A_PM_CTRL3; -} diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c deleted file mode 100644 index 9ed9dc84eac8..000000000000 --- a/drivers/mfd/rts5229.c +++ /dev/null @@ -1,273 +0,0 @@ -/* Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * 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, 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Author: - * Wei WANG - */ - -#include -#include -#include - -#include "rtsx_pcr.h" - -static u8 rts5229_get_ic_version(struct rtsx_pcr *pcr) -{ - u8 val; - - rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val); - return val & 0x0F; -} - -static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr) -{ - u32 reg; - - rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); - pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); - - if (!rtsx_vendor_setting_valid(reg)) - return; - - pcr->aspm_en = rtsx_reg_to_aspm(reg); - pcr->sd30_drive_sel_1v8 = - map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg)); - pcr->card_drive_sel &= 0x3F; - pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg); - - rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®); - pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); - pcr->sd30_drive_sel_3v3 = - map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg)); -} - -static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) -{ - rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); -} - -static int rts5229_extra_init_hw(struct rtsx_pcr *pcr) -{ - rtsx_pci_init_cmd(pcr); - - /* Configure GPIO as output */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); - /* Reset ASPM state to default value */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); - /* Force CLKREQ# PIN to drive 0 to request clock */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08); - /* Switch LDO3318 source from DV33 to card_3v3 */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); - /* LED shine disabled, set initial shine cycle period */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); - /* Configure driving */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, - 0xFF, pcr->sd30_drive_sel_3v3); - - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rts5229_optimize_phy(struct rtsx_pcr *pcr) -{ - /* Optimize RX sensitivity */ - return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42); -} - -static int rts5229_turn_on_led(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02); -} - -static int rts5229_turn_off_led(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00); -} - -static int rts5229_enable_auto_blink(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08); -} - -static int rts5229_disable_auto_blink(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00); -} - -static int rts5229_card_power_on(struct rtsx_pcr *pcr, int card) -{ - int err; - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - SD_POWER_MASK, SD_PARTIAL_POWER_ON); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x02); - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - /* To avoid too large in-rush current */ - udelay(150); - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - SD_POWER_MASK, SD_POWER_ON); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x06); - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rts5229_card_power_off(struct rtsx_pcr *pcr, int card) -{ - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - SD_POWER_MASK | PMOS_STRG_MASK, - SD_POWER_OFF | PMOS_STRG_400mA); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x00); - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) -{ - int err; - - if (voltage == OUTPUT_3V3) { - err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3); - if (err < 0) - return err; - err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); - if (err < 0) - return err; - } 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; - err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); - if (err < 0) - return err; - } else { - return -EINVAL; - } - - return 0; -} - -static const struct pcr_ops rts5229_pcr_ops = { - .fetch_vendor_settings = rts5229_fetch_vendor_settings, - .extra_init_hw = rts5229_extra_init_hw, - .optimize_phy = rts5229_optimize_phy, - .turn_on_led = rts5229_turn_on_led, - .turn_off_led = rts5229_turn_off_led, - .enable_auto_blink = rts5229_enable_auto_blink, - .disable_auto_blink = rts5229_disable_auto_blink, - .card_power_on = rts5229_card_power_on, - .card_power_off = rts5229_card_power_off, - .switch_output_voltage = rts5229_switch_output_voltage, - .cd_deglitch = NULL, - .conv_clk_and_div_n = NULL, - .force_power_down = rts5229_force_power_down, -}; - -/* SD Pull Control Enable: - * SD_DAT[3:0] ==> pull up - * SD_CD ==> pull up - * SD_WP ==> pull up - * SD_CMD ==> pull up - * SD_CLK ==> pull down - */ -static const u32 rts5229_sd_pull_ctl_enable_tbl1[] = { - RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), - 0, -}; - -/* For RTS5229 version C */ -static const u32 rts5229_sd_pull_ctl_enable_tbl2[] = { - RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD9), - 0, -}; - -/* SD Pull Control Disable: - * SD_DAT[3:0] ==> pull down - * SD_CD ==> pull up - * SD_WP ==> pull down - * SD_CMD ==> pull down - * SD_CLK ==> pull down - */ -static const u32 rts5229_sd_pull_ctl_disable_tbl1[] = { - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), - 0, -}; - -/* For RTS5229 version C */ -static const u32 rts5229_sd_pull_ctl_disable_tbl2[] = { - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE5), - 0, -}; - -/* MS Pull Control Enable: - * MS CD ==> pull up - * others ==> pull down - */ -static const u32 rts5229_ms_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), - 0, -}; - -/* MS Pull Control Disable: - * MS CD ==> pull up - * others ==> pull down - */ -static const u32 rts5229_ms_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), - 0, -}; - -void rts5229_init_params(struct rtsx_pcr *pcr) -{ - pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; - pcr->num_slots = 2; - pcr->ops = &rts5229_pcr_ops; - - pcr->flags = 0; - pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT; - pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; - pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; - pcr->aspm_en = ASPM_L1_EN; - pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15); - pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 6, 6); - - pcr->ic_version = rts5229_get_ic_version(pcr); - if (pcr->ic_version == IC_VER_C) { - pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl2; - pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl2; - } else { - pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl1; - pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl1; - } - pcr->ms_pull_ctl_enable_tbl = rts5229_ms_pull_ctl_enable_tbl; - pcr->ms_pull_ctl_disable_tbl = rts5229_ms_pull_ctl_disable_tbl; -} diff --git a/drivers/mfd/rts5249.c b/drivers/mfd/rts5249.c deleted file mode 100644 index 7fcf37ba922c..000000000000 --- a/drivers/mfd/rts5249.c +++ /dev/null @@ -1,741 +0,0 @@ -/* Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * 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, 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Author: - * Wei WANG - */ - -#include -#include -#include - -#include "rtsx_pcr.h" - -static u8 rts5249_get_ic_version(struct rtsx_pcr *pcr) -{ - u8 val; - - rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val); - return val & 0x0F; -} - -static void rts5249_fill_driving(struct rtsx_pcr *pcr, u8 voltage) -{ - u8 driving_3v3[4][3] = { - {0x11, 0x11, 0x18}, - {0x55, 0x55, 0x5C}, - {0xFF, 0xFF, 0xFF}, - {0x96, 0x96, 0x96}, - }; - u8 driving_1v8[4][3] = { - {0xC4, 0xC4, 0xC4}, - {0x3C, 0x3C, 0x3C}, - {0xFE, 0xFE, 0xFE}, - {0xB3, 0xB3, 0xB3}, - }; - u8 (*driving)[3], drive_sel; - - if (voltage == OUTPUT_3V3) { - driving = driving_3v3; - drive_sel = pcr->sd30_drive_sel_3v3; - } else { - driving = driving_1v8; - drive_sel = pcr->sd30_drive_sel_1v8; - } - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL, - 0xFF, driving[drive_sel][0]); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL, - 0xFF, driving[drive_sel][1]); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL, - 0xFF, driving[drive_sel][2]); -} - -static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr) -{ - u32 reg; - - rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); - pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); - - if (!rtsx_vendor_setting_valid(reg)) { - pcr_dbg(pcr, "skip fetch vendor setting\n"); - return; - } - - pcr->aspm_en = rtsx_reg_to_aspm(reg); - pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg); - pcr->card_drive_sel &= 0x3F; - pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg); - - rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®); - pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); - pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg); - if (rtsx_reg_check_reverse_socket(reg)) - pcr->flags |= PCR_REVERSE_SOCKET; -} - -static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) -{ - /* Set relink_time to 0 */ - rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0); - rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0); - rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0); - - if (pm_state == HOST_ENTER_S3) - rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, - D3_DELINK_MODE_EN, D3_DELINK_MODE_EN); - - rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); -} - -static void rts5249_init_from_cfg(struct rtsx_pcr *pcr) -{ - struct rtsx_cr_option *option = &(pcr->option); - u32 lval; - - if (CHK_PCI_PID(pcr, PID_524A)) - rtsx_pci_read_config_dword(pcr, - PCR_ASPM_SETTING_REG1, &lval); - else - rtsx_pci_read_config_dword(pcr, - PCR_ASPM_SETTING_REG2, &lval); - - if (lval & ASPM_L1_1_EN_MASK) - rtsx_set_dev_flag(pcr, ASPM_L1_1_EN); - - if (lval & ASPM_L1_2_EN_MASK) - rtsx_set_dev_flag(pcr, ASPM_L1_2_EN); - - if (lval & PM_L1_1_EN_MASK) - rtsx_set_dev_flag(pcr, PM_L1_1_EN); - - if (lval & PM_L1_2_EN_MASK) - rtsx_set_dev_flag(pcr, PM_L1_2_EN); - - if (option->ltr_en) { - u16 val; - - pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val); - if (val & PCI_EXP_DEVCTL2_LTR_EN) { - option->ltr_enabled = true; - option->ltr_active = true; - rtsx_set_ltr_latency(pcr, option->ltr_active_latency); - } else { - option->ltr_enabled = false; - } - } -} - -static int rts5249_init_from_hw(struct rtsx_pcr *pcr) -{ - struct rtsx_cr_option *option = &(pcr->option); - - if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN - | PM_L1_1_EN | PM_L1_2_EN)) - option->force_clkreq_0 = false; - else - option->force_clkreq_0 = true; - - return 0; -} - -static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) -{ - struct rtsx_cr_option *option = &(pcr->option); - - rts5249_init_from_cfg(pcr); - rts5249_init_from_hw(pcr); - - rtsx_pci_init_cmd(pcr); - - /* Rest L1SUB Config */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, L1SUB_CONFIG3, 0xFF, 0x00); - /* Configure GPIO as output */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); - /* Reset ASPM state to default value */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); - /* Switch LDO3318 source from DV33 to card_3v3 */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); - /* LED shine disabled, set initial shine cycle period */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); - /* Configure driving */ - rts5249_fill_driving(pcr, OUTPUT_3V3); - if (pcr->flags & PCR_REVERSE_SOCKET) - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0xB0); - else - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0x80); - - /* - * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced - * to drive low, and we forcibly request clock. - */ - if (option->force_clkreq_0) - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, - FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); - else - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, - FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH); - - return rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF); -} - -static int rts5249_optimize_phy(struct rtsx_pcr *pcr) -{ - int err; - - err = rtsx_pci_write_register(pcr, PM_CTRL3, D3_DELINK_MODE_EN, 0x00); - if (err < 0) - return err; - - err = rtsx_pci_write_phy_register(pcr, PHY_REV, - PHY_REV_RESV | PHY_REV_RXIDLE_LATCHED | - PHY_REV_P1_EN | PHY_REV_RXIDLE_EN | - PHY_REV_CLKREQ_TX_EN | PHY_REV_RX_PWST | - PHY_REV_CLKREQ_DT_1_0 | PHY_REV_STOP_CLKRD | - PHY_REV_STOP_CLKWR); - if (err < 0) - return err; - - msleep(1); - - err = rtsx_pci_write_phy_register(pcr, PHY_BPCR, - PHY_BPCR_IBRXSEL | PHY_BPCR_IBTXSEL | - PHY_BPCR_IB_FILTER | PHY_BPCR_CMIRROR_EN); - if (err < 0) - return err; - - err = rtsx_pci_write_phy_register(pcr, PHY_PCR, - PHY_PCR_FORCE_CODE | PHY_PCR_OOBS_CALI_50 | - PHY_PCR_OOBS_VCM_08 | PHY_PCR_OOBS_SEN_90 | - PHY_PCR_RSSI_EN | PHY_PCR_RX10K); - if (err < 0) - return err; - - err = rtsx_pci_write_phy_register(pcr, PHY_RCR2, - PHY_RCR2_EMPHASE_EN | PHY_RCR2_NADJR | - PHY_RCR2_CDR_SR_2 | PHY_RCR2_FREQSEL_12 | - PHY_RCR2_CDR_SC_12P | PHY_RCR2_CALIB_LATE); - if (err < 0) - return err; - - err = rtsx_pci_write_phy_register(pcr, PHY_FLD4, - PHY_FLD4_FLDEN_SEL | PHY_FLD4_REQ_REF | - PHY_FLD4_RXAMP_OFF | PHY_FLD4_REQ_ADDA | - PHY_FLD4_BER_COUNT | PHY_FLD4_BER_TIMER | - PHY_FLD4_BER_CHK_EN); - if (err < 0) - return err; - err = rtsx_pci_write_phy_register(pcr, PHY_RDR, - PHY_RDR_RXDSEL_1_9 | PHY_SSC_AUTO_PWD); - if (err < 0) - return err; - err = rtsx_pci_write_phy_register(pcr, PHY_RCR1, - PHY_RCR1_ADP_TIME_4 | PHY_RCR1_VCO_COARSE); - if (err < 0) - return err; - err = rtsx_pci_write_phy_register(pcr, PHY_FLD3, - PHY_FLD3_TIMER_4 | PHY_FLD3_TIMER_6 | - PHY_FLD3_RXDELINK); - if (err < 0) - return err; - - return rtsx_pci_write_phy_register(pcr, PHY_TUNE, - PHY_TUNE_TUNEREF_1_0 | PHY_TUNE_VBGSEL_1252 | - PHY_TUNE_SDBUS_33 | PHY_TUNE_TUNED18 | - PHY_TUNE_TUNED12 | PHY_TUNE_TUNEA12); -} - -static int rtsx_base_turn_on_led(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02); -} - -static int rtsx_base_turn_off_led(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00); -} - -static int rtsx_base_enable_auto_blink(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08); -} - -static int rtsx_base_disable_auto_blink(struct rtsx_pcr *pcr) -{ - return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00); -} - -static int rtsx_base_card_power_on(struct rtsx_pcr *pcr, int card) -{ - int err; - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - SD_POWER_MASK, SD_VCC_PARTIAL_POWER_ON); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x02); - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - msleep(5); - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - SD_POWER_MASK, SD_VCC_POWER_ON); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x06); - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rtsx_base_card_power_off(struct rtsx_pcr *pcr, int card) -{ - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, - SD_POWER_MASK, SD_POWER_OFF); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0x00); - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rtsx_base_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) -{ - int err; - u16 append; - - switch (voltage) { - case OUTPUT_3V3: - err = rtsx_pci_update_phy(pcr, PHY_TUNE, PHY_TUNE_VOLTAGE_MASK, - PHY_TUNE_VOLTAGE_3V3); - if (err < 0) - return err; - break; - case OUTPUT_1V8: - append = PHY_TUNE_D18_1V8; - if (CHK_PCI_PID(pcr, 0x5249)) { - err = rtsx_pci_update_phy(pcr, PHY_BACR, - PHY_BACR_BASIC_MASK, 0); - if (err < 0) - return err; - append = PHY_TUNE_D18_1V7; - } - - err = rtsx_pci_update_phy(pcr, PHY_TUNE, PHY_TUNE_VOLTAGE_MASK, - append); - if (err < 0) - return err; - break; - default: - pcr_dbg(pcr, "unknown output voltage %d\n", voltage); - return -EINVAL; - } - - /* set pad drive */ - rtsx_pci_init_cmd(pcr); - rts5249_fill_driving(pcr, voltage); - return rtsx_pci_send_cmd(pcr, 100); -} - -static void rts5249_set_aspm(struct rtsx_pcr *pcr, bool enable) -{ - struct rtsx_cr_option *option = &pcr->option; - u8 val = 0; - - if (pcr->aspm_enabled == enable) - return; - - if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) { - if (enable) - val = pcr->aspm_en; - rtsx_pci_update_cfg_byte(pcr, - pcr->pcie_cap + PCI_EXP_LNKCTL, - ASPM_MASK_NEG, val); - } else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) { - u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0; - - if (!enable) - val = FORCE_ASPM_CTL0; - rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val); - } - - pcr->aspm_enabled = enable; -} - -static const struct pcr_ops rts5249_pcr_ops = { - .fetch_vendor_settings = rtsx_base_fetch_vendor_settings, - .extra_init_hw = rts5249_extra_init_hw, - .optimize_phy = rts5249_optimize_phy, - .turn_on_led = rtsx_base_turn_on_led, - .turn_off_led = rtsx_base_turn_off_led, - .enable_auto_blink = rtsx_base_enable_auto_blink, - .disable_auto_blink = rtsx_base_disable_auto_blink, - .card_power_on = rtsx_base_card_power_on, - .card_power_off = rtsx_base_card_power_off, - .switch_output_voltage = rtsx_base_switch_output_voltage, - .force_power_down = rtsx_base_force_power_down, - .set_aspm = rts5249_set_aspm, -}; - -/* SD Pull Control Enable: - * SD_DAT[3:0] ==> pull up - * SD_CD ==> pull up - * SD_WP ==> pull up - * SD_CMD ==> pull up - * SD_CLK ==> pull down - */ -static const u32 rts5249_sd_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), - RTSX_REG_PAIR(CARD_PULL_CTL4, 0xAA), - 0, -}; - -/* SD Pull Control Disable: - * SD_DAT[3:0] ==> pull down - * SD_CD ==> pull up - * SD_WP ==> pull down - * SD_CMD ==> pull down - * SD_CLK ==> pull down - */ -static const u32 rts5249_sd_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL1, 0x66), - RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), - 0, -}; - -/* MS Pull Control Enable: - * MS CD ==> pull up - * others ==> pull down - */ -static const u32 rts5249_ms_pull_ctl_enable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), - 0, -}; - -/* MS Pull Control Disable: - * MS CD ==> pull up - * others ==> pull down - */ -static const u32 rts5249_ms_pull_ctl_disable_tbl[] = { - RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), - RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), - 0, -}; - -void rts5249_init_params(struct rtsx_pcr *pcr) -{ - struct rtsx_cr_option *option = &(pcr->option); - - pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; - pcr->num_slots = 2; - pcr->ops = &rts5249_pcr_ops; - - pcr->flags = 0; - pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT; - pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B; - pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B; - pcr->aspm_en = ASPM_L1_EN; - pcr->tx_initial_phase = SET_CLOCK_PHASE(1, 29, 16); - pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5); - - pcr->ic_version = rts5249_get_ic_version(pcr); - pcr->sd_pull_ctl_enable_tbl = rts5249_sd_pull_ctl_enable_tbl; - pcr->sd_pull_ctl_disable_tbl = rts5249_sd_pull_ctl_disable_tbl; - pcr->ms_pull_ctl_enable_tbl = rts5249_ms_pull_ctl_enable_tbl; - pcr->ms_pull_ctl_disable_tbl = rts5249_ms_pull_ctl_disable_tbl; - - pcr->reg_pm_ctrl3 = PM_CTRL3; - - option->dev_flags = (LTR_L1SS_PWR_GATE_CHECK_CARD_EN - | LTR_L1SS_PWR_GATE_EN); - option->ltr_en = true; - - /* Init latency of active, idle, L1OFF to 60us, 300us, 3ms */ - option->ltr_active_latency = LTR_ACTIVE_LATENCY_DEF; - option->ltr_idle_latency = LTR_IDLE_LATENCY_DEF; - option->ltr_l1off_latency = LTR_L1OFF_LATENCY_DEF; - option->dev_aspm_mode = DEV_ASPM_DYNAMIC; - option->l1_snooze_delay = L1_SNOOZE_DELAY_DEF; - option->ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5249_DEF; - option->ltr_l1off_snooze_sspwrgate = - LTR_L1OFF_SNOOZE_SSPWRGATE_5249_DEF; -} - -static int rts524a_write_phy(struct rtsx_pcr *pcr, u8 addr, u16 val) -{ - addr = addr & 0x80 ? (addr & 0x7F) | 0x40 : addr; - - return __rtsx_pci_write_phy_register(pcr, addr, val); -} - -static int rts524a_read_phy(struct rtsx_pcr *pcr, u8 addr, u16 *val) -{ - addr = addr & 0x80 ? (addr & 0x7F) | 0x40 : addr; - - return __rtsx_pci_read_phy_register(pcr, addr, val); -} - -static int rts524a_optimize_phy(struct rtsx_pcr *pcr) -{ - int err; - - err = rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3, - D3_DELINK_MODE_EN, 0x00); - if (err < 0) - return err; - - rtsx_pci_write_phy_register(pcr, PHY_PCR, - PHY_PCR_FORCE_CODE | PHY_PCR_OOBS_CALI_50 | - PHY_PCR_OOBS_VCM_08 | PHY_PCR_OOBS_SEN_90 | PHY_PCR_RSSI_EN); - rtsx_pci_write_phy_register(pcr, PHY_SSCCR3, - PHY_SSCCR3_STEP_IN | PHY_SSCCR3_CHECK_DELAY); - - if (is_version(pcr, 0x524A, IC_VER_A)) { - rtsx_pci_write_phy_register(pcr, PHY_SSCCR3, - PHY_SSCCR3_STEP_IN | PHY_SSCCR3_CHECK_DELAY); - rtsx_pci_write_phy_register(pcr, PHY_SSCCR2, - PHY_SSCCR2_PLL_NCODE | PHY_SSCCR2_TIME0 | - PHY_SSCCR2_TIME2_WIDTH); - rtsx_pci_write_phy_register(pcr, PHY_ANA1A, - PHY_ANA1A_TXR_LOOPBACK | PHY_ANA1A_RXT_BIST | - PHY_ANA1A_TXR_BIST | PHY_ANA1A_REV); - rtsx_pci_write_phy_register(pcr, PHY_ANA1D, - PHY_ANA1D_DEBUG_ADDR); - rtsx_pci_write_phy_register(pcr, PHY_DIG1E, - PHY_DIG1E_REV | PHY_DIG1E_D0_X_D1 | - PHY_DIG1E_RX_ON_HOST | PHY_DIG1E_RCLK_REF_HOST | - PHY_DIG1E_RCLK_TX_EN_KEEP | - PHY_DIG1E_RCLK_TX_TERM_KEEP | - PHY_DIG1E_RCLK_RX_EIDLE_ON | PHY_DIG1E_TX_TERM_KEEP | - PHY_DIG1E_RX_TERM_KEEP | PHY_DIG1E_TX_EN_KEEP | - PHY_DIG1E_RX_EN_KEEP); - } - - rtsx_pci_write_phy_register(pcr, PHY_ANA08, - PHY_ANA08_RX_EQ_DCGAIN | PHY_ANA08_SEL_RX_EN | - PHY_ANA08_RX_EQ_VAL | PHY_ANA08_SCP | PHY_ANA08_SEL_IPI); - - return 0; -} - -static int rts524a_extra_init_hw(struct rtsx_pcr *pcr) -{ - rts5249_extra_init_hw(pcr); - - rtsx_pci_write_register(pcr, FUNC_FORCE_CTL, - FORCE_ASPM_L1_EN, FORCE_ASPM_L1_EN); - rtsx_pci_write_register(pcr, PM_EVENT_DEBUG, PME_DEBUG_0, PME_DEBUG_0); - rtsx_pci_write_register(pcr, LDO_VCC_CFG1, LDO_VCC_LMT_EN, - LDO_VCC_LMT_EN); - rtsx_pci_write_register(pcr, PCLK_CTL, PCLK_MODE_SEL, PCLK_MODE_SEL); - if (is_version(pcr, 0x524A, IC_VER_A)) { - rtsx_pci_write_register(pcr, LDO_DV18_CFG, - LDO_DV18_SR_MASK, LDO_DV18_SR_DF); - rtsx_pci_write_register(pcr, LDO_VCC_CFG1, - LDO_VCC_REF_TUNE_MASK, LDO_VCC_REF_1V2); - rtsx_pci_write_register(pcr, LDO_VIO_CFG, - LDO_VIO_REF_TUNE_MASK, LDO_VIO_REF_1V2); - rtsx_pci_write_register(pcr, LDO_VIO_CFG, - LDO_VIO_SR_MASK, LDO_VIO_SR_DF); - rtsx_pci_write_register(pcr, LDO_DV12S_CFG, - LDO_REF12_TUNE_MASK, LDO_REF12_TUNE_DF); - rtsx_pci_write_register(pcr, SD40_LDO_CTL1, - SD40_VIO_TUNE_MASK, SD40_VIO_TUNE_1V7); - } - - return 0; -} - -static void rts5250_set_l1off_cfg_sub_d0(struct rtsx_pcr *pcr, int active) -{ - struct rtsx_cr_option *option = &(pcr->option); - - u32 interrupt = rtsx_pci_readl(pcr, RTSX_BIPR); - int card_exist = (interrupt & SD_EXIST) | (interrupt & MS_EXIST); - int aspm_L1_1, aspm_L1_2; - u8 val = 0; - - aspm_L1_1 = rtsx_check_dev_flag(pcr, ASPM_L1_1_EN); - aspm_L1_2 = rtsx_check_dev_flag(pcr, ASPM_L1_2_EN); - - if (active) { - /* Run, latency: 60us */ - if (aspm_L1_1) - val = option->ltr_l1off_snooze_sspwrgate; - } else { - /* L1off, latency: 300us */ - if (aspm_L1_2) - val = option->ltr_l1off_sspwrgate; - } - - if (aspm_L1_1 || aspm_L1_2) { - if (rtsx_check_dev_flag(pcr, - LTR_L1SS_PWR_GATE_CHECK_CARD_EN)) { - if (card_exist) - val &= ~L1OFF_MBIAS2_EN_5250; - else - val |= L1OFF_MBIAS2_EN_5250; - } - } - rtsx_set_l1off_sub(pcr, val); -} - -static const struct pcr_ops rts524a_pcr_ops = { - .write_phy = rts524a_write_phy, - .read_phy = rts524a_read_phy, - .fetch_vendor_settings = rtsx_base_fetch_vendor_settings, - .extra_init_hw = rts524a_extra_init_hw, - .optimize_phy = rts524a_optimize_phy, - .turn_on_led = rtsx_base_turn_on_led, - .turn_off_led = rtsx_base_turn_off_led, - .enable_auto_blink = rtsx_base_enable_auto_blink, - .disable_auto_blink = rtsx_base_disable_auto_blink, - .card_power_on = rtsx_base_card_power_on, - .card_power_off = rtsx_base_card_power_off, - .switch_output_voltage = rtsx_base_switch_output_voltage, - .force_power_down = rtsx_base_force_power_down, - .set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0, - .set_aspm = rts5249_set_aspm, -}; - -void rts524a_init_params(struct rtsx_pcr *pcr) -{ - rts5249_init_params(pcr); - pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF; - pcr->option.ltr_l1off_snooze_sspwrgate = - LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF; - - pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3; - pcr->ops = &rts524a_pcr_ops; -} - -static int rts525a_card_power_on(struct rtsx_pcr *pcr, int card) -{ - rtsx_pci_write_register(pcr, LDO_VCC_CFG1, - LDO_VCC_TUNE_MASK, LDO_VCC_3V3); - return rtsx_base_card_power_on(pcr, card); -} - -static int rts525a_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) -{ - switch (voltage) { - case OUTPUT_3V3: - rtsx_pci_write_register(pcr, LDO_CONFIG2, - LDO_D3318_MASK, LDO_D3318_33V); - rtsx_pci_write_register(pcr, SD_PAD_CTL, SD_IO_USING_1V8, 0); - break; - case OUTPUT_1V8: - rtsx_pci_write_register(pcr, LDO_CONFIG2, - LDO_D3318_MASK, LDO_D3318_18V); - rtsx_pci_write_register(pcr, SD_PAD_CTL, SD_IO_USING_1V8, - SD_IO_USING_1V8); - break; - default: - return -EINVAL; - } - - rtsx_pci_init_cmd(pcr); - rts5249_fill_driving(pcr, voltage); - return rtsx_pci_send_cmd(pcr, 100); -} - -static int rts525a_optimize_phy(struct rtsx_pcr *pcr) -{ - int err; - - err = rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3, - D3_DELINK_MODE_EN, 0x00); - if (err < 0) - return err; - - rtsx_pci_write_phy_register(pcr, _PHY_FLD0, - _PHY_FLD0_CLK_REQ_20C | _PHY_FLD0_RX_IDLE_EN | - _PHY_FLD0_BIT_ERR_RSTN | _PHY_FLD0_BER_COUNT | - _PHY_FLD0_BER_TIMER | _PHY_FLD0_CHECK_EN); - - rtsx_pci_write_phy_register(pcr, _PHY_ANA03, - _PHY_ANA03_TIMER_MAX | _PHY_ANA03_OOBS_DEB_EN | - _PHY_CMU_DEBUG_EN); - - if (is_version(pcr, 0x525A, IC_VER_A)) - rtsx_pci_write_phy_register(pcr, _PHY_REV0, - _PHY_REV0_FILTER_OUT | _PHY_REV0_CDR_BYPASS_PFD | - _PHY_REV0_CDR_RX_IDLE_BYPASS); - - return 0; -} - -static int rts525a_extra_init_hw(struct rtsx_pcr *pcr) -{ - rts5249_extra_init_hw(pcr); - - rtsx_pci_write_register(pcr, PCLK_CTL, PCLK_MODE_SEL, PCLK_MODE_SEL); - if (is_version(pcr, 0x525A, IC_VER_A)) { - rtsx_pci_write_register(pcr, L1SUB_CONFIG2, - L1SUB_AUTO_CFG, L1SUB_AUTO_CFG); - rtsx_pci_write_register(pcr, RREF_CFG, - RREF_VBGSEL_MASK, RREF_VBGSEL_1V25); - rtsx_pci_write_register(pcr, LDO_VIO_CFG, - LDO_VIO_TUNE_MASK, LDO_VIO_1V7); - rtsx_pci_write_register(pcr, LDO_DV12S_CFG, - LDO_D12_TUNE_MASK, LDO_D12_TUNE_DF); - rtsx_pci_write_register(pcr, LDO_AV12S_CFG, - LDO_AV12S_TUNE_MASK, LDO_AV12S_TUNE_DF); - rtsx_pci_write_register(pcr, LDO_VCC_CFG0, - LDO_VCC_LMTVTH_MASK, LDO_VCC_LMTVTH_2A); - rtsx_pci_write_register(pcr, OOBS_CONFIG, - OOBS_AUTOK_DIS | OOBS_VAL_MASK, 0x89); - } - - return 0; -} - -static const struct pcr_ops rts525a_pcr_ops = { - .fetch_vendor_settings = rtsx_base_fetch_vendor_settings, - .extra_init_hw = rts525a_extra_init_hw, - .optimize_phy = rts525a_optimize_phy, - .turn_on_led = rtsx_base_turn_on_led, - .turn_off_led = rtsx_base_turn_off_led, - .enable_auto_blink = rtsx_base_enable_auto_blink, - .disable_auto_blink = rtsx_base_disable_auto_blink, - .card_power_on = rts525a_card_power_on, - .card_power_off = rtsx_base_card_power_off, - .switch_output_voltage = rts525a_switch_output_voltage, - .force_power_down = rtsx_base_force_power_down, - .set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0, - .set_aspm = rts5249_set_aspm, -}; - -void rts525a_init_params(struct rtsx_pcr *pcr) -{ - rts5249_init_params(pcr); - pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF; - pcr->option.ltr_l1off_snooze_sspwrgate = - LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF; - - pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3; - pcr->ops = &rts525a_pcr_ops; -} - diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c deleted file mode 100644 index 590fb9aad77d..000000000000 --- a/drivers/mfd/rtsx_pcr.c +++ /dev/null @@ -1,1569 +0,0 @@ -/* Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * 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, 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Author: - * Wei WANG - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rtsx_pcr.h" - -static bool msi_en = true; -module_param(msi_en, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(msi_en, "Enable MSI"); - -static DEFINE_IDR(rtsx_pci_idr); -static DEFINE_SPINLOCK(rtsx_pci_lock); - -static struct mfd_cell rtsx_pcr_cells[] = { - [RTSX_SD_CARD] = { - .name = DRV_NAME_RTSX_PCI_SDMMC, - }, - [RTSX_MS_CARD] = { - .name = DRV_NAME_RTSX_PCI_MS, - }, -}; - -static const struct pci_device_id rtsx_pci_ids[] = { - { PCI_DEVICE(0x10EC, 0x5209), PCI_CLASS_OTHERS << 16, 0xFF0000 }, - { PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 }, - { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 }, - { PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 }, - { PCI_DEVICE(0x10EC, 0x522A), 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 }, - { PCI_DEVICE(0x10EC, 0x524A), PCI_CLASS_OTHERS << 16, 0xFF0000 }, - { PCI_DEVICE(0x10EC, 0x525A), PCI_CLASS_OTHERS << 16, 0xFF0000 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, rtsx_pci_ids); - -static inline void rtsx_pci_enable_aspm(struct rtsx_pcr *pcr) -{ - rtsx_pci_update_cfg_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL, - 0xFC, pcr->aspm_en); -} - -static inline void rtsx_pci_disable_aspm(struct rtsx_pcr *pcr) -{ - rtsx_pci_update_cfg_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL, - 0xFC, 0); -} - -int rtsx_comm_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency) -{ - rtsx_pci_write_register(pcr, MSGTXDATA0, - MASK_8_BIT_DEF, (u8) (latency & 0xFF)); - rtsx_pci_write_register(pcr, MSGTXDATA1, - MASK_8_BIT_DEF, (u8)((latency >> 8) & 0xFF)); - rtsx_pci_write_register(pcr, MSGTXDATA2, - MASK_8_BIT_DEF, (u8)((latency >> 16) & 0xFF)); - rtsx_pci_write_register(pcr, MSGTXDATA3, - MASK_8_BIT_DEF, (u8)((latency >> 24) & 0xFF)); - rtsx_pci_write_register(pcr, LTR_CTL, LTR_TX_EN_MASK | - LTR_LATENCY_MODE_MASK, LTR_TX_EN_1 | LTR_LATENCY_MODE_SW); - - return 0; -} - -int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency) -{ - if (pcr->ops->set_ltr_latency) - return pcr->ops->set_ltr_latency(pcr, latency); - else - return rtsx_comm_set_ltr_latency(pcr, latency); -} - -static void rtsx_comm_set_aspm(struct rtsx_pcr *pcr, bool enable) -{ - struct rtsx_cr_option *option = &pcr->option; - - if (pcr->aspm_enabled == enable) - return; - - if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) { - if (enable) - rtsx_pci_enable_aspm(pcr); - else - rtsx_pci_disable_aspm(pcr); - } else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) { - u8 mask = FORCE_ASPM_VAL_MASK; - u8 val = 0; - - if (enable) - val = pcr->aspm_en; - rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val); - } - - pcr->aspm_enabled = enable; -} - -static void rtsx_disable_aspm(struct rtsx_pcr *pcr) -{ - if (pcr->ops->set_aspm) - pcr->ops->set_aspm(pcr, false); - else - rtsx_comm_set_aspm(pcr, false); -} - -int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val) -{ - rtsx_pci_write_register(pcr, L1SUB_CONFIG3, 0xFF, val); - - return 0; -} - -void rtsx_set_l1off_sub_cfg_d0(struct rtsx_pcr *pcr, int active) -{ - if (pcr->ops->set_l1off_cfg_sub_d0) - pcr->ops->set_l1off_cfg_sub_d0(pcr, active); -} - -static void rtsx_comm_pm_full_on(struct rtsx_pcr *pcr) -{ - struct rtsx_cr_option *option = &pcr->option; - - rtsx_disable_aspm(pcr); - - if (option->ltr_enabled) - rtsx_set_ltr_latency(pcr, option->ltr_active_latency); - - if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN)) - rtsx_set_l1off_sub_cfg_d0(pcr, 1); -} - -void rtsx_pm_full_on(struct rtsx_pcr *pcr) -{ - if (pcr->ops->full_on) - pcr->ops->full_on(pcr); - else - rtsx_comm_pm_full_on(pcr); -} - -void rtsx_pci_start_run(struct rtsx_pcr *pcr) -{ - /* If pci device removed, don't queue idle work any more */ - if (pcr->remove_pci) - return; - - if (pcr->state != PDEV_STAT_RUN) { - pcr->state = PDEV_STAT_RUN; - if (pcr->ops->enable_auto_blink) - pcr->ops->enable_auto_blink(pcr); - rtsx_pm_full_on(pcr); - } - - mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200)); -} -EXPORT_SYMBOL_GPL(rtsx_pci_start_run); - -int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data) -{ - int i; - u32 val = HAIMR_WRITE_START; - - val |= (u32)(addr & 0x3FFF) << 16; - val |= (u32)mask << 8; - val |= (u32)data; - - rtsx_pci_writel(pcr, RTSX_HAIMR, val); - - for (i = 0; i < MAX_RW_REG_CNT; i++) { - val = rtsx_pci_readl(pcr, RTSX_HAIMR); - if ((val & HAIMR_TRANS_END) == 0) { - if (data != (u8)val) - return -EIO; - return 0; - } - } - - return -ETIMEDOUT; -} -EXPORT_SYMBOL_GPL(rtsx_pci_write_register); - -int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data) -{ - u32 val = HAIMR_READ_START; - int i; - - val |= (u32)(addr & 0x3FFF) << 16; - rtsx_pci_writel(pcr, RTSX_HAIMR, val); - - for (i = 0; i < MAX_RW_REG_CNT; i++) { - val = rtsx_pci_readl(pcr, RTSX_HAIMR); - if ((val & HAIMR_TRANS_END) == 0) - break; - } - - if (i >= MAX_RW_REG_CNT) - return -ETIMEDOUT; - - if (data) - *data = (u8)(val & 0xFF); - - return 0; -} -EXPORT_SYMBOL_GPL(rtsx_pci_read_register); - -int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val) -{ - int err, i, finished = 0; - u8 tmp; - - rtsx_pci_init_cmd(pcr); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA0, 0xFF, (u8)val); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA1, 0xFF, (u8)(val >> 8)); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x81); - - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - for (i = 0; i < 100000; i++) { - err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp); - if (err < 0) - return err; - - if (!(tmp & 0x80)) { - finished = 1; - break; - } - } - - if (!finished) - return -ETIMEDOUT; - - return 0; -} - -int rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val) -{ - if (pcr->ops->write_phy) - return pcr->ops->write_phy(pcr, addr, val); - - return __rtsx_pci_write_phy_register(pcr, addr, val); -} -EXPORT_SYMBOL_GPL(rtsx_pci_write_phy_register); - -int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val) -{ - int err, i, finished = 0; - u16 data; - u8 *ptr, tmp; - - rtsx_pci_init_cmd(pcr); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x80); - - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - for (i = 0; i < 100000; i++) { - err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp); - if (err < 0) - return err; - - if (!(tmp & 0x80)) { - finished = 1; - break; - } - } - - if (!finished) - return -ETIMEDOUT; - - rtsx_pci_init_cmd(pcr); - - rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA0, 0, 0); - rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA1, 0, 0); - - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - ptr = rtsx_pci_get_cmd_data(pcr); - data = ((u16)ptr[1] << 8) | ptr[0]; - - if (val) - *val = data; - - return 0; -} - -int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val) -{ - if (pcr->ops->read_phy) - return pcr->ops->read_phy(pcr, addr, val); - - return __rtsx_pci_read_phy_register(pcr, addr, val); -} -EXPORT_SYMBOL_GPL(rtsx_pci_read_phy_register); - -void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr) -{ - rtsx_pci_writel(pcr, RTSX_HCBCTLR, STOP_CMD); - rtsx_pci_writel(pcr, RTSX_HDBCTLR, STOP_DMA); - - rtsx_pci_write_register(pcr, DMACTL, 0x80, 0x80); - rtsx_pci_write_register(pcr, RBCTL, 0x80, 0x80); -} -EXPORT_SYMBOL_GPL(rtsx_pci_stop_cmd); - -void rtsx_pci_add_cmd(struct rtsx_pcr *pcr, - u8 cmd_type, u16 reg_addr, u8 mask, u8 data) -{ - unsigned long flags; - u32 val = 0; - u32 *ptr = (u32 *)(pcr->host_cmds_ptr); - - val |= (u32)(cmd_type & 0x03) << 30; - val |= (u32)(reg_addr & 0x3FFF) << 16; - val |= (u32)mask << 8; - val |= (u32)data; - - spin_lock_irqsave(&pcr->lock, flags); - ptr += pcr->ci; - if (pcr->ci < (HOST_CMDS_BUF_LEN / 4)) { - put_unaligned_le32(val, ptr); - ptr++; - pcr->ci++; - } - spin_unlock_irqrestore(&pcr->lock, flags); -} -EXPORT_SYMBOL_GPL(rtsx_pci_add_cmd); - -void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr) -{ - u32 val = 1 << 31; - - rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); - - val |= (u32)(pcr->ci * 4) & 0x00FFFFFF; - /* Hardware Auto Response */ - val |= 0x40000000; - rtsx_pci_writel(pcr, RTSX_HCBCTLR, val); -} -EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd_no_wait); - -int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout) -{ - struct completion trans_done; - u32 val = 1 << 31; - long timeleft; - unsigned long flags; - int err = 0; - - spin_lock_irqsave(&pcr->lock, flags); - - /* set up data structures for the wakeup system */ - pcr->done = &trans_done; - pcr->trans_result = TRANS_NOT_READY; - init_completion(&trans_done); - - rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); - - val |= (u32)(pcr->ci * 4) & 0x00FFFFFF; - /* Hardware Auto Response */ - val |= 0x40000000; - rtsx_pci_writel(pcr, RTSX_HCBCTLR, val); - - spin_unlock_irqrestore(&pcr->lock, flags); - - /* Wait for TRANS_OK_INT */ - timeleft = wait_for_completion_interruptible_timeout( - &trans_done, msecs_to_jiffies(timeout)); - if (timeleft <= 0) { - pcr_dbg(pcr, "Timeout (%s %d)\n", __func__, __LINE__); - err = -ETIMEDOUT; - goto finish_send_cmd; - } - - spin_lock_irqsave(&pcr->lock, flags); - if (pcr->trans_result == TRANS_RESULT_FAIL) - err = -EINVAL; - else if (pcr->trans_result == TRANS_RESULT_OK) - err = 0; - else if (pcr->trans_result == TRANS_NO_DEVICE) - err = -ENODEV; - spin_unlock_irqrestore(&pcr->lock, flags); - -finish_send_cmd: - spin_lock_irqsave(&pcr->lock, flags); - pcr->done = NULL; - spin_unlock_irqrestore(&pcr->lock, flags); - - if ((err < 0) && (err != -ENODEV)) - rtsx_pci_stop_cmd(pcr); - - if (pcr->finish_me) - complete(pcr->finish_me); - - return err; -} -EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd); - -static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr, - dma_addr_t addr, unsigned int len, int end) -{ - u64 *ptr = (u64 *)(pcr->host_sg_tbl_ptr) + pcr->sgi; - u64 val; - u8 option = SG_VALID | SG_TRANS_DATA; - - pcr_dbg(pcr, "DMA addr: 0x%x, Len: 0x%x\n", (unsigned int)addr, len); - - if (end) - option |= SG_END; - val = ((u64)addr << 32) | ((u64)len << 12) | option; - - put_unaligned_le64(val, ptr); - pcr->sgi++; -} - -int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, - int num_sg, bool read, int timeout) -{ - int err = 0, count; - - pcr_dbg(pcr, "--> %s: num_sg = %d\n", __func__, num_sg); - count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read); - if (count < 1) - return -EINVAL; - pcr_dbg(pcr, "DMA mapping count: %d\n", count); - - err = rtsx_pci_dma_transfer(pcr, sglist, count, read, timeout); - - rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read); - - return err; -} -EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data); - -int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist, - int num_sg, bool read) -{ - enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - - if (pcr->remove_pci) - return -EINVAL; - - if ((sglist == NULL) || (num_sg <= 0)) - return -EINVAL; - - return dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dir); -} -EXPORT_SYMBOL_GPL(rtsx_pci_dma_map_sg); - -void rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist, - int num_sg, bool read) -{ - enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - - dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dir); -} -EXPORT_SYMBOL_GPL(rtsx_pci_dma_unmap_sg); - -int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist, - int count, bool read, int timeout) -{ - struct completion trans_done; - struct scatterlist *sg; - dma_addr_t addr; - long timeleft; - unsigned long flags; - unsigned int len; - int i, err = 0; - u32 val; - u8 dir = read ? DEVICE_TO_HOST : HOST_TO_DEVICE; - - if (pcr->remove_pci) - return -ENODEV; - - if ((sglist == NULL) || (count < 1)) - return -EINVAL; - - val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE; - pcr->sgi = 0; - for_each_sg(sglist, sg, count, i) { - addr = sg_dma_address(sg); - len = sg_dma_len(sg); - rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1); - } - - spin_lock_irqsave(&pcr->lock, flags); - - pcr->done = &trans_done; - pcr->trans_result = TRANS_NOT_READY; - init_completion(&trans_done); - rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr); - rtsx_pci_writel(pcr, RTSX_HDBCTLR, val); - - spin_unlock_irqrestore(&pcr->lock, flags); - - timeleft = wait_for_completion_interruptible_timeout( - &trans_done, msecs_to_jiffies(timeout)); - if (timeleft <= 0) { - pcr_dbg(pcr, "Timeout (%s %d)\n", __func__, __LINE__); - err = -ETIMEDOUT; - goto out; - } - - spin_lock_irqsave(&pcr->lock, flags); - if (pcr->trans_result == TRANS_RESULT_FAIL) { - err = -EILSEQ; - if (pcr->dma_error_count < RTS_MAX_TIMES_FREQ_REDUCTION) - pcr->dma_error_count++; - } - - else if (pcr->trans_result == TRANS_NO_DEVICE) - err = -ENODEV; - spin_unlock_irqrestore(&pcr->lock, flags); - -out: - spin_lock_irqsave(&pcr->lock, flags); - pcr->done = NULL; - spin_unlock_irqrestore(&pcr->lock, flags); - - if ((err < 0) && (err != -ENODEV)) - rtsx_pci_stop_cmd(pcr); - - if (pcr->finish_me) - complete(pcr->finish_me); - - return err; -} -EXPORT_SYMBOL_GPL(rtsx_pci_dma_transfer); - -int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len) -{ - int err; - int i, j; - u16 reg; - u8 *ptr; - - if (buf_len > 512) - buf_len = 512; - - ptr = buf; - reg = PPBUF_BASE2; - for (i = 0; i < buf_len / 256; i++) { - rtsx_pci_init_cmd(pcr); - - for (j = 0; j < 256; j++) - rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0); - - err = rtsx_pci_send_cmd(pcr, 250); - if (err < 0) - return err; - - memcpy(ptr, rtsx_pci_get_cmd_data(pcr), 256); - ptr += 256; - } - - if (buf_len % 256) { - rtsx_pci_init_cmd(pcr); - - for (j = 0; j < buf_len % 256; j++) - rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0); - - err = rtsx_pci_send_cmd(pcr, 250); - if (err < 0) - return err; - } - - memcpy(ptr, rtsx_pci_get_cmd_data(pcr), buf_len % 256); - - return 0; -} -EXPORT_SYMBOL_GPL(rtsx_pci_read_ppbuf); - -int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len) -{ - int err; - int i, j; - u16 reg; - u8 *ptr; - - if (buf_len > 512) - buf_len = 512; - - ptr = buf; - reg = PPBUF_BASE2; - for (i = 0; i < buf_len / 256; i++) { - rtsx_pci_init_cmd(pcr); - - for (j = 0; j < 256; j++) { - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - reg++, 0xFF, *ptr); - ptr++; - } - - err = rtsx_pci_send_cmd(pcr, 250); - if (err < 0) - return err; - } - - if (buf_len % 256) { - rtsx_pci_init_cmd(pcr); - - for (j = 0; j < buf_len % 256; j++) { - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - reg++, 0xFF, *ptr); - ptr++; - } - - err = rtsx_pci_send_cmd(pcr, 250); - if (err < 0) - return err; - } - - return 0; -} -EXPORT_SYMBOL_GPL(rtsx_pci_write_ppbuf); - -static int rtsx_pci_set_pull_ctl(struct rtsx_pcr *pcr, const u32 *tbl) -{ - rtsx_pci_init_cmd(pcr); - - while (*tbl & 0xFFFF0000) { - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - (u16)(*tbl >> 16), 0xFF, (u8)(*tbl)); - tbl++; - } - - return rtsx_pci_send_cmd(pcr, 100); -} - -int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card) -{ - const u32 *tbl; - - if (card == RTSX_SD_CARD) - tbl = pcr->sd_pull_ctl_enable_tbl; - else if (card == RTSX_MS_CARD) - tbl = pcr->ms_pull_ctl_enable_tbl; - else - return -EINVAL; - - return rtsx_pci_set_pull_ctl(pcr, tbl); -} -EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_enable); - -int rtsx_pci_card_pull_ctl_disable(struct rtsx_pcr *pcr, int card) -{ - const u32 *tbl; - - if (card == RTSX_SD_CARD) - tbl = pcr->sd_pull_ctl_disable_tbl; - else if (card == RTSX_MS_CARD) - tbl = pcr->ms_pull_ctl_disable_tbl; - else - return -EINVAL; - - - return rtsx_pci_set_pull_ctl(pcr, tbl); -} -EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_disable); - -static void rtsx_pci_enable_bus_int(struct rtsx_pcr *pcr) -{ - pcr->bier = TRANS_OK_INT_EN | TRANS_FAIL_INT_EN | SD_INT_EN; - - if (pcr->num_slots > 1) - pcr->bier |= MS_INT_EN; - - /* Enable Bus Interrupt */ - rtsx_pci_writel(pcr, RTSX_BIER, pcr->bier); - - pcr_dbg(pcr, "RTSX_BIER: 0x%08x\n", pcr->bier); -} - -static inline u8 double_ssc_depth(u8 depth) -{ - return ((depth > 1) ? (depth - 1) : depth); -} - -static u8 revise_ssc_depth(u8 ssc_depth, u8 div) -{ - if (div > CLK_DIV_1) { - if (ssc_depth > (div - 1)) - ssc_depth -= (div - 1); - else - ssc_depth = SSC_DEPTH_4M; - } - - return ssc_depth; -} - -int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock, - u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk) -{ - int err, clk; - u8 n, clk_divider, mcu_cnt, div; - static const u8 depth[] = { - [RTSX_SSC_DEPTH_4M] = SSC_DEPTH_4M, - [RTSX_SSC_DEPTH_2M] = SSC_DEPTH_2M, - [RTSX_SSC_DEPTH_1M] = SSC_DEPTH_1M, - [RTSX_SSC_DEPTH_500K] = SSC_DEPTH_500K, - [RTSX_SSC_DEPTH_250K] = SSC_DEPTH_250K, - }; - - if (initial_mode) { - /* We use 250k(around) here, in initial stage */ - clk_divider = SD_CLK_DIVIDE_128; - card_clock = 30000000; - } else { - clk_divider = SD_CLK_DIVIDE_0; - } - err = rtsx_pci_write_register(pcr, SD_CFG1, - SD_CLK_DIVIDE_MASK, clk_divider); - if (err < 0) - return err; - - /* Reduce card clock by 20MHz each time a DMA transfer error occurs */ - if (card_clock == UHS_SDR104_MAX_DTR && - pcr->dma_error_count && - PCI_PID(pcr) == RTS5227_DEVICE_ID) - card_clock = UHS_SDR104_MAX_DTR - - (pcr->dma_error_count * 20000000); - - card_clock /= 1000000; - pcr_dbg(pcr, "Switch card clock to %dMHz\n", card_clock); - - clk = card_clock; - if (!initial_mode && double_clk) - clk = card_clock * 2; - pcr_dbg(pcr, "Internal SSC clock: %dMHz (cur_clock = %d)\n", - clk, pcr->cur_clock); - - if (clk == pcr->cur_clock) - return 0; - - if (pcr->ops->conv_clk_and_div_n) - n = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N); - else - n = (u8)(clk - 2); - if ((clk <= 2) || (n > MAX_DIV_N_PCR)) - return -EINVAL; - - mcu_cnt = (u8)(125/clk + 3); - if (mcu_cnt > 15) - mcu_cnt = 15; - - /* Make sure that the SSC clock div_n is not less than MIN_DIV_N_PCR */ - div = CLK_DIV_1; - while ((n < MIN_DIV_N_PCR) && (div < CLK_DIV_8)) { - if (pcr->ops->conv_clk_and_div_n) { - int dbl_clk = pcr->ops->conv_clk_and_div_n(n, - DIV_N_TO_CLK) * 2; - n = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk, - CLK_TO_DIV_N); - } else { - n = (n + 2) * 2 - 2; - } - div++; - } - pcr_dbg(pcr, "n = %d, div = %d\n", n, div); - - ssc_depth = depth[ssc_depth]; - if (double_clk) - ssc_depth = double_ssc_depth(ssc_depth); - - ssc_depth = revise_ssc_depth(ssc_depth, div); - pcr_dbg(pcr, "ssc_depth = %d\n", ssc_depth); - - rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, - CLK_LOW_FREQ, CLK_LOW_FREQ); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV, - 0xFF, (div << 4) | mcu_cnt); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, - SSC_DEPTH_MASK, ssc_depth); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB); - if (vpclk) { - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, - PHASE_NOT_RESET, 0); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, - PHASE_NOT_RESET, PHASE_NOT_RESET); - } - - err = rtsx_pci_send_cmd(pcr, 2000); - if (err < 0) - return err; - - /* Wait SSC clock stable */ - udelay(10); - err = rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0); - if (err < 0) - return err; - - pcr->cur_clock = clk; - return 0; -} -EXPORT_SYMBOL_GPL(rtsx_pci_switch_clock); - -int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card) -{ - if (pcr->ops->card_power_on) - return pcr->ops->card_power_on(pcr, card); - - return 0; -} -EXPORT_SYMBOL_GPL(rtsx_pci_card_power_on); - -int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card) -{ - if (pcr->ops->card_power_off) - return pcr->ops->card_power_off(pcr, card); - - return 0; -} -EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off); - -int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card) -{ - static const unsigned int cd_mask[] = { - [RTSX_SD_CARD] = SD_EXIST, - [RTSX_MS_CARD] = MS_EXIST - }; - - if (!(pcr->flags & PCR_MS_PMOS)) { - /* When using single PMOS, accessing card is not permitted - * if the existing card is not the designated one. - */ - if (pcr->card_exist & (~cd_mask[card])) - return -EIO; - } - - return 0; -} -EXPORT_SYMBOL_GPL(rtsx_pci_card_exclusive_check); - -int rtsx_pci_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) -{ - if (pcr->ops->switch_output_voltage) - return pcr->ops->switch_output_voltage(pcr, voltage); - - return 0; -} -EXPORT_SYMBOL_GPL(rtsx_pci_switch_output_voltage); - -unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr) -{ - unsigned int val; - - val = rtsx_pci_readl(pcr, RTSX_BIPR); - if (pcr->ops->cd_deglitch) - val = pcr->ops->cd_deglitch(pcr); - - return val; -} -EXPORT_SYMBOL_GPL(rtsx_pci_card_exist); - -void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr) -{ - struct completion finish; - - pcr->finish_me = &finish; - init_completion(&finish); - - if (pcr->done) - complete(pcr->done); - - if (!pcr->remove_pci) - rtsx_pci_stop_cmd(pcr); - - wait_for_completion_interruptible_timeout(&finish, - msecs_to_jiffies(2)); - pcr->finish_me = NULL; -} -EXPORT_SYMBOL_GPL(rtsx_pci_complete_unfinished_transfer); - -static void rtsx_pci_card_detect(struct work_struct *work) -{ - struct delayed_work *dwork; - struct rtsx_pcr *pcr; - unsigned long flags; - unsigned int card_detect = 0, card_inserted, card_removed; - u32 irq_status; - - dwork = to_delayed_work(work); - pcr = container_of(dwork, struct rtsx_pcr, carddet_work); - - pcr_dbg(pcr, "--> %s\n", __func__); - - mutex_lock(&pcr->pcr_mutex); - spin_lock_irqsave(&pcr->lock, flags); - - irq_status = rtsx_pci_readl(pcr, RTSX_BIPR); - pcr_dbg(pcr, "irq_status: 0x%08x\n", irq_status); - - irq_status &= CARD_EXIST; - card_inserted = pcr->card_inserted & irq_status; - card_removed = pcr->card_removed; - pcr->card_inserted = 0; - pcr->card_removed = 0; - - spin_unlock_irqrestore(&pcr->lock, flags); - - if (card_inserted || card_removed) { - pcr_dbg(pcr, "card_inserted: 0x%x, card_removed: 0x%x\n", - card_inserted, card_removed); - - if (pcr->ops->cd_deglitch) - card_inserted = pcr->ops->cd_deglitch(pcr); - - card_detect = card_inserted | card_removed; - - pcr->card_exist |= card_inserted; - pcr->card_exist &= ~card_removed; - } - - mutex_unlock(&pcr->pcr_mutex); - - if ((card_detect & SD_EXIST) && pcr->slots[RTSX_SD_CARD].card_event) - pcr->slots[RTSX_SD_CARD].card_event( - pcr->slots[RTSX_SD_CARD].p_dev); - if ((card_detect & MS_EXIST) && pcr->slots[RTSX_MS_CARD].card_event) - pcr->slots[RTSX_MS_CARD].card_event( - pcr->slots[RTSX_MS_CARD].p_dev); -} - -static irqreturn_t rtsx_pci_isr(int irq, void *dev_id) -{ - struct rtsx_pcr *pcr = dev_id; - u32 int_reg; - - if (!pcr) - return IRQ_NONE; - - spin_lock(&pcr->lock); - - int_reg = rtsx_pci_readl(pcr, RTSX_BIPR); - /* Clear interrupt flag */ - rtsx_pci_writel(pcr, RTSX_BIPR, int_reg); - if ((int_reg & pcr->bier) == 0) { - spin_unlock(&pcr->lock); - return IRQ_NONE; - } - if (int_reg == 0xFFFFFFFF) { - spin_unlock(&pcr->lock); - return IRQ_HANDLED; - } - - int_reg &= (pcr->bier | 0x7FFFFF); - - if (int_reg & SD_INT) { - if (int_reg & SD_EXIST) { - pcr->card_inserted |= SD_EXIST; - } else { - pcr->card_removed |= SD_EXIST; - pcr->card_inserted &= ~SD_EXIST; - } - pcr->dma_error_count = 0; - } - - if (int_reg & MS_INT) { - if (int_reg & MS_EXIST) { - pcr->card_inserted |= MS_EXIST; - } else { - pcr->card_removed |= MS_EXIST; - pcr->card_inserted &= ~MS_EXIST; - } - } - - if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) { - if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) { - pcr->trans_result = TRANS_RESULT_FAIL; - if (pcr->done) - complete(pcr->done); - } else if (int_reg & TRANS_OK_INT) { - pcr->trans_result = TRANS_RESULT_OK; - if (pcr->done) - complete(pcr->done); - } - } - - if (pcr->card_inserted || pcr->card_removed) - schedule_delayed_work(&pcr->carddet_work, - msecs_to_jiffies(200)); - - spin_unlock(&pcr->lock); - return IRQ_HANDLED; -} - -static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr) -{ - pcr_dbg(pcr, "%s: pcr->msi_en = %d, pci->irq = %d\n", - __func__, pcr->msi_en, pcr->pci->irq); - - if (request_irq(pcr->pci->irq, rtsx_pci_isr, - pcr->msi_en ? 0 : IRQF_SHARED, - DRV_NAME_RTSX_PCI, pcr)) { - dev_err(&(pcr->pci->dev), - "rtsx_sdmmc: unable to grab IRQ %d, disabling device\n", - pcr->pci->irq); - return -1; - } - - pcr->irq = pcr->pci->irq; - pci_intx(pcr->pci, !pcr->msi_en); - - return 0; -} - -static void rtsx_enable_aspm(struct rtsx_pcr *pcr) -{ - if (pcr->ops->set_aspm) - pcr->ops->set_aspm(pcr, true); - else - rtsx_comm_set_aspm(pcr, true); -} - -static void rtsx_comm_pm_power_saving(struct rtsx_pcr *pcr) -{ - struct rtsx_cr_option *option = &pcr->option; - - if (option->ltr_enabled) { - u32 latency = option->ltr_l1off_latency; - - if (rtsx_check_dev_flag(pcr, L1_SNOOZE_TEST_EN)) - mdelay(option->l1_snooze_delay); - - rtsx_set_ltr_latency(pcr, latency); - } - - if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN)) - rtsx_set_l1off_sub_cfg_d0(pcr, 0); - - rtsx_enable_aspm(pcr); -} - -void rtsx_pm_power_saving(struct rtsx_pcr *pcr) -{ - if (pcr->ops->power_saving) - pcr->ops->power_saving(pcr); - else - rtsx_comm_pm_power_saving(pcr); -} - -static void rtsx_pci_idle_work(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work); - - pcr_dbg(pcr, "--> %s\n", __func__); - - mutex_lock(&pcr->pcr_mutex); - - pcr->state = PDEV_STAT_IDLE; - - if (pcr->ops->disable_auto_blink) - pcr->ops->disable_auto_blink(pcr); - if (pcr->ops->turn_off_led) - pcr->ops->turn_off_led(pcr); - - rtsx_pm_power_saving(pcr); - - mutex_unlock(&pcr->pcr_mutex); -} - -#ifdef CONFIG_PM -static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state) -{ - if (pcr->ops->turn_off_led) - pcr->ops->turn_off_led(pcr); - - rtsx_pci_writel(pcr, RTSX_BIER, 0); - pcr->bier = 0; - - rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08); - rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state); - - if (pcr->ops->force_power_down) - pcr->ops->force_power_down(pcr, pm_state); -} -#endif - -static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) -{ - int err; - - pcr->pcie_cap = pci_find_capability(pcr->pci, PCI_CAP_ID_EXP); - rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); - - rtsx_pci_enable_bus_int(pcr); - - /* Power on SSC */ - err = rtsx_pci_write_register(pcr, FPDCTL, SSC_POWER_DOWN, 0); - if (err < 0) - return err; - - /* Wait SSC power stable */ - udelay(200); - - rtsx_pci_disable_aspm(pcr); - if (pcr->ops->optimize_phy) { - err = pcr->ops->optimize_phy(pcr); - if (err < 0) - return err; - } - - rtsx_pci_init_cmd(pcr); - - /* Set mcu_cnt to 7 to ensure data can be sampled properly */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV, 0x07, 0x07); - - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, HOST_SLEEP_STATE, 0x03, 0x00); - /* Disable card clock */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, 0x1E, 0); - /* Reset delink mode */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x0A, 0); - /* Card driving select */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DRIVE_SEL, - 0xFF, pcr->card_drive_sel); - /* Enable SSC Clock */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, - 0xFF, SSC_8X_EN | SSC_SEL_4M); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF, 0x12); - /* Disable cd_pwr_save */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x16, 0x10); - /* Clear Link Ready Interrupt */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, - LINK_RDY_INT, LINK_RDY_INT); - /* Enlarge the estimation window of PERST# glitch - * to reduce the chance of invalid card interrupt - */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PERST_GLITCH_WIDTH, 0xFF, 0x80); - /* Update RC oscillator to 400k - * bit[0] F_HIGH: for RC oscillator, Rst_value is 1'b1 - * 1: 2M 0: 400k - */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RCCTL, 0x01, 0x00); - /* Set interrupt write clear - * bit 1: U_elbi_if_rd_clr_en - * 1: Enable ELBI interrupt[31:22] & [7:0] flag read clear - * 0: ELBI interrupt flag[31:22] & [7:0] only can be write clear - */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, NFTS_TX_CTRL, 0x02, 0); - - err = rtsx_pci_send_cmd(pcr, 100); - if (err < 0) - return err; - - switch (PCI_PID(pcr)) { - case PID_5250: - case PID_524A: - case PID_525A: - rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 1, 1); - break; - default: - break; - } - - /* Enable clk_request_n to enable clock power management */ - rtsx_pci_write_config_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL + 1, 1); - /* Enter L1 when host tx idle */ - rtsx_pci_write_config_byte(pcr, 0x70F, 0x5B); - - if (pcr->ops->extra_init_hw) { - err = pcr->ops->extra_init_hw(pcr); - if (err < 0) - return err; - } - - /* No CD interrupt if probing driver with card inserted. - * So we need to initialize pcr->card_exist here. - */ - if (pcr->ops->cd_deglitch) - pcr->card_exist = pcr->ops->cd_deglitch(pcr); - else - pcr->card_exist = rtsx_pci_readl(pcr, RTSX_BIPR) & CARD_EXIST; - - return 0; -} - -static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) -{ - int err; - - spin_lock_init(&pcr->lock); - mutex_init(&pcr->pcr_mutex); - - switch (PCI_PID(pcr)) { - default: - case 0x5209: - rts5209_init_params(pcr); - break; - - case 0x5229: - rts5229_init_params(pcr); - break; - - case 0x5289: - rtl8411_init_params(pcr); - break; - - case 0x5227: - rts5227_init_params(pcr); - break; - - case 0x522A: - rts522a_init_params(pcr); - break; - - case 0x5249: - rts5249_init_params(pcr); - break; - - case 0x524A: - rts524a_init_params(pcr); - break; - - case 0x525A: - rts525a_init_params(pcr); - break; - - case 0x5287: - rtl8411b_init_params(pcr); - break; - - case 0x5286: - rtl8402_init_params(pcr); - break; - } - - pcr_dbg(pcr, "PID: 0x%04x, IC version: 0x%02x\n", - PCI_PID(pcr), pcr->ic_version); - - pcr->slots = kcalloc(pcr->num_slots, sizeof(struct rtsx_slot), - GFP_KERNEL); - if (!pcr->slots) - return -ENOMEM; - - if (pcr->ops->fetch_vendor_settings) - pcr->ops->fetch_vendor_settings(pcr); - - pcr_dbg(pcr, "pcr->aspm_en = 0x%x\n", pcr->aspm_en); - pcr_dbg(pcr, "pcr->sd30_drive_sel_1v8 = 0x%x\n", - pcr->sd30_drive_sel_1v8); - pcr_dbg(pcr, "pcr->sd30_drive_sel_3v3 = 0x%x\n", - pcr->sd30_drive_sel_3v3); - pcr_dbg(pcr, "pcr->card_drive_sel = 0x%x\n", - pcr->card_drive_sel); - pcr_dbg(pcr, "pcr->flags = 0x%x\n", pcr->flags); - - pcr->state = PDEV_STAT_IDLE; - err = rtsx_pci_init_hw(pcr); - if (err < 0) { - kfree(pcr->slots); - return err; - } - - return 0; -} - -static int rtsx_pci_probe(struct pci_dev *pcidev, - const struct pci_device_id *id) -{ - struct rtsx_pcr *pcr; - struct pcr_handle *handle; - u32 base, len; - int ret, i, bar = 0; - - dev_dbg(&(pcidev->dev), - ": Realtek PCI-E Card Reader found at %s [%04x:%04x] (rev %x)\n", - pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device, - (int)pcidev->revision); - - ret = pci_set_dma_mask(pcidev, DMA_BIT_MASK(32)); - if (ret < 0) - return ret; - - ret = pci_enable_device(pcidev); - if (ret) - return ret; - - ret = pci_request_regions(pcidev, DRV_NAME_RTSX_PCI); - if (ret) - goto disable; - - pcr = kzalloc(sizeof(*pcr), GFP_KERNEL); - if (!pcr) { - ret = -ENOMEM; - goto release_pci; - } - - handle = kzalloc(sizeof(*handle), GFP_KERNEL); - if (!handle) { - ret = -ENOMEM; - goto free_pcr; - } - handle->pcr = pcr; - - idr_preload(GFP_KERNEL); - spin_lock(&rtsx_pci_lock); - ret = idr_alloc(&rtsx_pci_idr, pcr, 0, 0, GFP_NOWAIT); - if (ret >= 0) - pcr->id = ret; - spin_unlock(&rtsx_pci_lock); - idr_preload_end(); - if (ret < 0) - goto free_handle; - - pcr->pci = pcidev; - dev_set_drvdata(&pcidev->dev, handle); - - if (CHK_PCI_PID(pcr, 0x525A)) - bar = 1; - len = pci_resource_len(pcidev, bar); - base = pci_resource_start(pcidev, bar); - pcr->remap_addr = ioremap_nocache(base, len); - if (!pcr->remap_addr) { - ret = -ENOMEM; - goto free_handle; - } - - pcr->rtsx_resv_buf = dma_alloc_coherent(&(pcidev->dev), - RTSX_RESV_BUF_LEN, &(pcr->rtsx_resv_buf_addr), - GFP_KERNEL); - if (pcr->rtsx_resv_buf == NULL) { - ret = -ENXIO; - goto unmap; - } - pcr->host_cmds_ptr = pcr->rtsx_resv_buf; - pcr->host_cmds_addr = pcr->rtsx_resv_buf_addr; - pcr->host_sg_tbl_ptr = pcr->rtsx_resv_buf + HOST_CMDS_BUF_LEN; - pcr->host_sg_tbl_addr = pcr->rtsx_resv_buf_addr + HOST_CMDS_BUF_LEN; - - pcr->card_inserted = 0; - pcr->card_removed = 0; - INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect); - INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work); - - pcr->msi_en = msi_en; - if (pcr->msi_en) { - ret = pci_enable_msi(pcidev); - if (ret) - pcr->msi_en = false; - } - - ret = rtsx_pci_acquire_irq(pcr); - if (ret < 0) - goto disable_msi; - - pci_set_master(pcidev); - synchronize_irq(pcr->irq); - - ret = rtsx_pci_init_chip(pcr); - if (ret < 0) - goto disable_irq; - - for (i = 0; i < ARRAY_SIZE(rtsx_pcr_cells); i++) { - rtsx_pcr_cells[i].platform_data = handle; - rtsx_pcr_cells[i].pdata_size = sizeof(*handle); - } - ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells, - ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL); - if (ret < 0) - goto disable_irq; - - schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200)); - - return 0; - -disable_irq: - free_irq(pcr->irq, (void *)pcr); -disable_msi: - if (pcr->msi_en) - pci_disable_msi(pcr->pci); - dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, - pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); -unmap: - iounmap(pcr->remap_addr); -free_handle: - kfree(handle); -free_pcr: - kfree(pcr); -release_pci: - pci_release_regions(pcidev); -disable: - pci_disable_device(pcidev); - - return ret; -} - -static void rtsx_pci_remove(struct pci_dev *pcidev) -{ - struct pcr_handle *handle = pci_get_drvdata(pcidev); - struct rtsx_pcr *pcr = handle->pcr; - - pcr->remove_pci = true; - - /* Disable interrupts at the pcr level */ - spin_lock_irq(&pcr->lock); - rtsx_pci_writel(pcr, RTSX_BIER, 0); - pcr->bier = 0; - spin_unlock_irq(&pcr->lock); - - cancel_delayed_work_sync(&pcr->carddet_work); - cancel_delayed_work_sync(&pcr->idle_work); - - mfd_remove_devices(&pcidev->dev); - - dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, - pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); - free_irq(pcr->irq, (void *)pcr); - if (pcr->msi_en) - pci_disable_msi(pcr->pci); - iounmap(pcr->remap_addr); - - pci_release_regions(pcidev); - pci_disable_device(pcidev); - - spin_lock(&rtsx_pci_lock); - idr_remove(&rtsx_pci_idr, pcr->id); - spin_unlock(&rtsx_pci_lock); - - kfree(pcr->slots); - kfree(pcr); - kfree(handle); - - dev_dbg(&(pcidev->dev), - ": Realtek PCI-E Card Reader at %s [%04x:%04x] has been removed\n", - pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device); -} - -#ifdef CONFIG_PM - -static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state) -{ - struct pcr_handle *handle; - struct rtsx_pcr *pcr; - - dev_dbg(&(pcidev->dev), "--> %s\n", __func__); - - handle = pci_get_drvdata(pcidev); - pcr = handle->pcr; - - cancel_delayed_work(&pcr->carddet_work); - cancel_delayed_work(&pcr->idle_work); - - mutex_lock(&pcr->pcr_mutex); - - rtsx_pci_power_off(pcr, HOST_ENTER_S3); - - pci_save_state(pcidev); - pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0); - pci_disable_device(pcidev); - pci_set_power_state(pcidev, pci_choose_state(pcidev, state)); - - mutex_unlock(&pcr->pcr_mutex); - return 0; -} - -static int rtsx_pci_resume(struct pci_dev *pcidev) -{ - struct pcr_handle *handle; - struct rtsx_pcr *pcr; - int ret = 0; - - dev_dbg(&(pcidev->dev), "--> %s\n", __func__); - - handle = pci_get_drvdata(pcidev); - pcr = handle->pcr; - - mutex_lock(&pcr->pcr_mutex); - - pci_set_power_state(pcidev, PCI_D0); - pci_restore_state(pcidev); - ret = pci_enable_device(pcidev); - if (ret) - goto out; - pci_set_master(pcidev); - - ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00); - if (ret) - goto out; - - ret = rtsx_pci_init_hw(pcr); - if (ret) - goto out; - - schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200)); - -out: - mutex_unlock(&pcr->pcr_mutex); - return ret; -} - -static void rtsx_pci_shutdown(struct pci_dev *pcidev) -{ - struct pcr_handle *handle; - struct rtsx_pcr *pcr; - - dev_dbg(&(pcidev->dev), "--> %s\n", __func__); - - handle = pci_get_drvdata(pcidev); - pcr = handle->pcr; - rtsx_pci_power_off(pcr, HOST_ENTER_S1); - - pci_disable_device(pcidev); -} - -#else /* CONFIG_PM */ - -#define rtsx_pci_suspend NULL -#define rtsx_pci_resume NULL -#define rtsx_pci_shutdown NULL - -#endif /* CONFIG_PM */ - -static struct pci_driver rtsx_pci_driver = { - .name = DRV_NAME_RTSX_PCI, - .id_table = rtsx_pci_ids, - .probe = rtsx_pci_probe, - .remove = rtsx_pci_remove, - .suspend = rtsx_pci_suspend, - .resume = rtsx_pci_resume, - .shutdown = rtsx_pci_shutdown, -}; -module_pci_driver(rtsx_pci_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Wei WANG "); -MODULE_DESCRIPTION("Realtek PCI-E Card Reader Driver"); diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h deleted file mode 100644 index ec784e04fe20..000000000000 --- a/drivers/mfd/rtsx_pcr.h +++ /dev/null @@ -1,103 +0,0 @@ -/* Driver for Realtek PCI-Express card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * 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, 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, see . - * - * Author: - * Wei WANG - */ - -#ifndef __RTSX_PCR_H -#define __RTSX_PCR_H - -#include - -#define MIN_DIV_N_PCR 80 -#define MAX_DIV_N_PCR 208 - -#define RTS522A_PM_CTRL3 0xFF7E - -#define RTS524A_PME_FORCE_CTL 0xFF78 -#define RTS524A_PM_CTRL3 0xFF7E - -#define LTR_ACTIVE_LATENCY_DEF 0x883C -#define LTR_IDLE_LATENCY_DEF 0x892C -#define LTR_L1OFF_LATENCY_DEF 0x9003 -#define L1_SNOOZE_DELAY_DEF 1 -#define LTR_L1OFF_SSPWRGATE_5249_DEF 0xAF -#define LTR_L1OFF_SSPWRGATE_5250_DEF 0xFF -#define LTR_L1OFF_SNOOZE_SSPWRGATE_5249_DEF 0xAC -#define LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF 0xF8 -#define CMD_TIMEOUT_DEF 100 -#define ASPM_MASK_NEG 0xFC -#define MASK_8_BIT_DEF 0xFF - -int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val); -int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val); - -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 rts522a_init_params(struct rtsx_pcr *pcr); -void rts5249_init_params(struct rtsx_pcr *pcr); -void rts524a_init_params(struct rtsx_pcr *pcr); -void rts525a_init_params(struct rtsx_pcr *pcr); -void rtl8411b_init_params(struct rtsx_pcr *pcr); - -static inline u8 map_sd_drive(int idx) -{ - u8 sd_drive[4] = { - 0x01, /* Type D */ - 0x02, /* Type C */ - 0x05, /* Type A */ - 0x03 /* Type B */ - }; - - return sd_drive[idx]; -} - -#define rtsx_vendor_setting_valid(reg) (!((reg) & 0x1000000)) -#define rts5209_vendor_setting1_valid(reg) (!((reg) & 0x80)) -#define rts5209_vendor_setting2_valid(reg) ((reg) & 0x80) - -#define rtsx_reg_to_aspm(reg) (((reg) >> 28) & 0x03) -#define rtsx_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 26) & 0x03) -#define rtsx_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 5) & 0x03) -#define rtsx_reg_to_card_drive_sel(reg) ((((reg) >> 25) & 0x01) << 6) -#define rtsx_reg_check_reverse_socket(reg) ((reg) & 0x4000) -#define rts5209_reg_to_aspm(reg) (((reg) >> 5) & 0x03) -#define rts5209_reg_check_ms_pmos(reg) (!((reg) & 0x08)) -#define rts5209_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 3) & 0x07) -#define rts5209_reg_to_sd30_drive_sel_3v3(reg) ((reg) & 0x07) -#define rts5209_reg_to_card_drive_sel(reg) ((reg) >> 8) -#define rtl8411_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 5) & 0x07) -#define rtl8411b_reg_to_sd30_drive_sel_3v3(reg) ((reg) & 0x03) - -#define set_pull_ctrl_tables(pcr, __device) \ -do { \ - pcr->sd_pull_ctl_enable_tbl = __device##_sd_pull_ctl_enable_tbl; \ - pcr->sd_pull_ctl_disable_tbl = __device##_sd_pull_ctl_disable_tbl; \ - pcr->ms_pull_ctl_enable_tbl = __device##_ms_pull_ctl_enable_tbl; \ - pcr->ms_pull_ctl_disable_tbl = __device##_ms_pull_ctl_disable_tbl; \ -} while (0) - -/* generic operations */ -int rtsx_gops_pm_reset(struct rtsx_pcr *pcr); -int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency); -int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val); - -#endif diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c deleted file mode 100644 index 59d61b04c197..000000000000 --- a/drivers/mfd/rtsx_usb.c +++ /dev/null @@ -1,791 +0,0 @@ -/* Driver for Realtek USB card reader - * - * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. - * - * 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, see . - * - * Author: - * Roger Tseng - */ -#include -#include -#include -#include -#include -#include -#include - -static int polling_pipe = 1; -module_param(polling_pipe, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(polling_pipe, "polling pipe (0: ctl, 1: bulk)"); - -static const struct mfd_cell rtsx_usb_cells[] = { - [RTSX_USB_SD_CARD] = { - .name = "rtsx_usb_sdmmc", - .pdata_size = 0, - }, - [RTSX_USB_MS_CARD] = { - .name = "rtsx_usb_ms", - .pdata_size = 0, - }, -}; - -static void rtsx_usb_sg_timed_out(struct timer_list *t) -{ - struct rtsx_ucr *ucr = from_timer(ucr, t, sg_timer); - - dev_dbg(&ucr->pusb_intf->dev, "%s: sg transfer timed out", __func__); - usb_sg_cancel(&ucr->current_sg); -} - -static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr, - unsigned int pipe, struct scatterlist *sg, int num_sg, - unsigned int length, unsigned int *act_len, int timeout) -{ - int ret; - - dev_dbg(&ucr->pusb_intf->dev, "%s: xfer %u bytes, %d entries\n", - __func__, length, num_sg); - ret = usb_sg_init(&ucr->current_sg, ucr->pusb_dev, pipe, 0, - sg, num_sg, length, GFP_NOIO); - if (ret) - return ret; - - ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout); - add_timer(&ucr->sg_timer); - usb_sg_wait(&ucr->current_sg); - if (!del_timer_sync(&ucr->sg_timer)) - ret = -ETIMEDOUT; - else - ret = ucr->current_sg.status; - - if (act_len) - *act_len = ucr->current_sg.bytes; - - return ret; -} - -int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe, - void *buf, unsigned int len, int num_sg, - unsigned int *act_len, int timeout) -{ - if (timeout < 600) - timeout = 600; - - if (num_sg) - return rtsx_usb_bulk_transfer_sglist(ucr, pipe, - (struct scatterlist *)buf, num_sg, len, act_len, - timeout); - else - return usb_bulk_msg(ucr->pusb_dev, pipe, buf, len, act_len, - timeout); -} -EXPORT_SYMBOL_GPL(rtsx_usb_transfer_data); - -static inline void rtsx_usb_seq_cmd_hdr(struct rtsx_ucr *ucr, - u16 addr, u16 len, u8 seq_type) -{ - rtsx_usb_cmd_hdr_tag(ucr); - - ucr->cmd_buf[PACKET_TYPE] = seq_type; - ucr->cmd_buf[5] = (u8)(len >> 8); - ucr->cmd_buf[6] = (u8)len; - ucr->cmd_buf[8] = (u8)(addr >> 8); - ucr->cmd_buf[9] = (u8)addr; - - if (seq_type == SEQ_WRITE) - ucr->cmd_buf[STAGE_FLAG] = 0; - else - ucr->cmd_buf[STAGE_FLAG] = STAGE_R; -} - -static int rtsx_usb_seq_write_register(struct rtsx_ucr *ucr, - u16 addr, u16 len, u8 *data) -{ - u16 cmd_len = ALIGN(SEQ_WRITE_DATA_OFFSET + len, 4); - - if (!data) - return -EINVAL; - - if (cmd_len > IOBUF_SIZE) - return -EINVAL; - - rtsx_usb_seq_cmd_hdr(ucr, addr, len, SEQ_WRITE); - memcpy(ucr->cmd_buf + SEQ_WRITE_DATA_OFFSET, data, len); - - return rtsx_usb_transfer_data(ucr, - usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT), - ucr->cmd_buf, cmd_len, 0, NULL, 100); -} - -static int rtsx_usb_seq_read_register(struct rtsx_ucr *ucr, - u16 addr, u16 len, u8 *data) -{ - int i, ret; - u16 rsp_len = round_down(len, 4); - u16 res_len = len - rsp_len; - - if (!data) - return -EINVAL; - - /* 4-byte aligned part */ - if (rsp_len) { - rtsx_usb_seq_cmd_hdr(ucr, addr, len, SEQ_READ); - ret = rtsx_usb_transfer_data(ucr, - usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT), - ucr->cmd_buf, 12, 0, NULL, 100); - if (ret) - return ret; - - ret = rtsx_usb_transfer_data(ucr, - usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN), - data, rsp_len, 0, NULL, 100); - if (ret) - return ret; - } - - /* unaligned part */ - for (i = 0; i < res_len; i++) { - ret = rtsx_usb_read_register(ucr, addr + rsp_len + i, - data + rsp_len + i); - if (ret) - return ret; - } - - return 0; -} - -int rtsx_usb_read_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len) -{ - return rtsx_usb_seq_read_register(ucr, PPBUF_BASE2, (u16)buf_len, buf); -} -EXPORT_SYMBOL_GPL(rtsx_usb_read_ppbuf); - -int rtsx_usb_write_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len) -{ - return rtsx_usb_seq_write_register(ucr, PPBUF_BASE2, (u16)buf_len, buf); -} -EXPORT_SYMBOL_GPL(rtsx_usb_write_ppbuf); - -int rtsx_usb_ep0_write_register(struct rtsx_ucr *ucr, u16 addr, - u8 mask, u8 data) -{ - u16 value, index; - - addr |= EP0_WRITE_REG_CMD << EP0_OP_SHIFT; - value = swab16(addr); - index = mask | data << 8; - - return usb_control_msg(ucr->pusb_dev, - usb_sndctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, 100); -} -EXPORT_SYMBOL_GPL(rtsx_usb_ep0_write_register); - -int rtsx_usb_ep0_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data) -{ - u16 value; - u8 *buf; - int ret; - - if (!data) - return -EINVAL; - - buf = kzalloc(sizeof(u8), GFP_KERNEL); - if (!buf) - return -ENOMEM; - - addr |= EP0_READ_REG_CMD << EP0_OP_SHIFT; - value = swab16(addr); - - ret = usb_control_msg(ucr->pusb_dev, - usb_rcvctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, 0, buf, 1, 100); - *data = *buf; - - kfree(buf); - return ret; -} -EXPORT_SYMBOL_GPL(rtsx_usb_ep0_read_register); - -void rtsx_usb_add_cmd(struct rtsx_ucr *ucr, u8 cmd_type, u16 reg_addr, - u8 mask, u8 data) -{ - int i; - - if (ucr->cmd_idx < (IOBUF_SIZE - CMD_OFFSET) / 4) { - i = CMD_OFFSET + ucr->cmd_idx * 4; - - ucr->cmd_buf[i++] = ((cmd_type & 0x03) << 6) | - (u8)((reg_addr >> 8) & 0x3F); - ucr->cmd_buf[i++] = (u8)reg_addr; - ucr->cmd_buf[i++] = mask; - ucr->cmd_buf[i++] = data; - - ucr->cmd_idx++; - } -} -EXPORT_SYMBOL_GPL(rtsx_usb_add_cmd); - -int rtsx_usb_send_cmd(struct rtsx_ucr *ucr, u8 flag, int timeout) -{ - int ret; - - ucr->cmd_buf[CNT_H] = (u8)(ucr->cmd_idx >> 8); - ucr->cmd_buf[CNT_L] = (u8)(ucr->cmd_idx); - ucr->cmd_buf[STAGE_FLAG] = flag; - - ret = rtsx_usb_transfer_data(ucr, - usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT), - ucr->cmd_buf, ucr->cmd_idx * 4 + CMD_OFFSET, - 0, NULL, timeout); - if (ret) { - rtsx_usb_clear_fsm_err(ucr); - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(rtsx_usb_send_cmd); - -int rtsx_usb_get_rsp(struct rtsx_ucr *ucr, int rsp_len, int timeout) -{ - if (rsp_len <= 0) - return -EINVAL; - - rsp_len = ALIGN(rsp_len, 4); - - return rtsx_usb_transfer_data(ucr, - usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN), - ucr->rsp_buf, rsp_len, 0, NULL, timeout); -} -EXPORT_SYMBOL_GPL(rtsx_usb_get_rsp); - -static int rtsx_usb_get_status_with_bulk(struct rtsx_ucr *ucr, u16 *status) -{ - int ret; - - rtsx_usb_init_cmd(ucr); - rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_EXIST, 0x00, 0x00); - rtsx_usb_add_cmd(ucr, READ_REG_CMD, OCPSTAT, 0x00, 0x00); - ret = rtsx_usb_send_cmd(ucr, MODE_CR, 100); - if (ret) - return ret; - - ret = rtsx_usb_get_rsp(ucr, 2, 100); - if (ret) - return ret; - - *status = ((ucr->rsp_buf[0] >> 2) & 0x0f) | - ((ucr->rsp_buf[1] & 0x03) << 4); - - return 0; -} - -int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status) -{ - int ret; - u16 *buf; - - if (!status) - return -EINVAL; - - if (polling_pipe == 0) { - buf = kzalloc(sizeof(u16), GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = usb_control_msg(ucr->pusb_dev, - usb_rcvctrlpipe(ucr->pusb_dev, 0), - RTSX_USB_REQ_POLL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, 0, buf, 2, 100); - *status = *buf; - - kfree(buf); - } else { - ret = rtsx_usb_get_status_with_bulk(ucr, status); - } - - /* usb_control_msg may return positive when success */ - if (ret < 0) - return ret; - - return 0; -} -EXPORT_SYMBOL_GPL(rtsx_usb_get_card_status); - -static int rtsx_usb_write_phy_register(struct rtsx_ucr *ucr, u8 addr, u8 val) -{ - dev_dbg(&ucr->pusb_intf->dev, "Write 0x%x to phy register 0x%x\n", - val, addr); - - rtsx_usb_init_cmd(ucr); - - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VSTAIN, 0xFF, val); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VCONTROL, 0xFF, addr & 0x0F); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VCONTROL, - 0xFF, (addr >> 4) & 0x0F); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01); - - return rtsx_usb_send_cmd(ucr, MODE_C, 100); -} - -int rtsx_usb_write_register(struct rtsx_ucr *ucr, u16 addr, u8 mask, u8 data) -{ - rtsx_usb_init_cmd(ucr); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, addr, mask, data); - return rtsx_usb_send_cmd(ucr, MODE_C, 100); -} -EXPORT_SYMBOL_GPL(rtsx_usb_write_register); - -int rtsx_usb_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data) -{ - int ret; - - if (data != NULL) - *data = 0; - - rtsx_usb_init_cmd(ucr); - rtsx_usb_add_cmd(ucr, READ_REG_CMD, addr, 0, 0); - ret = rtsx_usb_send_cmd(ucr, MODE_CR, 100); - if (ret) - return ret; - - ret = rtsx_usb_get_rsp(ucr, 1, 100); - if (ret) - return ret; - - if (data != NULL) - *data = ucr->rsp_buf[0]; - - return 0; -} -EXPORT_SYMBOL_GPL(rtsx_usb_read_register); - -static inline u8 double_ssc_depth(u8 depth) -{ - return (depth > 1) ? (depth - 1) : depth; -} - -static u8 revise_ssc_depth(u8 ssc_depth, u8 div) -{ - if (div > CLK_DIV_1) { - if (ssc_depth > div - 1) - ssc_depth -= (div - 1); - else - ssc_depth = SSC_DEPTH_2M; - } - - return ssc_depth; -} - -int rtsx_usb_switch_clock(struct rtsx_ucr *ucr, unsigned int card_clock, - u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk) -{ - int ret; - u8 n, clk_divider, mcu_cnt, div; - - if (!card_clock) { - ucr->cur_clk = 0; - return 0; - } - - if (initial_mode) { - /* We use 250k(around) here, in initial stage */ - clk_divider = SD_CLK_DIVIDE_128; - card_clock = 30000000; - } else { - clk_divider = SD_CLK_DIVIDE_0; - } - - ret = rtsx_usb_write_register(ucr, SD_CFG1, - SD_CLK_DIVIDE_MASK, clk_divider); - if (ret < 0) - return ret; - - card_clock /= 1000000; - dev_dbg(&ucr->pusb_intf->dev, - "Switch card clock to %dMHz\n", card_clock); - - if (!initial_mode && double_clk) - card_clock *= 2; - dev_dbg(&ucr->pusb_intf->dev, - "Internal SSC clock: %dMHz (cur_clk = %d)\n", - card_clock, ucr->cur_clk); - - if (card_clock == ucr->cur_clk) - return 0; - - /* Converting clock value into internal settings: n and div */ - n = card_clock - 2; - if ((card_clock <= 2) || (n > MAX_DIV_N)) - return -EINVAL; - - mcu_cnt = 60/card_clock + 3; - if (mcu_cnt > 15) - mcu_cnt = 15; - - /* Make sure that the SSC clock div_n is not less than MIN_DIV_N */ - - div = CLK_DIV_1; - while (n < MIN_DIV_N && div < CLK_DIV_4) { - n = (n + 2) * 2 - 2; - div++; - } - dev_dbg(&ucr->pusb_intf->dev, "n = %d, div = %d\n", n, div); - - if (double_clk) - ssc_depth = double_ssc_depth(ssc_depth); - - ssc_depth = revise_ssc_depth(ssc_depth, div); - dev_dbg(&ucr->pusb_intf->dev, "ssc_depth = %d\n", ssc_depth); - - rtsx_usb_init_cmd(ucr); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, - 0x3F, (div << 4) | mcu_cnt); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL2, - SSC_DEPTH_MASK, ssc_depth); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB); - if (vpclk) { - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL, - PHASE_NOT_RESET, 0); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL, - PHASE_NOT_RESET, PHASE_NOT_RESET); - } - - ret = rtsx_usb_send_cmd(ucr, MODE_C, 2000); - if (ret < 0) - return ret; - - ret = rtsx_usb_write_register(ucr, SSC_CTL1, 0xff, - SSC_RSTB | SSC_8X_EN | SSC_SEL_4M); - if (ret < 0) - return ret; - - /* Wait SSC clock stable */ - usleep_range(100, 1000); - - ret = rtsx_usb_write_register(ucr, CLK_DIV, CLK_CHANGE, 0); - if (ret < 0) - return ret; - - ucr->cur_clk = card_clock; - - return 0; -} -EXPORT_SYMBOL_GPL(rtsx_usb_switch_clock); - -int rtsx_usb_card_exclusive_check(struct rtsx_ucr *ucr, int card) -{ - int ret; - u16 val; - u16 cd_mask[] = { - [RTSX_USB_SD_CARD] = (CD_MASK & ~SD_CD), - [RTSX_USB_MS_CARD] = (CD_MASK & ~MS_CD) - }; - - ret = rtsx_usb_get_card_status(ucr, &val); - /* - * If get status fails, return 0 (ok) for the exclusive check - * and let the flow fail at somewhere else. - */ - if (ret) - return 0; - - if (val & cd_mask[card]) - return -EIO; - - return 0; -} -EXPORT_SYMBOL_GPL(rtsx_usb_card_exclusive_check); - -static int rtsx_usb_reset_chip(struct rtsx_ucr *ucr) -{ - int ret; - u8 val; - - rtsx_usb_init_cmd(ucr); - - if (CHECK_PKG(ucr, LQFP48)) { - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, - LDO3318_PWR_MASK, LDO_SUSPEND); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL, - FORCE_LDO_POWERB, FORCE_LDO_POWERB); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1, - 0x30, 0x10); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5, - 0x03, 0x01); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6, - 0x0C, 0x04); - } - - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SYS_DUMMY0, NYET_MSAK, NYET_EN); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CD_DEGLITCH_WIDTH, 0xFF, 0x08); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, - CD_DEGLITCH_EN, XD_CD_DEGLITCH_EN, 0x0); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD30_DRIVE_SEL, - SD30_DRIVE_MASK, DRIVER_TYPE_D); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, - CARD_DRIVE_SEL, SD20_DRIVE_MASK, 0x0); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG, 0xE0, 0x0); - - if (ucr->is_rts5179) - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, - CARD_PULL_CTL5, 0x03, 0x01); - - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DMA1_CTL, - EXTEND_DMA1_ASYNC_SIGNAL, EXTEND_DMA1_ASYNC_SIGNAL); - rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_INT_PEND, - XD_INT | MS_INT | SD_INT, - XD_INT | MS_INT | SD_INT); - - ret = rtsx_usb_send_cmd(ucr, MODE_C, 100); - if (ret) - return ret; - - /* config non-crystal mode */ - rtsx_usb_read_register(ucr, CFG_MODE, &val); - if ((val & XTAL_FREE) || ((val & CLK_MODE_MASK) == CLK_MODE_NON_XTAL)) { - ret = rtsx_usb_write_phy_register(ucr, 0xC2, 0x7C); - if (ret) - return ret; - } - - return 0; -} - -static int rtsx_usb_init_chip(struct rtsx_ucr *ucr) -{ - int ret; - u8 val; - - rtsx_usb_clear_fsm_err(ucr); - - /* power on SSC */ - ret = rtsx_usb_write_register(ucr, - FPDCTL, SSC_POWER_MASK, SSC_POWER_ON); - if (ret) - return ret; - - usleep_range(100, 1000); - ret = rtsx_usb_write_register(ucr, CLK_DIV, CLK_CHANGE, 0x00); - if (ret) - return ret; - - /* determine IC version */ - ret = rtsx_usb_read_register(ucr, HW_VERSION, &val); - if (ret) - return ret; - - ucr->ic_version = val & HW_VER_MASK; - - /* determine package */ - ret = rtsx_usb_read_register(ucr, CARD_SHARE_MODE, &val); - if (ret) - return ret; - - if (val & CARD_SHARE_LQFP_SEL) { - ucr->package = LQFP48; - dev_dbg(&ucr->pusb_intf->dev, "Package: LQFP48\n"); - } else { - ucr->package = QFN24; - dev_dbg(&ucr->pusb_intf->dev, "Package: QFN24\n"); - } - - /* determine IC variations */ - rtsx_usb_read_register(ucr, CFG_MODE_1, &val); - if (val & RTS5179) { - ucr->is_rts5179 = true; - dev_dbg(&ucr->pusb_intf->dev, "Device is rts5179\n"); - } else { - ucr->is_rts5179 = false; - } - - return rtsx_usb_reset_chip(ucr); -} - -static int rtsx_usb_probe(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *usb_dev = interface_to_usbdev(intf); - struct rtsx_ucr *ucr; - int ret; - - dev_dbg(&intf->dev, - ": Realtek USB Card Reader found at bus %03d address %03d\n", - usb_dev->bus->busnum, usb_dev->devnum); - - ucr = devm_kzalloc(&intf->dev, sizeof(*ucr), GFP_KERNEL); - if (!ucr) - return -ENOMEM; - - ucr->pusb_dev = usb_dev; - - ucr->iobuf = usb_alloc_coherent(ucr->pusb_dev, IOBUF_SIZE, - GFP_KERNEL, &ucr->iobuf_dma); - if (!ucr->iobuf) - return -ENOMEM; - - usb_set_intfdata(intf, ucr); - - ucr->vendor_id = id->idVendor; - ucr->product_id = id->idProduct; - ucr->cmd_buf = ucr->rsp_buf = ucr->iobuf; - - mutex_init(&ucr->dev_mutex); - - ucr->pusb_intf = intf; - - /* initialize */ - ret = rtsx_usb_init_chip(ucr); - if (ret) - goto out_init_fail; - - /* initialize USB SG transfer timer */ - timer_setup(&ucr->sg_timer, rtsx_usb_sg_timed_out, 0); - - ret = mfd_add_hotplug_devices(&intf->dev, rtsx_usb_cells, - ARRAY_SIZE(rtsx_usb_cells)); - if (ret) - goto out_init_fail; - -#ifdef CONFIG_PM - intf->needs_remote_wakeup = 1; - usb_enable_autosuspend(usb_dev); -#endif - - return 0; - -out_init_fail: - usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf, - ucr->iobuf_dma); - return ret; -} - -static void rtsx_usb_disconnect(struct usb_interface *intf) -{ - struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf); - - dev_dbg(&intf->dev, "%s called\n", __func__); - - mfd_remove_devices(&intf->dev); - - usb_set_intfdata(ucr->pusb_intf, NULL); - usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf, - ucr->iobuf_dma); -} - -#ifdef CONFIG_PM -static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct rtsx_ucr *ucr = - (struct rtsx_ucr *)usb_get_intfdata(intf); - u16 val = 0; - - dev_dbg(&intf->dev, "%s called with pm message 0x%04x\n", - __func__, message.event); - - if (PMSG_IS_AUTO(message)) { - if (mutex_trylock(&ucr->dev_mutex)) { - rtsx_usb_get_card_status(ucr, &val); - mutex_unlock(&ucr->dev_mutex); - - /* Defer the autosuspend if card exists */ - if (val & (SD_CD | MS_CD)) - return -EAGAIN; - } else { - /* There is an ongoing operation*/ - return -EAGAIN; - } - } - - return 0; -} - -static int rtsx_usb_resume(struct usb_interface *intf) -{ - return 0; -} - -static int rtsx_usb_reset_resume(struct usb_interface *intf) -{ - struct rtsx_ucr *ucr = - (struct rtsx_ucr *)usb_get_intfdata(intf); - - rtsx_usb_reset_chip(ucr); - return 0; -} - -#else /* CONFIG_PM */ - -#define rtsx_usb_suspend NULL -#define rtsx_usb_resume NULL -#define rtsx_usb_reset_resume NULL - -#endif /* CONFIG_PM */ - - -static int rtsx_usb_pre_reset(struct usb_interface *intf) -{ - struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf); - - mutex_lock(&ucr->dev_mutex); - return 0; -} - -static int rtsx_usb_post_reset(struct usb_interface *intf) -{ - struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf); - - mutex_unlock(&ucr->dev_mutex); - return 0; -} - -static struct usb_device_id rtsx_usb_usb_ids[] = { - { USB_DEVICE(0x0BDA, 0x0129) }, - { USB_DEVICE(0x0BDA, 0x0139) }, - { USB_DEVICE(0x0BDA, 0x0140) }, - { } -}; -MODULE_DEVICE_TABLE(usb, rtsx_usb_usb_ids); - -static struct usb_driver rtsx_usb_driver = { - .name = "rtsx_usb", - .probe = rtsx_usb_probe, - .disconnect = rtsx_usb_disconnect, - .suspend = rtsx_usb_suspend, - .resume = rtsx_usb_resume, - .reset_resume = rtsx_usb_reset_resume, - .pre_reset = rtsx_usb_pre_reset, - .post_reset = rtsx_usb_post_reset, - .id_table = rtsx_usb_usb_ids, - .supports_autosuspend = 1, - .soft_unbind = 1, -}; - -module_usb_driver(rtsx_usb_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Roger Tseng "); -MODULE_DESCRIPTION("Realtek USB Card Reader Driver"); -- cgit v1.2.3 From ea01a31b90581a94cdeef7fda9e4522f15ef64f2 Mon Sep 17 00:00:00 2001 From: Thierry Escande Date: Mon, 20 Nov 2017 17:15:25 +0100 Subject: cros_ec: Split cros_ec_devs module This patch splits the cros_ec_devs module in two parts with a cros_ec_dev module responsible for handling MFD devices registration and a cros_ec_ctl module responsible for handling the various user-space interfaces. For consistency purpose, the driver name for the cros_ec_dev module is now cros-ec-dev instead of cros-ec-ctl. In the next commit, the new cros_ec_dev module will be moved to the MFD subtree so mfd_add_devices() calls are not done from outside MFD. Signed-off-by: Thierry Escande Reviewed-by: Gwendal Grignou Tested-by: Guenter Roeck Signed-off-by: Lee Jones --- drivers/mfd/cros_ec.c | 4 ++-- drivers/platform/chrome/Kconfig | 4 ++++ drivers/platform/chrome/Makefile | 8 ++++---- drivers/platform/chrome/cros_ec_debugfs.c | 2 ++ drivers/platform/chrome/cros_ec_dev.c | 7 +++++-- drivers/platform/chrome/cros_ec_lightbar.c | 4 ++++ drivers/platform/chrome/cros_ec_sysfs.c | 3 +++ drivers/platform/chrome/cros_ec_vbc.c | 1 + 8 files changed, 25 insertions(+), 8 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index b0ca5a4c841e..d61024141e2b 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -40,13 +40,13 @@ static struct cros_ec_platform pd_p = { }; static const struct mfd_cell ec_cell = { - .name = "cros-ec-ctl", + .name = "cros-ec-dev", .platform_data = &ec_p, .pdata_size = sizeof(ec_p), }; static const struct mfd_cell ec_pd_cell = { - .name = "cros-ec-ctl", + .name = "cros-ec-dev", .platform_data = &pd_p, .pdata_size = sizeof(pd_p), }; diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index 0ad6e290bbda..bffc892c8bf1 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -41,12 +41,16 @@ config CHROMEOS_PSTORE config CROS_EC_CHARDEV tristate "Chrome OS Embedded Controller userspace device interface" depends on MFD_CROS_EC + select CROS_EC_CTL ---help--- This driver adds support to talk with the ChromeOS EC from userspace. If you have a supported Chromebook, choose Y or M here. The module will be called cros_ec_dev. +config CROS_EC_CTL + tristate + config CROS_EC_LPC tristate "ChromeOS Embedded Controller (LPC)" depends on MFD_CROS_EC && ACPI && (X86 || COMPILE_TEST) diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index a077b1f0211d..bc239ec98fd7 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -2,10 +2,10 @@ obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o -cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o \ - cros_ec_lightbar.o cros_ec_vbc.o \ - cros_ec_debugfs.o -obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o +cros_ec_ctl-objs := cros_ec_sysfs.o cros_ec_lightbar.o \ + cros_ec_vbc.o cros_ec_debugfs.o +obj-$(CONFIG_CROS_EC_CTL) += cros_ec_ctl.o +obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_dev.o cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_reg.o cros_ec_lpcs-$(CONFIG_CROS_EC_LPC_MEC) += cros_ec_lpc_mec.o obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c index 4cc66f405760..d0b8ce0d678e 100644 --- a/drivers/platform/chrome/cros_ec_debugfs.c +++ b/drivers/platform/chrome/cros_ec_debugfs.c @@ -390,6 +390,7 @@ remove_debugfs: debugfs_remove_recursive(debug_info->dir); return ret; } +EXPORT_SYMBOL(cros_ec_debugfs_init); void cros_ec_debugfs_remove(struct cros_ec_dev *ec) { @@ -399,3 +400,4 @@ void cros_ec_debugfs_remove(struct cros_ec_dev *ec) debugfs_remove_recursive(ec->debug_info->dir); cros_ec_cleanup_console_log(ec->debug_info); } +EXPORT_SYMBOL(cros_ec_debugfs_remove); diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c index cf6c4f0846b8..daf0ffd367a2 100644 --- a/drivers/platform/chrome/cros_ec_dev.c +++ b/drivers/platform/chrome/cros_ec_dev.c @@ -28,6 +28,8 @@ #include "cros_ec_debugfs.h" #include "cros_ec_dev.h" +#define DRV_NAME "cros-ec-dev" + /* Device variables */ #define CROS_MAX_DEV 128 static int ec_major; @@ -461,7 +463,7 @@ static int ec_device_remove(struct platform_device *pdev) } static const struct platform_device_id cros_ec_id[] = { - { "cros-ec-ctl", 0 }, + { DRV_NAME, 0 }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(platform, cros_ec_id); @@ -493,7 +495,7 @@ static const struct dev_pm_ops cros_ec_dev_pm_ops = { static struct platform_driver cros_ec_dev_driver = { .driver = { - .name = "cros-ec-ctl", + .name = DRV_NAME, .pm = &cros_ec_dev_pm_ops, }, .probe = ec_device_probe, @@ -544,6 +546,7 @@ static void __exit cros_ec_dev_exit(void) module_init(cros_ec_dev_init); module_exit(cros_ec_dev_exit); +MODULE_ALIAS("platform:" DRV_NAME); MODULE_AUTHOR("Bill Richardson "); MODULE_DESCRIPTION("Userspace interface to the Chrome OS Embedded Controller"); MODULE_VERSION("1.0"); diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index fd2b047a2748..925d91c5868e 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c @@ -414,6 +414,7 @@ error: return ret; } +EXPORT_SYMBOL(lb_manual_suspend_ctrl); int lb_suspend(struct cros_ec_dev *ec) { @@ -422,6 +423,7 @@ int lb_suspend(struct cros_ec_dev *ec) return lb_send_empty_cmd(ec, LIGHTBAR_CMD_SUSPEND); } +EXPORT_SYMBOL(lb_suspend); int lb_resume(struct cros_ec_dev *ec) { @@ -430,6 +432,7 @@ int lb_resume(struct cros_ec_dev *ec) return lb_send_empty_cmd(ec, LIGHTBAR_CMD_RESUME); } +EXPORT_SYMBOL(lb_resume); static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -622,3 +625,4 @@ struct attribute_group cros_ec_lightbar_attr_group = { .attrs = __lb_cmds_attrs, .is_visible = cros_ec_lightbar_attrs_are_visible, }; +EXPORT_SYMBOL(cros_ec_lightbar_attr_group); diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c index f3baf9973989..201f11afcdc9 100644 --- a/drivers/platform/chrome/cros_ec_sysfs.c +++ b/drivers/platform/chrome/cros_ec_sysfs.c @@ -294,4 +294,7 @@ static struct attribute *__ec_attrs[] = { struct attribute_group cros_ec_attr_group = { .attrs = __ec_attrs, }; +EXPORT_SYMBOL(cros_ec_attr_group); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ChromeOS EC control driver"); diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c index 564a0d08c8bf..6d38e6b08334 100644 --- a/drivers/platform/chrome/cros_ec_vbc.c +++ b/drivers/platform/chrome/cros_ec_vbc.c @@ -135,3 +135,4 @@ struct attribute_group cros_ec_vbc_attr_group = { .bin_attrs = cros_ec_vbc_bin_attrs, .is_bin_visible = cros_ec_vbc_is_visible, }; +EXPORT_SYMBOL(cros_ec_vbc_attr_group); -- cgit v1.2.3 From 5e0115581bbc367c7958bf5ab8c511b808558533 Mon Sep 17 00:00:00 2001 From: Thierry Escande Date: Mon, 20 Nov 2017 17:15:26 +0100 Subject: cros_ec: Move cros_ec_dev module to drivers/mfd The cros_ec_dev module is responsible for registering the MFD devices attached to the ChromeOS EC. This patch moves this module to drivers/mfd so calls to mfd_add_devices() are not done from outside the MFD subtree anymore. Signed-off-by: Thierry Escande Reviewed-by: Gwendal Grignou Tested-by: Guenter Roeck Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 10 + drivers/mfd/Makefile | 1 + drivers/mfd/cros_ec_dev.c | 552 ++++++++++++++++++++++++++++ drivers/mfd/cros_ec_dev.h | 52 +++ drivers/platform/chrome/Kconfig | 10 - drivers/platform/chrome/Makefile | 1 - drivers/platform/chrome/cros_ec_debugfs.c | 3 - drivers/platform/chrome/cros_ec_debugfs.h | 27 -- drivers/platform/chrome/cros_ec_dev.c | 553 ----------------------------- drivers/platform/chrome/cros_ec_dev.h | 52 --- drivers/platform/chrome/cros_ec_lightbar.c | 2 - drivers/platform/chrome/cros_ec_sysfs.c | 2 - include/linux/mfd/cros_ec.h | 4 + 13 files changed, 619 insertions(+), 650 deletions(-) create mode 100644 drivers/mfd/cros_ec_dev.c create mode 100644 drivers/mfd/cros_ec_dev.h delete mode 100644 drivers/platform/chrome/cros_ec_debugfs.h delete mode 100644 drivers/platform/chrome/cros_ec_dev.c delete mode 100644 drivers/platform/chrome/cros_ec_dev.h (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1d20a800e967..538a2ae8bd25 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -222,6 +222,16 @@ config MFD_CROS_EC_SPI response time cannot be guaranteed, we support ignoring 'pre-amble' bytes before the response actually starts. +config MFD_CROS_EC_CHARDEV + tristate "Chrome OS Embedded Controller userspace device interface" + depends on MFD_CROS_EC + select CROS_EC_CTL + ---help--- + This driver adds support to talk with the ChromeOS EC from userspace. + + If you have a supported Chromebook, choose Y or M here. + The module will be called cros_ec_dev. + config MFD_ASIC3 bool "Compaq ASIC3" depends on GPIOLIB && ARM diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d9474ade32e6..fcd8af88110e 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -17,6 +17,7 @@ cros_ec_core-$(CONFIG_ACPI) += cros_ec_acpi_gpe.o obj-$(CONFIG_MFD_CROS_EC) += cros_ec_core.o obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o +obj-$(CONFIG_MFD_CROS_EC_CHARDEV) += cros_ec_dev.o obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c new file mode 100644 index 000000000000..e4fafdd96e5e --- /dev/null +++ b/drivers/mfd/cros_ec_dev.c @@ -0,0 +1,552 @@ +/* + * cros_ec_dev - expose the Chrome OS Embedded Controller to user-space + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cros_ec_dev.h" + +#define DRV_NAME "cros-ec-dev" + +/* Device variables */ +#define CROS_MAX_DEV 128 +static int ec_major; + +static const struct attribute_group *cros_ec_groups[] = { + &cros_ec_attr_group, + &cros_ec_lightbar_attr_group, + &cros_ec_vbc_attr_group, + NULL, +}; + +static struct class cros_class = { + .owner = THIS_MODULE, + .name = "chromeos", + .dev_groups = cros_ec_groups, +}; + +/* Basic communication */ +static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen) +{ + struct ec_response_get_version *resp; + static const char * const current_image_name[] = { + "unknown", "read-only", "read-write", "invalid", + }; + struct cros_ec_command *msg; + int ret; + + msg = kmalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->version = 0; + msg->command = EC_CMD_GET_VERSION + ec->cmd_offset; + msg->insize = sizeof(*resp); + msg->outsize = 0; + + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); + if (ret < 0) + goto exit; + + if (msg->result != EC_RES_SUCCESS) { + snprintf(str, maxlen, + "%s\nUnknown EC version: EC returned %d\n", + CROS_EC_DEV_VERSION, msg->result); + ret = -EINVAL; + goto exit; + } + + resp = (struct ec_response_get_version *)msg->data; + if (resp->current_image >= ARRAY_SIZE(current_image_name)) + resp->current_image = 3; /* invalid */ + + snprintf(str, maxlen, "%s\n%s\n%s\n%s\n", CROS_EC_DEV_VERSION, + resp->version_string_ro, resp->version_string_rw, + current_image_name[resp->current_image]); + + ret = 0; +exit: + kfree(msg); + return ret; +} + +static int cros_ec_check_features(struct cros_ec_dev *ec, int feature) +{ + struct cros_ec_command *msg; + int ret; + + if (ec->features[0] == -1U && ec->features[1] == -1U) { + /* features bitmap not read yet */ + + msg = kmalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->version = 0; + msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset; + msg->insize = sizeof(ec->features); + msg->outsize = 0; + + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); + if (ret < 0 || msg->result != EC_RES_SUCCESS) { + dev_warn(ec->dev, "cannot get EC features: %d/%d\n", + ret, msg->result); + memset(ec->features, 0, sizeof(ec->features)); + } + + memcpy(ec->features, msg->data, sizeof(ec->features)); + + dev_dbg(ec->dev, "EC features %08x %08x\n", + ec->features[0], ec->features[1]); + + kfree(msg); + } + + return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature); +} + +/* Device file ops */ +static int ec_device_open(struct inode *inode, struct file *filp) +{ + struct cros_ec_dev *ec = container_of(inode->i_cdev, + struct cros_ec_dev, cdev); + filp->private_data = ec; + nonseekable_open(inode, filp); + return 0; +} + +static int ec_device_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static ssize_t ec_device_read(struct file *filp, char __user *buffer, + size_t length, loff_t *offset) +{ + struct cros_ec_dev *ec = filp->private_data; + char msg[sizeof(struct ec_response_get_version) + + sizeof(CROS_EC_DEV_VERSION)]; + size_t count; + int ret; + + if (*offset != 0) + return 0; + + ret = ec_get_version(ec, msg, sizeof(msg)); + if (ret) + return ret; + + count = min(length, strlen(msg)); + + if (copy_to_user(buffer, msg, count)) + return -EFAULT; + + *offset = count; + return count; +} + +/* Ioctls */ +static long ec_device_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg) +{ + long ret; + struct cros_ec_command u_cmd; + struct cros_ec_command *s_cmd; + + if (copy_from_user(&u_cmd, arg, sizeof(u_cmd))) + return -EFAULT; + + if ((u_cmd.outsize > EC_MAX_MSG_BYTES) || + (u_cmd.insize > EC_MAX_MSG_BYTES)) + return -EINVAL; + + s_cmd = kmalloc(sizeof(*s_cmd) + max(u_cmd.outsize, u_cmd.insize), + GFP_KERNEL); + if (!s_cmd) + return -ENOMEM; + + if (copy_from_user(s_cmd, arg, sizeof(*s_cmd) + u_cmd.outsize)) { + ret = -EFAULT; + goto exit; + } + + if (u_cmd.outsize != s_cmd->outsize || + u_cmd.insize != s_cmd->insize) { + ret = -EINVAL; + goto exit; + } + + s_cmd->command += ec->cmd_offset; + ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd); + /* Only copy data to userland if data was received. */ + if (ret < 0) + goto exit; + + if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + s_cmd->insize)) + ret = -EFAULT; +exit: + kfree(s_cmd); + return ret; +} + +static long ec_device_ioctl_readmem(struct cros_ec_dev *ec, void __user *arg) +{ + struct cros_ec_device *ec_dev = ec->ec_dev; + struct cros_ec_readmem s_mem = { }; + long num; + + /* Not every platform supports direct reads */ + if (!ec_dev->cmd_readmem) + return -ENOTTY; + + if (copy_from_user(&s_mem, arg, sizeof(s_mem))) + return -EFAULT; + + num = ec_dev->cmd_readmem(ec_dev, s_mem.offset, s_mem.bytes, + s_mem.buffer); + if (num <= 0) + return num; + + if (copy_to_user((void __user *)arg, &s_mem, sizeof(s_mem))) + return -EFAULT; + + return 0; +} + +static long ec_device_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct cros_ec_dev *ec = filp->private_data; + + if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC) + return -ENOTTY; + + switch (cmd) { + case CROS_EC_DEV_IOCXCMD: + return ec_device_ioctl_xcmd(ec, (void __user *)arg); + case CROS_EC_DEV_IOCRDMEM: + return ec_device_ioctl_readmem(ec, (void __user *)arg); + } + + return -ENOTTY; +} + +/* Module initialization */ +static const struct file_operations fops = { + .open = ec_device_open, + .release = ec_device_release, + .read = ec_device_read, + .unlocked_ioctl = ec_device_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ec_device_ioctl, +#endif +}; + +static void __remove(struct device *dev) +{ + struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, + class_dev); + kfree(ec); +} + +static void cros_ec_sensors_register(struct cros_ec_dev *ec) +{ + /* + * Issue a command to get the number of sensor reported. + * Build an array of sensors driver and register them all. + */ + int ret, i, id, sensor_num; + struct mfd_cell *sensor_cells; + struct cros_ec_sensor_platform *sensor_platforms; + int sensor_type[MOTIONSENSE_TYPE_MAX]; + struct ec_params_motion_sense *params; + struct ec_response_motion_sense *resp; + struct cros_ec_command *msg; + + msg = kzalloc(sizeof(struct cros_ec_command) + + max(sizeof(*params), sizeof(*resp)), GFP_KERNEL); + if (msg == NULL) + return; + + msg->version = 2; + msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset; + msg->outsize = sizeof(*params); + msg->insize = sizeof(*resp); + + params = (struct ec_params_motion_sense *)msg->data; + params->cmd = MOTIONSENSE_CMD_DUMP; + + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); + if (ret < 0 || msg->result != EC_RES_SUCCESS) { + dev_warn(ec->dev, "cannot get EC sensor information: %d/%d\n", + ret, msg->result); + goto error; + } + + resp = (struct ec_response_motion_sense *)msg->data; + sensor_num = resp->dump.sensor_count; + /* Allocate 2 extra sensors in case lid angle or FIFO are needed */ + sensor_cells = kzalloc(sizeof(struct mfd_cell) * (sensor_num + 2), + GFP_KERNEL); + if (sensor_cells == NULL) + goto error; + + sensor_platforms = kzalloc(sizeof(struct cros_ec_sensor_platform) * + (sensor_num + 1), GFP_KERNEL); + if (sensor_platforms == NULL) + goto error_platforms; + + memset(sensor_type, 0, sizeof(sensor_type)); + id = 0; + for (i = 0; i < sensor_num; i++) { + params->cmd = MOTIONSENSE_CMD_INFO; + params->info.sensor_num = i; + ret = cros_ec_cmd_xfer(ec->ec_dev, msg); + if (ret < 0 || msg->result != EC_RES_SUCCESS) { + dev_warn(ec->dev, "no info for EC sensor %d : %d/%d\n", + i, ret, msg->result); + continue; + } + switch (resp->info.type) { + case MOTIONSENSE_TYPE_ACCEL: + sensor_cells[id].name = "cros-ec-accel"; + break; + case MOTIONSENSE_TYPE_BARO: + sensor_cells[id].name = "cros-ec-baro"; + break; + case MOTIONSENSE_TYPE_GYRO: + sensor_cells[id].name = "cros-ec-gyro"; + break; + case MOTIONSENSE_TYPE_MAG: + sensor_cells[id].name = "cros-ec-mag"; + break; + case MOTIONSENSE_TYPE_PROX: + sensor_cells[id].name = "cros-ec-prox"; + break; + case MOTIONSENSE_TYPE_LIGHT: + sensor_cells[id].name = "cros-ec-light"; + break; + case MOTIONSENSE_TYPE_ACTIVITY: + sensor_cells[id].name = "cros-ec-activity"; + break; + default: + dev_warn(ec->dev, "unknown type %d\n", resp->info.type); + continue; + } + sensor_platforms[id].sensor_num = i; + sensor_cells[id].id = sensor_type[resp->info.type]; + sensor_cells[id].platform_data = &sensor_platforms[id]; + sensor_cells[id].pdata_size = + sizeof(struct cros_ec_sensor_platform); + + sensor_type[resp->info.type]++; + id++; + } + if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2) { + sensor_platforms[id].sensor_num = sensor_num; + + sensor_cells[id].name = "cros-ec-angle"; + sensor_cells[id].id = 0; + sensor_cells[id].platform_data = &sensor_platforms[id]; + sensor_cells[id].pdata_size = + sizeof(struct cros_ec_sensor_platform); + id++; + } + if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) { + sensor_cells[id].name = "cros-ec-ring"; + id++; + } + + ret = mfd_add_devices(ec->dev, 0, sensor_cells, id, + NULL, 0, NULL); + if (ret) + dev_err(ec->dev, "failed to add EC sensors\n"); + + kfree(sensor_platforms); +error_platforms: + kfree(sensor_cells); +error: + kfree(msg); +} + +static int ec_device_probe(struct platform_device *pdev) +{ + int retval = -ENOMEM; + struct device *dev = &pdev->dev; + struct cros_ec_platform *ec_platform = dev_get_platdata(dev); + struct cros_ec_dev *ec = kzalloc(sizeof(*ec), GFP_KERNEL); + + if (!ec) + return retval; + + dev_set_drvdata(dev, ec); + ec->ec_dev = dev_get_drvdata(dev->parent); + ec->dev = dev; + ec->cmd_offset = ec_platform->cmd_offset; + ec->features[0] = -1U; /* Not cached yet */ + ec->features[1] = -1U; /* Not cached yet */ + device_initialize(&ec->class_dev); + cdev_init(&ec->cdev, &fops); + + /* + * Add the class device + * Link to the character device for creating the /dev entry + * in devtmpfs. + */ + ec->class_dev.devt = MKDEV(ec_major, pdev->id); + ec->class_dev.class = &cros_class; + ec->class_dev.parent = dev; + ec->class_dev.release = __remove; + + retval = dev_set_name(&ec->class_dev, "%s", ec_platform->ec_name); + if (retval) { + dev_err(dev, "dev_set_name failed => %d\n", retval); + goto failed; + } + + retval = cdev_device_add(&ec->cdev, &ec->class_dev); + if (retval) { + dev_err(dev, "cdev_device_add failed => %d\n", retval); + goto failed; + } + + if (cros_ec_debugfs_init(ec)) + dev_warn(dev, "failed to create debugfs directory\n"); + + /* check whether this EC is a sensor hub. */ + if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE)) + cros_ec_sensors_register(ec); + + /* Take control of the lightbar from the EC. */ + lb_manual_suspend_ctrl(ec, 1); + + return 0; + +failed: + put_device(&ec->class_dev); + return retval; +} + +static int ec_device_remove(struct platform_device *pdev) +{ + struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev); + + /* Let the EC take over the lightbar again. */ + lb_manual_suspend_ctrl(ec, 0); + + cros_ec_debugfs_remove(ec); + + cdev_del(&ec->cdev); + device_unregister(&ec->class_dev); + return 0; +} + +static const struct platform_device_id cros_ec_id[] = { + { DRV_NAME, 0 }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(platform, cros_ec_id); + +static __maybe_unused int ec_device_suspend(struct device *dev) +{ + struct cros_ec_dev *ec = dev_get_drvdata(dev); + + lb_suspend(ec); + + return 0; +} + +static __maybe_unused int ec_device_resume(struct device *dev) +{ + struct cros_ec_dev *ec = dev_get_drvdata(dev); + + lb_resume(ec); + + return 0; +} + +static const struct dev_pm_ops cros_ec_dev_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .suspend = ec_device_suspend, + .resume = ec_device_resume, +#endif +}; + +static struct platform_driver cros_ec_dev_driver = { + .driver = { + .name = DRV_NAME, + .pm = &cros_ec_dev_pm_ops, + }, + .probe = ec_device_probe, + .remove = ec_device_remove, +}; + +static int __init cros_ec_dev_init(void) +{ + int ret; + dev_t dev = 0; + + ret = class_register(&cros_class); + if (ret) { + pr_err(CROS_EC_DEV_NAME ": failed to register device class\n"); + return ret; + } + + /* Get a range of minor numbers (starting with 0) to work with */ + ret = alloc_chrdev_region(&dev, 0, CROS_MAX_DEV, CROS_EC_DEV_NAME); + if (ret < 0) { + pr_err(CROS_EC_DEV_NAME ": alloc_chrdev_region() failed\n"); + goto failed_chrdevreg; + } + ec_major = MAJOR(dev); + + /* Register the driver */ + ret = platform_driver_register(&cros_ec_dev_driver); + if (ret < 0) { + pr_warn(CROS_EC_DEV_NAME ": can't register driver: %d\n", ret); + goto failed_devreg; + } + return 0; + +failed_devreg: + unregister_chrdev_region(MKDEV(ec_major, 0), CROS_MAX_DEV); +failed_chrdevreg: + class_unregister(&cros_class); + return ret; +} + +static void __exit cros_ec_dev_exit(void) +{ + platform_driver_unregister(&cros_ec_dev_driver); + unregister_chrdev(ec_major, CROS_EC_DEV_NAME); + class_unregister(&cros_class); +} + +module_init(cros_ec_dev_init); +module_exit(cros_ec_dev_exit); + +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_AUTHOR("Bill Richardson "); +MODULE_DESCRIPTION("Userspace interface to the Chrome OS Embedded Controller"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/cros_ec_dev.h b/drivers/mfd/cros_ec_dev.h new file mode 100644 index 000000000000..45e9453608c5 --- /dev/null +++ b/drivers/mfd/cros_ec_dev.h @@ -0,0 +1,52 @@ +/* + * cros_ec_dev - expose the Chrome OS Embedded Controller to userspace + * + * Copyright (C) 2014 Google, Inc. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _CROS_EC_DEV_H_ +#define _CROS_EC_DEV_H_ + +#include +#include +#include + +#define CROS_EC_DEV_VERSION "1.0.0" + +/* + * @offset: within EC_LPC_ADDR_MEMMAP region + * @bytes: number of bytes to read. zero means "read a string" (including '\0') + * (at most only EC_MEMMAP_SIZE bytes can be read) + * @buffer: where to store the result + * ioctl returns the number of bytes read, negative on error + */ +struct cros_ec_readmem { + uint32_t offset; + uint32_t bytes; + uint8_t buffer[EC_MEMMAP_SIZE]; +}; + +#define CROS_EC_DEV_IOC 0xEC +#define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command) +#define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem) + +/* Lightbar utilities */ +extern bool ec_has_lightbar(struct cros_ec_dev *ec); +extern int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable); +extern int lb_suspend(struct cros_ec_dev *ec); +extern int lb_resume(struct cros_ec_dev *ec); + +#endif /* _CROS_EC_DEV_H_ */ diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index bffc892c8bf1..e728a96cabfd 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -38,16 +38,6 @@ config CHROMEOS_PSTORE If you have a supported Chromebook, choose Y or M here. The module will be called chromeos_pstore. -config CROS_EC_CHARDEV - tristate "Chrome OS Embedded Controller userspace device interface" - depends on MFD_CROS_EC - select CROS_EC_CTL - ---help--- - This driver adds support to talk with the ChromeOS EC from userspace. - - If you have a supported Chromebook, choose Y or M here. - The module will be called cros_ec_dev. - config CROS_EC_CTL tristate diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index bc239ec98fd7..ff3b369911f0 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o cros_ec_ctl-objs := cros_ec_sysfs.o cros_ec_lightbar.o \ cros_ec_vbc.o cros_ec_debugfs.o obj-$(CONFIG_CROS_EC_CTL) += cros_ec_ctl.o -obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_dev.o cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_reg.o cros_ec_lpcs-$(CONFIG_CROS_EC_LPC_MEC) += cros_ec_lpc_mec.o obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c index d0b8ce0d678e..98a35d32f9dd 100644 --- a/drivers/platform/chrome/cros_ec_debugfs.c +++ b/drivers/platform/chrome/cros_ec_debugfs.c @@ -29,9 +29,6 @@ #include #include -#include "cros_ec_dev.h" -#include "cros_ec_debugfs.h" - #define LOG_SHIFT 14 #define LOG_SIZE (1 << LOG_SHIFT) #define LOG_POLL_SEC 10 diff --git a/drivers/platform/chrome/cros_ec_debugfs.h b/drivers/platform/chrome/cros_ec_debugfs.h deleted file mode 100644 index 1ff3a50aa1b8..000000000000 --- a/drivers/platform/chrome/cros_ec_debugfs.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2015 Google, Inc. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _DRV_CROS_EC_DEBUGFS_H_ -#define _DRV_CROS_EC_DEBUGFS_H_ - -#include "cros_ec_dev.h" - -/* debugfs stuff */ -int cros_ec_debugfs_init(struct cros_ec_dev *ec); -void cros_ec_debugfs_remove(struct cros_ec_dev *ec); - -#endif /* _DRV_CROS_EC_DEBUGFS_H_ */ diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c deleted file mode 100644 index daf0ffd367a2..000000000000 --- a/drivers/platform/chrome/cros_ec_dev.c +++ /dev/null @@ -1,553 +0,0 @@ -/* - * cros_ec_dev - expose the Chrome OS Embedded Controller to user-space - * - * Copyright (C) 2014 Google, Inc. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "cros_ec_debugfs.h" -#include "cros_ec_dev.h" - -#define DRV_NAME "cros-ec-dev" - -/* Device variables */ -#define CROS_MAX_DEV 128 -static int ec_major; - -static const struct attribute_group *cros_ec_groups[] = { - &cros_ec_attr_group, - &cros_ec_lightbar_attr_group, - &cros_ec_vbc_attr_group, - NULL, -}; - -static struct class cros_class = { - .owner = THIS_MODULE, - .name = "chromeos", - .dev_groups = cros_ec_groups, -}; - -/* Basic communication */ -static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen) -{ - struct ec_response_get_version *resp; - static const char * const current_image_name[] = { - "unknown", "read-only", "read-write", "invalid", - }; - struct cros_ec_command *msg; - int ret; - - msg = kmalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL); - if (!msg) - return -ENOMEM; - - msg->version = 0; - msg->command = EC_CMD_GET_VERSION + ec->cmd_offset; - msg->insize = sizeof(*resp); - msg->outsize = 0; - - ret = cros_ec_cmd_xfer(ec->ec_dev, msg); - if (ret < 0) - goto exit; - - if (msg->result != EC_RES_SUCCESS) { - snprintf(str, maxlen, - "%s\nUnknown EC version: EC returned %d\n", - CROS_EC_DEV_VERSION, msg->result); - ret = -EINVAL; - goto exit; - } - - resp = (struct ec_response_get_version *)msg->data; - if (resp->current_image >= ARRAY_SIZE(current_image_name)) - resp->current_image = 3; /* invalid */ - - snprintf(str, maxlen, "%s\n%s\n%s\n%s\n", CROS_EC_DEV_VERSION, - resp->version_string_ro, resp->version_string_rw, - current_image_name[resp->current_image]); - - ret = 0; -exit: - kfree(msg); - return ret; -} - -static int cros_ec_check_features(struct cros_ec_dev *ec, int feature) -{ - struct cros_ec_command *msg; - int ret; - - if (ec->features[0] == -1U && ec->features[1] == -1U) { - /* features bitmap not read yet */ - - msg = kmalloc(sizeof(*msg) + sizeof(ec->features), GFP_KERNEL); - if (!msg) - return -ENOMEM; - - msg->version = 0; - msg->command = EC_CMD_GET_FEATURES + ec->cmd_offset; - msg->insize = sizeof(ec->features); - msg->outsize = 0; - - ret = cros_ec_cmd_xfer(ec->ec_dev, msg); - if (ret < 0 || msg->result != EC_RES_SUCCESS) { - dev_warn(ec->dev, "cannot get EC features: %d/%d\n", - ret, msg->result); - memset(ec->features, 0, sizeof(ec->features)); - } - - memcpy(ec->features, msg->data, sizeof(ec->features)); - - dev_dbg(ec->dev, "EC features %08x %08x\n", - ec->features[0], ec->features[1]); - - kfree(msg); - } - - return ec->features[feature / 32] & EC_FEATURE_MASK_0(feature); -} - -/* Device file ops */ -static int ec_device_open(struct inode *inode, struct file *filp) -{ - struct cros_ec_dev *ec = container_of(inode->i_cdev, - struct cros_ec_dev, cdev); - filp->private_data = ec; - nonseekable_open(inode, filp); - return 0; -} - -static int ec_device_release(struct inode *inode, struct file *filp) -{ - return 0; -} - -static ssize_t ec_device_read(struct file *filp, char __user *buffer, - size_t length, loff_t *offset) -{ - struct cros_ec_dev *ec = filp->private_data; - char msg[sizeof(struct ec_response_get_version) + - sizeof(CROS_EC_DEV_VERSION)]; - size_t count; - int ret; - - if (*offset != 0) - return 0; - - ret = ec_get_version(ec, msg, sizeof(msg)); - if (ret) - return ret; - - count = min(length, strlen(msg)); - - if (copy_to_user(buffer, msg, count)) - return -EFAULT; - - *offset = count; - return count; -} - -/* Ioctls */ -static long ec_device_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg) -{ - long ret; - struct cros_ec_command u_cmd; - struct cros_ec_command *s_cmd; - - if (copy_from_user(&u_cmd, arg, sizeof(u_cmd))) - return -EFAULT; - - if ((u_cmd.outsize > EC_MAX_MSG_BYTES) || - (u_cmd.insize > EC_MAX_MSG_BYTES)) - return -EINVAL; - - s_cmd = kmalloc(sizeof(*s_cmd) + max(u_cmd.outsize, u_cmd.insize), - GFP_KERNEL); - if (!s_cmd) - return -ENOMEM; - - if (copy_from_user(s_cmd, arg, sizeof(*s_cmd) + u_cmd.outsize)) { - ret = -EFAULT; - goto exit; - } - - if (u_cmd.outsize != s_cmd->outsize || - u_cmd.insize != s_cmd->insize) { - ret = -EINVAL; - goto exit; - } - - s_cmd->command += ec->cmd_offset; - ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd); - /* Only copy data to userland if data was received. */ - if (ret < 0) - goto exit; - - if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + s_cmd->insize)) - ret = -EFAULT; -exit: - kfree(s_cmd); - return ret; -} - -static long ec_device_ioctl_readmem(struct cros_ec_dev *ec, void __user *arg) -{ - struct cros_ec_device *ec_dev = ec->ec_dev; - struct cros_ec_readmem s_mem = { }; - long num; - - /* Not every platform supports direct reads */ - if (!ec_dev->cmd_readmem) - return -ENOTTY; - - if (copy_from_user(&s_mem, arg, sizeof(s_mem))) - return -EFAULT; - - num = ec_dev->cmd_readmem(ec_dev, s_mem.offset, s_mem.bytes, - s_mem.buffer); - if (num <= 0) - return num; - - if (copy_to_user((void __user *)arg, &s_mem, sizeof(s_mem))) - return -EFAULT; - - return 0; -} - -static long ec_device_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct cros_ec_dev *ec = filp->private_data; - - if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC) - return -ENOTTY; - - switch (cmd) { - case CROS_EC_DEV_IOCXCMD: - return ec_device_ioctl_xcmd(ec, (void __user *)arg); - case CROS_EC_DEV_IOCRDMEM: - return ec_device_ioctl_readmem(ec, (void __user *)arg); - } - - return -ENOTTY; -} - -/* Module initialization */ -static const struct file_operations fops = { - .open = ec_device_open, - .release = ec_device_release, - .read = ec_device_read, - .unlocked_ioctl = ec_device_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ec_device_ioctl, -#endif -}; - -static void __remove(struct device *dev) -{ - struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev, - class_dev); - kfree(ec); -} - -static void cros_ec_sensors_register(struct cros_ec_dev *ec) -{ - /* - * Issue a command to get the number of sensor reported. - * Build an array of sensors driver and register them all. - */ - int ret, i, id, sensor_num; - struct mfd_cell *sensor_cells; - struct cros_ec_sensor_platform *sensor_platforms; - int sensor_type[MOTIONSENSE_TYPE_MAX]; - struct ec_params_motion_sense *params; - struct ec_response_motion_sense *resp; - struct cros_ec_command *msg; - - msg = kzalloc(sizeof(struct cros_ec_command) + - max(sizeof(*params), sizeof(*resp)), GFP_KERNEL); - if (msg == NULL) - return; - - msg->version = 2; - msg->command = EC_CMD_MOTION_SENSE_CMD + ec->cmd_offset; - msg->outsize = sizeof(*params); - msg->insize = sizeof(*resp); - - params = (struct ec_params_motion_sense *)msg->data; - params->cmd = MOTIONSENSE_CMD_DUMP; - - ret = cros_ec_cmd_xfer(ec->ec_dev, msg); - if (ret < 0 || msg->result != EC_RES_SUCCESS) { - dev_warn(ec->dev, "cannot get EC sensor information: %d/%d\n", - ret, msg->result); - goto error; - } - - resp = (struct ec_response_motion_sense *)msg->data; - sensor_num = resp->dump.sensor_count; - /* Allocate 2 extra sensors in case lid angle or FIFO are needed */ - sensor_cells = kzalloc(sizeof(struct mfd_cell) * (sensor_num + 2), - GFP_KERNEL); - if (sensor_cells == NULL) - goto error; - - sensor_platforms = kzalloc(sizeof(struct cros_ec_sensor_platform) * - (sensor_num + 1), GFP_KERNEL); - if (sensor_platforms == NULL) - goto error_platforms; - - memset(sensor_type, 0, sizeof(sensor_type)); - id = 0; - for (i = 0; i < sensor_num; i++) { - params->cmd = MOTIONSENSE_CMD_INFO; - params->info.sensor_num = i; - ret = cros_ec_cmd_xfer(ec->ec_dev, msg); - if (ret < 0 || msg->result != EC_RES_SUCCESS) { - dev_warn(ec->dev, "no info for EC sensor %d : %d/%d\n", - i, ret, msg->result); - continue; - } - switch (resp->info.type) { - case MOTIONSENSE_TYPE_ACCEL: - sensor_cells[id].name = "cros-ec-accel"; - break; - case MOTIONSENSE_TYPE_BARO: - sensor_cells[id].name = "cros-ec-baro"; - break; - case MOTIONSENSE_TYPE_GYRO: - sensor_cells[id].name = "cros-ec-gyro"; - break; - case MOTIONSENSE_TYPE_MAG: - sensor_cells[id].name = "cros-ec-mag"; - break; - case MOTIONSENSE_TYPE_PROX: - sensor_cells[id].name = "cros-ec-prox"; - break; - case MOTIONSENSE_TYPE_LIGHT: - sensor_cells[id].name = "cros-ec-light"; - break; - case MOTIONSENSE_TYPE_ACTIVITY: - sensor_cells[id].name = "cros-ec-activity"; - break; - default: - dev_warn(ec->dev, "unknown type %d\n", resp->info.type); - continue; - } - sensor_platforms[id].sensor_num = i; - sensor_cells[id].id = sensor_type[resp->info.type]; - sensor_cells[id].platform_data = &sensor_platforms[id]; - sensor_cells[id].pdata_size = - sizeof(struct cros_ec_sensor_platform); - - sensor_type[resp->info.type]++; - id++; - } - if (sensor_type[MOTIONSENSE_TYPE_ACCEL] >= 2) { - sensor_platforms[id].sensor_num = sensor_num; - - sensor_cells[id].name = "cros-ec-angle"; - sensor_cells[id].id = 0; - sensor_cells[id].platform_data = &sensor_platforms[id]; - sensor_cells[id].pdata_size = - sizeof(struct cros_ec_sensor_platform); - id++; - } - if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE_FIFO)) { - sensor_cells[id].name = "cros-ec-ring"; - id++; - } - - ret = mfd_add_devices(ec->dev, 0, sensor_cells, id, - NULL, 0, NULL); - if (ret) - dev_err(ec->dev, "failed to add EC sensors\n"); - - kfree(sensor_platforms); -error_platforms: - kfree(sensor_cells); -error: - kfree(msg); -} - -static int ec_device_probe(struct platform_device *pdev) -{ - int retval = -ENOMEM; - struct device *dev = &pdev->dev; - struct cros_ec_platform *ec_platform = dev_get_platdata(dev); - struct cros_ec_dev *ec = kzalloc(sizeof(*ec), GFP_KERNEL); - - if (!ec) - return retval; - - dev_set_drvdata(dev, ec); - ec->ec_dev = dev_get_drvdata(dev->parent); - ec->dev = dev; - ec->cmd_offset = ec_platform->cmd_offset; - ec->features[0] = -1U; /* Not cached yet */ - ec->features[1] = -1U; /* Not cached yet */ - device_initialize(&ec->class_dev); - cdev_init(&ec->cdev, &fops); - - /* - * Add the class device - * Link to the character device for creating the /dev entry - * in devtmpfs. - */ - ec->class_dev.devt = MKDEV(ec_major, pdev->id); - ec->class_dev.class = &cros_class; - ec->class_dev.parent = dev; - ec->class_dev.release = __remove; - - retval = dev_set_name(&ec->class_dev, "%s", ec_platform->ec_name); - if (retval) { - dev_err(dev, "dev_set_name failed => %d\n", retval); - goto failed; - } - - retval = cdev_device_add(&ec->cdev, &ec->class_dev); - if (retval) { - dev_err(dev, "cdev_device_add failed => %d\n", retval); - goto failed; - } - - if (cros_ec_debugfs_init(ec)) - dev_warn(dev, "failed to create debugfs directory\n"); - - /* check whether this EC is a sensor hub. */ - if (cros_ec_check_features(ec, EC_FEATURE_MOTION_SENSE)) - cros_ec_sensors_register(ec); - - /* Take control of the lightbar from the EC. */ - lb_manual_suspend_ctrl(ec, 1); - - return 0; - -failed: - put_device(&ec->class_dev); - return retval; -} - -static int ec_device_remove(struct platform_device *pdev) -{ - struct cros_ec_dev *ec = dev_get_drvdata(&pdev->dev); - - /* Let the EC take over the lightbar again. */ - lb_manual_suspend_ctrl(ec, 0); - - cros_ec_debugfs_remove(ec); - - cdev_del(&ec->cdev); - device_unregister(&ec->class_dev); - return 0; -} - -static const struct platform_device_id cros_ec_id[] = { - { DRV_NAME, 0 }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(platform, cros_ec_id); - -static __maybe_unused int ec_device_suspend(struct device *dev) -{ - struct cros_ec_dev *ec = dev_get_drvdata(dev); - - lb_suspend(ec); - - return 0; -} - -static __maybe_unused int ec_device_resume(struct device *dev) -{ - struct cros_ec_dev *ec = dev_get_drvdata(dev); - - lb_resume(ec); - - return 0; -} - -static const struct dev_pm_ops cros_ec_dev_pm_ops = { -#ifdef CONFIG_PM_SLEEP - .suspend = ec_device_suspend, - .resume = ec_device_resume, -#endif -}; - -static struct platform_driver cros_ec_dev_driver = { - .driver = { - .name = DRV_NAME, - .pm = &cros_ec_dev_pm_ops, - }, - .probe = ec_device_probe, - .remove = ec_device_remove, -}; - -static int __init cros_ec_dev_init(void) -{ - int ret; - dev_t dev = 0; - - ret = class_register(&cros_class); - if (ret) { - pr_err(CROS_EC_DEV_NAME ": failed to register device class\n"); - return ret; - } - - /* Get a range of minor numbers (starting with 0) to work with */ - ret = alloc_chrdev_region(&dev, 0, CROS_MAX_DEV, CROS_EC_DEV_NAME); - if (ret < 0) { - pr_err(CROS_EC_DEV_NAME ": alloc_chrdev_region() failed\n"); - goto failed_chrdevreg; - } - ec_major = MAJOR(dev); - - /* Register the driver */ - ret = platform_driver_register(&cros_ec_dev_driver); - if (ret < 0) { - pr_warn(CROS_EC_DEV_NAME ": can't register driver: %d\n", ret); - goto failed_devreg; - } - return 0; - -failed_devreg: - unregister_chrdev_region(MKDEV(ec_major, 0), CROS_MAX_DEV); -failed_chrdevreg: - class_unregister(&cros_class); - return ret; -} - -static void __exit cros_ec_dev_exit(void) -{ - platform_driver_unregister(&cros_ec_dev_driver); - unregister_chrdev(ec_major, CROS_EC_DEV_NAME); - class_unregister(&cros_class); -} - -module_init(cros_ec_dev_init); -module_exit(cros_ec_dev_exit); - -MODULE_ALIAS("platform:" DRV_NAME); -MODULE_AUTHOR("Bill Richardson "); -MODULE_DESCRIPTION("Userspace interface to the Chrome OS Embedded Controller"); -MODULE_VERSION("1.0"); -MODULE_LICENSE("GPL"); diff --git a/drivers/platform/chrome/cros_ec_dev.h b/drivers/platform/chrome/cros_ec_dev.h deleted file mode 100644 index 45e9453608c5..000000000000 --- a/drivers/platform/chrome/cros_ec_dev.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * cros_ec_dev - expose the Chrome OS Embedded Controller to userspace - * - * Copyright (C) 2014 Google, Inc. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef _CROS_EC_DEV_H_ -#define _CROS_EC_DEV_H_ - -#include -#include -#include - -#define CROS_EC_DEV_VERSION "1.0.0" - -/* - * @offset: within EC_LPC_ADDR_MEMMAP region - * @bytes: number of bytes to read. zero means "read a string" (including '\0') - * (at most only EC_MEMMAP_SIZE bytes can be read) - * @buffer: where to store the result - * ioctl returns the number of bytes read, negative on error - */ -struct cros_ec_readmem { - uint32_t offset; - uint32_t bytes; - uint8_t buffer[EC_MEMMAP_SIZE]; -}; - -#define CROS_EC_DEV_IOC 0xEC -#define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command) -#define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem) - -/* Lightbar utilities */ -extern bool ec_has_lightbar(struct cros_ec_dev *ec); -extern int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable); -extern int lb_suspend(struct cros_ec_dev *ec); -extern int lb_resume(struct cros_ec_dev *ec); - -#endif /* _CROS_EC_DEV_H_ */ diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index 925d91c5868e..6ea79d495aa2 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c @@ -33,8 +33,6 @@ #include #include -#include "cros_ec_dev.h" - /* Rate-limit the lightbar interface to prevent DoS. */ static unsigned long lb_interval_jiffies = 50 * HZ / 1000; diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c index 201f11afcdc9..d6eebe872187 100644 --- a/drivers/platform/chrome/cros_ec_sysfs.c +++ b/drivers/platform/chrome/cros_ec_sysfs.c @@ -34,8 +34,6 @@ #include #include -#include "cros_ec_dev.h" - /* Accessor functions */ static ssize_t show_ec_reboot(struct device *dev, diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h index 4e887ba22635..c61535979b8f 100644 --- a/include/linux/mfd/cros_ec.h +++ b/include/linux/mfd/cros_ec.h @@ -322,6 +322,10 @@ extern struct attribute_group cros_ec_attr_group; extern struct attribute_group cros_ec_lightbar_attr_group; extern struct attribute_group cros_ec_vbc_attr_group; +/* debugfs stuff */ +int cros_ec_debugfs_init(struct cros_ec_dev *ec); +void cros_ec_debugfs_remove(struct cros_ec_dev *ec); + /* ACPI GPE handler */ #ifdef CONFIG_ACPI -- cgit v1.2.3 From 538ee27290fa277f82159f61da1c5f95f6d631e2 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Wed, 20 Dec 2017 22:51:16 -0800 Subject: mfd: Add driver for RAVE Supervisory Processor Add a driver for RAVE Supervisory Processor, an MCU implementing various bits of housekeeping functionality (watchdoging, backlight control, LED control, etc) on RAVE family of products by Zodiac Inflight Innovations. This driver implementes core MFD/serdev device as well as communication subroutines necessary for commanding the device. Signed-off-by: Andrey Smirnov Acked-by: Philippe Ombredanne Acked-by: Pavel Machek Reviewed-by: Guenter Roeck Reviewed-by: Andy Shevchenko Tested-by: Chris Healy Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 8 + drivers/mfd/Makefile | 2 + drivers/mfd/rave-sp.c | 710 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/rave-sp.h | 60 ++++ 4 files changed, 780 insertions(+) create mode 100644 drivers/mfd/rave-sp.c create mode 100644 include/linux/mfd/rave-sp.h (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1d20a800e967..ec90d408bfa9 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1859,5 +1859,13 @@ config MFD_VEXPRESS_SYSREG System Registers are the platform configuration block on the ARM Ltd. Versatile Express board. +config RAVE_SP_CORE + tristate "RAVE SP MCU core driver" + depends on SERIAL_DEV_BUS + select CRC_CCITT + help + Select this to get support for the Supervisory Processor + device found on several devices in RAVE line of hardware. + endmenu endif diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d9474ade32e6..61abc297b97c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -230,3 +230,5 @@ obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o +obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o + diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c new file mode 100644 index 000000000000..5c858e784a89 --- /dev/null +++ b/drivers/mfd/rave-sp.c @@ -0,0 +1,710 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Multifunction core driver for Zodiac Inflight Innovations RAVE + * Supervisory Processor(SP) MCU that is connected via dedicated UART + * port + * + * Copyright (C) 2017 Zodiac Inflight Innovations + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * UART protocol using following entities: + * - message to MCU => ACK response + * - event from MCU => event ACK + * + * Frame structure: + * + * Where: + * - STX - is start of transmission character + * - ETX - end of transmission + * - DATA - payload + * - CHECKSUM - checksum calculated on + * + * If or contain one of control characters, then it is + * escaped using control code. Added does not participate in + * checksum calculation. + */ +#define RAVE_SP_STX 0x02 +#define RAVE_SP_ETX 0x03 +#define RAVE_SP_DLE 0x10 + +#define RAVE_SP_MAX_DATA_SIZE 64 +#define RAVE_SP_CHECKSUM_SIZE 2 /* Worst case scenario on RDU2 */ +/* + * We don't store STX, ETX and unescaped bytes, so Rx is only + * DATA + CSUM + */ +#define RAVE_SP_RX_BUFFER_SIZE \ + (RAVE_SP_MAX_DATA_SIZE + RAVE_SP_CHECKSUM_SIZE) + +#define RAVE_SP_STX_ETX_SIZE 2 +/* + * For Tx we have to have space for everything, STX, EXT and + * potentially stuffed DATA + CSUM data + csum + */ +#define RAVE_SP_TX_BUFFER_SIZE \ + (RAVE_SP_STX_ETX_SIZE + 2 * RAVE_SP_RX_BUFFER_SIZE) + +#define RAVE_SP_BOOT_SOURCE_GET 0 +#define RAVE_SP_BOOT_SOURCE_SET 1 + +#define RAVE_SP_RDU2_BOARD_TYPE_RMB 0 +#define RAVE_SP_RDU2_BOARD_TYPE_DEB 1 + +#define RAVE_SP_BOOT_SOURCE_SD 0 +#define RAVE_SP_BOOT_SOURCE_EMMC 1 +#define RAVE_SP_BOOT_SOURCE_NOR 2 + +/** + * enum rave_sp_deframer_state - Possible state for de-framer + * + * @RAVE_SP_EXPECT_SOF: Scanning input for start-of-frame marker + * @RAVE_SP_EXPECT_DATA: Got start of frame marker, collecting frame + * @RAVE_SP_EXPECT_ESCAPED_DATA: Got escape character, collecting escaped byte + */ +enum rave_sp_deframer_state { + RAVE_SP_EXPECT_SOF, + RAVE_SP_EXPECT_DATA, + RAVE_SP_EXPECT_ESCAPED_DATA, +}; + +/** + * struct rave_sp_deframer - Device protocol deframer + * + * @state: Current state of the deframer + * @data: Buffer used to collect deframed data + * @length: Number of bytes de-framed so far + */ +struct rave_sp_deframer { + enum rave_sp_deframer_state state; + unsigned char data[RAVE_SP_RX_BUFFER_SIZE]; + size_t length; +}; + +/** + * struct rave_sp_reply - Reply as per RAVE device protocol + * + * @length: Expected reply length + * @data: Buffer to store reply payload in + * @code: Expected reply code + * @ackid: Expected reply ACK ID + * @completion: Successful reply reception completion + */ +struct rave_sp_reply { + size_t length; + void *data; + u8 code; + u8 ackid; + struct completion received; +}; + +/** + * struct rave_sp_checksum - Variant specific checksum implementation details + * + * @length: Caculated checksum length + * @subroutine: Utilized checksum algorithm implementation + */ +struct rave_sp_checksum { + size_t length; + void (*subroutine)(const u8 *, size_t, u8 *); +}; + +/** + * struct rave_sp_variant_cmds - Variant specific command routines + * + * @translate: Generic to variant specific command mapping routine + * + */ +struct rave_sp_variant_cmds { + int (*translate)(enum rave_sp_command); +}; + +/** + * struct rave_sp_variant - RAVE supervisory processor core variant + * + * @checksum: Variant specific checksum implementation + * @cmd: Variant specific command pointer table + * + */ +struct rave_sp_variant { + const struct rave_sp_checksum *checksum; + struct rave_sp_variant_cmds cmd; +}; + +/** + * struct rave_sp - RAVE supervisory processor core + * + * @serdev: Pointer to underlying serdev + * @deframer: Stored state of the protocol deframer + * @ackid: ACK ID used in last reply sent to the device + * @bus_lock: Lock to serialize access to the device + * @reply_lock: Lock protecting @reply + * @reply: Pointer to memory to store reply payload + * + * @variant: Device variant specific information + * @event_notifier_list: Input event notification chain + * + */ +struct rave_sp { + struct serdev_device *serdev; + struct rave_sp_deframer deframer; + atomic_t ackid; + struct mutex bus_lock; + struct mutex reply_lock; + struct rave_sp_reply *reply; + + const struct rave_sp_variant *variant; + struct blocking_notifier_head event_notifier_list; +}; + +static bool rave_sp_id_is_event(u8 code) +{ + return (code & 0xF0) == RAVE_SP_EVNT_BASE; +} + +static void rave_sp_unregister_event_notifier(struct device *dev, void *res) +{ + struct rave_sp *sp = dev_get_drvdata(dev->parent); + struct notifier_block *nb = *(struct notifier_block **)res; + struct blocking_notifier_head *bnh = &sp->event_notifier_list; + + WARN_ON(blocking_notifier_chain_unregister(bnh, nb)); +} + +int devm_rave_sp_register_event_notifier(struct device *dev, + struct notifier_block *nb) +{ + struct rave_sp *sp = dev_get_drvdata(dev->parent); + struct notifier_block **rcnb; + int ret; + + rcnb = devres_alloc(rave_sp_unregister_event_notifier, + sizeof(*rcnb), GFP_KERNEL); + if (!rcnb) + return -ENOMEM; + + ret = blocking_notifier_chain_register(&sp->event_notifier_list, nb); + if (!ret) { + *rcnb = nb; + devres_add(dev, rcnb); + } else { + devres_free(rcnb); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_rave_sp_register_event_notifier); + +static void csum_8b2c(const u8 *buf, size_t size, u8 *crc) +{ + *crc = *buf++; + size--; + + while (size--) + *crc += *buf++; + + *crc = 1 + ~(*crc); +} + +static void csum_ccitt(const u8 *buf, size_t size, u8 *crc) +{ + const u16 calculated = crc_ccitt_false(0xffff, buf, size); + + /* + * While the rest of the wire protocol is little-endian, + * CCITT-16 CRC in RDU2 device is sent out in big-endian order. + */ + put_unaligned_be16(calculated, crc); +} + +static void *stuff(unsigned char *dest, const unsigned char *src, size_t n) +{ + while (n--) { + const unsigned char byte = *src++; + + switch (byte) { + case RAVE_SP_STX: + case RAVE_SP_ETX: + case RAVE_SP_DLE: + *dest++ = RAVE_SP_DLE; + /* FALLTHROUGH */ + default: + *dest++ = byte; + } + } + + return dest; +} + +static int rave_sp_write(struct rave_sp *sp, const u8 *data, u8 data_size) +{ + const size_t checksum_length = sp->variant->checksum->length; + unsigned char frame[RAVE_SP_TX_BUFFER_SIZE]; + unsigned char crc[RAVE_SP_CHECKSUM_SIZE]; + unsigned char *dest = frame; + size_t length; + + if (WARN_ON(checksum_length > sizeof(crc))) + return -ENOMEM; + + if (WARN_ON(data_size > sizeof(frame))) + return -ENOMEM; + + sp->variant->checksum->subroutine(data, data_size, crc); + + *dest++ = RAVE_SP_STX; + dest = stuff(dest, data, data_size); + dest = stuff(dest, crc, checksum_length); + *dest++ = RAVE_SP_ETX; + + length = dest - frame; + + print_hex_dump(KERN_DEBUG, "rave-sp tx: ", DUMP_PREFIX_NONE, + 16, 1, frame, length, false); + + return serdev_device_write(sp->serdev, frame, length, HZ); +} + +static u8 rave_sp_reply_code(u8 command) +{ + /* + * There isn't a single rule that describes command code -> + * ACK code transformation, but, going through various + * versions of ICDs, there appear to be three distinct groups + * that can be described by simple transformation. + */ + switch (command) { + case 0xA0 ... 0xBE: + /* + * Commands implemented by firmware found in RDU1 and + * older devices all seem to obey the following rule + */ + return command + 0x20; + case 0xE0 ... 0xEF: + /* + * Events emitted by all versions of the firmare use + * least significant bit to get an ACK code + */ + return command | 0x01; + default: + /* + * Commands implemented by firmware found in RDU2 are + * similar to "old" commands, but they use slightly + * different offset + */ + return command + 0x40; + } +} + +int rave_sp_exec(struct rave_sp *sp, + void *__data, size_t data_size, + void *reply_data, size_t reply_data_size) +{ + struct rave_sp_reply reply = { + .data = reply_data, + .length = reply_data_size, + .received = COMPLETION_INITIALIZER_ONSTACK(reply.received), + }; + unsigned char *data = __data; + int command, ret = 0; + u8 ackid; + + command = sp->variant->cmd.translate(data[0]); + if (command < 0) + return command; + + ackid = atomic_inc_return(&sp->ackid); + reply.ackid = ackid; + reply.code = rave_sp_reply_code((u8)command), + + mutex_lock(&sp->bus_lock); + + mutex_lock(&sp->reply_lock); + sp->reply = &reply; + mutex_unlock(&sp->reply_lock); + + data[0] = command; + data[1] = ackid; + + rave_sp_write(sp, data, data_size); + + if (!wait_for_completion_timeout(&reply.received, HZ)) { + dev_err(&sp->serdev->dev, "Command timeout\n"); + ret = -ETIMEDOUT; + + mutex_lock(&sp->reply_lock); + sp->reply = NULL; + mutex_unlock(&sp->reply_lock); + } + + mutex_unlock(&sp->bus_lock); + return ret; +} +EXPORT_SYMBOL_GPL(rave_sp_exec); + +static void rave_sp_receive_event(struct rave_sp *sp, + const unsigned char *data, size_t length) +{ + u8 cmd[] = { + [0] = rave_sp_reply_code(data[0]), + [1] = data[1], + }; + + rave_sp_write(sp, cmd, sizeof(cmd)); + + blocking_notifier_call_chain(&sp->event_notifier_list, + rave_sp_action_pack(data[0], data[2]), + NULL); +} + +static void rave_sp_receive_reply(struct rave_sp *sp, + const unsigned char *data, size_t length) +{ + struct device *dev = &sp->serdev->dev; + struct rave_sp_reply *reply; + const size_t payload_length = length - 2; + + mutex_lock(&sp->reply_lock); + reply = sp->reply; + + if (reply) { + if (reply->code == data[0] && reply->ackid == data[1] && + payload_length >= reply->length) { + /* + * We are relying on memcpy(dst, src, 0) to be a no-op + * when handling commands that have a no-payload reply + */ + memcpy(reply->data, &data[2], reply->length); + complete(&reply->received); + sp->reply = NULL; + } else { + dev_err(dev, "Ignoring incorrect reply\n"); + dev_dbg(dev, "Code: expected = 0x%08x received = 0x%08x\n", + reply->code, data[0]); + dev_dbg(dev, "ACK ID: expected = 0x%08x received = 0x%08x\n", + reply->ackid, data[1]); + dev_dbg(dev, "Length: expected = %zu received = %zu\n", + reply->length, payload_length); + } + } + + mutex_unlock(&sp->reply_lock); +} + +static void rave_sp_receive_frame(struct rave_sp *sp, + const unsigned char *data, + size_t length) +{ + const size_t checksum_length = sp->variant->checksum->length; + const size_t payload_length = length - checksum_length; + const u8 *crc_reported = &data[payload_length]; + struct device *dev = &sp->serdev->dev; + u8 crc_calculated[checksum_length]; + + print_hex_dump(KERN_DEBUG, "rave-sp rx: ", DUMP_PREFIX_NONE, + 16, 1, data, length, false); + + if (unlikely(length <= checksum_length)) { + dev_warn(dev, "Dropping short frame\n"); + return; + } + + sp->variant->checksum->subroutine(data, payload_length, + crc_calculated); + + if (memcmp(crc_calculated, crc_reported, checksum_length)) { + dev_warn(dev, "Dropping bad frame\n"); + return; + } + + if (rave_sp_id_is_event(data[0])) + rave_sp_receive_event(sp, data, length); + else + rave_sp_receive_reply(sp, data, length); +} + +static int rave_sp_receive_buf(struct serdev_device *serdev, + const unsigned char *buf, size_t size) +{ + struct device *dev = &serdev->dev; + struct rave_sp *sp = dev_get_drvdata(dev); + struct rave_sp_deframer *deframer = &sp->deframer; + const unsigned char *src = buf; + const unsigned char *end = buf + size; + + while (src < end) { + const unsigned char byte = *src++; + + switch (deframer->state) { + case RAVE_SP_EXPECT_SOF: + if (byte == RAVE_SP_STX) + deframer->state = RAVE_SP_EXPECT_DATA; + break; + + case RAVE_SP_EXPECT_DATA: + /* + * Treat special byte values first + */ + switch (byte) { + case RAVE_SP_ETX: + rave_sp_receive_frame(sp, + deframer->data, + deframer->length); + /* + * Once we extracted a complete frame + * out of a stream, we call it done + * and proceed to bailing out while + * resetting the framer to initial + * state, regardless if we've consumed + * all of the stream or not. + */ + goto reset_framer; + case RAVE_SP_STX: + dev_warn(dev, "Bad frame: STX before ETX\n"); + /* + * If we encounter second "start of + * the frame" marker before seeing + * corresponding "end of frame", we + * reset the framer and ignore both: + * frame started by first SOF and + * frame started by current SOF. + * + * NOTE: The above means that only the + * frame started by third SOF, sent + * after this one will have a chance + * to get throught. + */ + goto reset_framer; + case RAVE_SP_DLE: + deframer->state = RAVE_SP_EXPECT_ESCAPED_DATA; + /* + * If we encounter escape sequence we + * need to skip it and collect the + * byte that follows. We do it by + * forcing the next iteration of the + * encompassing while loop. + */ + continue; + } + /* + * For the rest of the bytes, that are not + * speical snoflakes, we do the same thing + * that we do to escaped data - collect it in + * deframer buffer + */ + + /* FALLTHROUGH */ + + case RAVE_SP_EXPECT_ESCAPED_DATA: + deframer->data[deframer->length++] = byte; + + if (deframer->length == sizeof(deframer->data)) { + dev_warn(dev, "Bad frame: Too long\n"); + /* + * If the amount of data we've + * accumulated for current frame so + * far starts to exceed the capacity + * of deframer's buffer, there's + * nothing else we can do but to + * discard that data and start + * assemblying a new frame again + */ + goto reset_framer; + } + + /* + * We've extracted out special byte, now we + * can go back to regular data collecting + */ + deframer->state = RAVE_SP_EXPECT_DATA; + break; + } + } + + /* + * The only way to get out of the above loop and end up here + * is throught consuming all of the supplied data, so here we + * report that we processed it all. + */ + return size; + +reset_framer: + /* + * NOTE: A number of codepaths that will drop us here will do + * so before consuming all 'size' bytes of the data passed by + * serdev layer. We rely on the fact that serdev layer will + * re-execute this handler with the remainder of the Rx bytes + * once we report actual number of bytes that we processed. + */ + deframer->state = RAVE_SP_EXPECT_SOF; + deframer->length = 0; + + return src - buf; +} + +static int rave_sp_rdu1_cmd_translate(enum rave_sp_command command) +{ + if (command >= RAVE_SP_CMD_STATUS && + command <= RAVE_SP_CMD_CONTROL_EVENTS) + return command; + + return -EINVAL; +} + +static int rave_sp_rdu2_cmd_translate(enum rave_sp_command command) +{ + if (command >= RAVE_SP_CMD_GET_FIRMWARE_VERSION && + command <= RAVE_SP_CMD_GET_GPIO_STATE) + return command; + + if (command == RAVE_SP_CMD_REQ_COPPER_REV) { + /* + * As per RDU2 ICD 3.4.47 CMD_GET_COPPER_REV code is + * different from that for RDU1 and it is set to 0x28. + */ + return 0x28; + } + + return rave_sp_rdu1_cmd_translate(command); +} + +static int rave_sp_default_cmd_translate(enum rave_sp_command command) +{ + /* + * All of the following command codes were taken from "Table : + * Communications Protocol Message Types" in section 3.3 + * "MESSAGE TYPES" of Rave PIC24 ICD. + */ + switch (command) { + case RAVE_SP_CMD_GET_FIRMWARE_VERSION: + return 0x11; + case RAVE_SP_CMD_GET_BOOTLOADER_VERSION: + return 0x12; + case RAVE_SP_CMD_BOOT_SOURCE: + return 0x14; + case RAVE_SP_CMD_SW_WDT: + return 0x1C; + case RAVE_SP_CMD_RESET: + return 0x1E; + case RAVE_SP_CMD_RESET_REASON: + return 0x1F; + default: + return -EINVAL; + } +} + +static const struct rave_sp_checksum rave_sp_checksum_8b2c = { + .length = 1, + .subroutine = csum_8b2c, +}; + +static const struct rave_sp_checksum rave_sp_checksum_ccitt = { + .length = 2, + .subroutine = csum_ccitt, +}; + +static const struct rave_sp_variant rave_sp_legacy = { + .checksum = &rave_sp_checksum_8b2c, + .cmd = { + .translate = rave_sp_default_cmd_translate, + }, +}; + +static const struct rave_sp_variant rave_sp_rdu1 = { + .checksum = &rave_sp_checksum_8b2c, + .cmd = { + .translate = rave_sp_rdu1_cmd_translate, + }, +}; + +static const struct rave_sp_variant rave_sp_rdu2 = { + .checksum = &rave_sp_checksum_ccitt, + .cmd = { + .translate = rave_sp_rdu2_cmd_translate, + }, +}; + +static const struct of_device_id rave_sp_dt_ids[] = { + { .compatible = "zii,rave-sp-niu", .data = &rave_sp_legacy }, + { .compatible = "zii,rave-sp-mezz", .data = &rave_sp_legacy }, + { .compatible = "zii,rave-sp-esb", .data = &rave_sp_legacy }, + { .compatible = "zii,rave-sp-rdu1", .data = &rave_sp_rdu1 }, + { .compatible = "zii,rave-sp-rdu2", .data = &rave_sp_rdu2 }, + { /* sentinel */ } +}; + +static const struct serdev_device_ops rave_sp_serdev_device_ops = { + .receive_buf = rave_sp_receive_buf, + .write_wakeup = serdev_device_write_wakeup, +}; + +static int rave_sp_probe(struct serdev_device *serdev) +{ + struct device *dev = &serdev->dev; + struct rave_sp *sp; + u32 baud; + int ret; + + if (of_property_read_u32(dev->of_node, "current-speed", &baud)) { + dev_err(dev, + "'current-speed' is not specified in device node\n"); + return -EINVAL; + } + + sp = devm_kzalloc(dev, sizeof(*sp), GFP_KERNEL); + if (!sp) + return -ENOMEM; + + sp->serdev = serdev; + dev_set_drvdata(dev, sp); + + sp->variant = of_device_get_match_data(dev); + if (!sp->variant) + return -ENODEV; + + mutex_init(&sp->bus_lock); + mutex_init(&sp->reply_lock); + BLOCKING_INIT_NOTIFIER_HEAD(&sp->event_notifier_list); + + serdev_device_set_client_ops(serdev, &rave_sp_serdev_device_ops); + ret = devm_serdev_device_open(dev, serdev); + if (ret) + return ret; + + serdev_device_set_baudrate(serdev, baud); + + return devm_of_platform_populate(dev); +} + +MODULE_DEVICE_TABLE(of, rave_sp_dt_ids); + +static struct serdev_device_driver rave_sp_drv = { + .probe = rave_sp_probe, + .driver = { + .name = "rave-sp", + .of_match_table = rave_sp_dt_ids, + }, +}; +module_serdev_device_driver(rave_sp_drv); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Andrey Vostrikov "); +MODULE_AUTHOR("Nikita Yushchenko "); +MODULE_AUTHOR("Andrey Smirnov "); +MODULE_DESCRIPTION("RAVE SP core driver"); diff --git a/include/linux/mfd/rave-sp.h b/include/linux/mfd/rave-sp.h new file mode 100644 index 000000000000..796fb9794c9e --- /dev/null +++ b/include/linux/mfd/rave-sp.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +/* + * Core definitions for RAVE SP MFD driver. + * + * Copyright (C) 2017 Zodiac Inflight Innovations + */ + +#ifndef _LINUX_RAVE_SP_H_ +#define _LINUX_RAVE_SP_H_ + +#include + +enum rave_sp_command { + RAVE_SP_CMD_GET_FIRMWARE_VERSION = 0x20, + RAVE_SP_CMD_GET_BOOTLOADER_VERSION = 0x21, + RAVE_SP_CMD_BOOT_SOURCE = 0x26, + RAVE_SP_CMD_GET_BOARD_COPPER_REV = 0x2B, + RAVE_SP_CMD_GET_GPIO_STATE = 0x2F, + + RAVE_SP_CMD_STATUS = 0xA0, + RAVE_SP_CMD_SW_WDT = 0xA1, + RAVE_SP_CMD_PET_WDT = 0xA2, + RAVE_SP_CMD_RESET = 0xA7, + RAVE_SP_CMD_RESET_REASON = 0xA8, + + RAVE_SP_CMD_REQ_COPPER_REV = 0xB6, + RAVE_SP_CMD_GET_I2C_DEVICE_STATUS = 0xBA, + RAVE_SP_CMD_GET_SP_SILICON_REV = 0xB9, + RAVE_SP_CMD_CONTROL_EVENTS = 0xBB, + + RAVE_SP_EVNT_BASE = 0xE0, +}; + +struct rave_sp; + +static inline unsigned long rave_sp_action_pack(u8 event, u8 value) +{ + return ((unsigned long)value << 8) | event; +} + +static inline u8 rave_sp_action_unpack_event(unsigned long action) +{ + return action; +} + +static inline u8 rave_sp_action_unpack_value(unsigned long action) +{ + return action >> 8; +} + +int rave_sp_exec(struct rave_sp *sp, + void *__data, size_t data_size, + void *reply_data, size_t reply_data_size); + +struct device; +int devm_rave_sp_register_event_notifier(struct device *dev, + struct notifier_block *nb); + +#endif /* _LINUX_RAVE_SP_H_ */ -- cgit v1.2.3 From f058aa3faba60cf61b573bd519366c809b6f2727 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 29 Oct 2017 11:31:23 +0530 Subject: mfd: pcf50633: Fix spelling mistake: 'Falied' -> 'Failed' Trivial fix to spelling mistakes in 'pcf50633_client_dev_register'. Signed-off-by: Arvind Yadav Signed-off-by: Lee Jones --- drivers/mfd/pcf50633-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 6155d123a84e..f952dff6765f 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -149,7 +149,7 @@ pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, *pdev = platform_device_alloc(name, -1); if (!*pdev) { - dev_err(pcf->dev, "Falied to allocate %s\n", name); + dev_err(pcf->dev, "Failed to allocate %s\n", name); return; } -- cgit v1.2.3 From e368866ea7a88f5ea16544c4e037b22d993dc3df Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 29 Oct 2017 12:58:51 +0000 Subject: mfd: ti_am335x_tscadc: Remove redundant assignment to node Node is being initialized a value that is never read, it is being written over a few statements into the function with the return value from call to of_get_child_by_name. Hence this initialization can be removed. Cleans up clang warning: drivers/mfd/ti_am335x_tscadc.c:127:22: warning: Value stored to 'node' during its initialization is never read Signed-off-by: Colin Ian King Signed-off-by: Lee Jones --- drivers/mfd/ti_am335x_tscadc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 0f3fab47fe48..3cd958a31f36 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -124,7 +124,7 @@ static int ti_tscadc_probe(struct platform_device *pdev) struct ti_tscadc_dev *tscadc; struct resource *res; struct clk *clk; - struct device_node *node = pdev->dev.of_node; + struct device_node *node; struct mfd_cell *cell; struct property *prop; const __be32 *cur; -- cgit v1.2.3 From 0a5d79bfc0154bb587d5a439dc0e439d4d72f25b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 27 Oct 2017 17:20:45 +0200 Subject: mfd: ab8500-debugfs: Use common error handling code in ab8500_print_modem_registers() Add jump targets so that two error messages are stored only once at the end of this function implementation. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ab8500-debugfs.c | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index c1c815241e02..37f39b2a1aa1 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -1620,18 +1620,15 @@ static int ab8500_print_modem_registers(struct seq_file *s, void *p) err = abx500_get_register_interruptible(dev, AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG, &orig_value); - if (err < 0) { - dev_err(dev, "ab->read fail %d\n", err); - return err; - } + if (err < 0) + goto report_read_failure; + /* Config 1 will allow APE side to read SIM registers */ err = abx500_set_register_interruptible(dev, AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG, AB8500_SUPPLY_CONTROL_CONFIG_1); - if (err < 0) { - dev_err(dev, "ab->write fail %d\n", err); - return err; - } + if (err < 0) + goto report_write_failure; seq_printf(s, " bank 0x%02X:\n", bank); @@ -1641,19 +1638,25 @@ static int ab8500_print_modem_registers(struct seq_file *s, void *p) for (reg = AB8500_FIRST_SIM_REG; reg <= last_sim_reg; reg++) { err = abx500_get_register_interruptible(dev, bank, reg, &value); - if (err < 0) { - dev_err(dev, "ab->read fail %d\n", err); - return err; - } + if (err < 0) + goto report_read_failure; + seq_printf(s, " [0x%02X/0x%02X]: 0x%02X\n", bank, reg, value); } err = abx500_set_register_interruptible(dev, AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG, orig_value); - if (err < 0) { - dev_err(dev, "ab->write fail %d\n", err); - return err; - } + if (err < 0) + goto report_write_failure; + return 0; + +report_read_failure: + dev_err(dev, "ab->read fail %d\n", err); + return err; + +report_write_failure: + dev_err(dev, "ab->write fail %d\n", err); + return err; } static int ab8500_modem_open(struct inode *inode, struct file *file) -- cgit v1.2.3 From 572ff4d560be3784205b224cd67d6715620092d7 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 24 Oct 2017 13:51:36 +0530 Subject: mfd: palmas: Assign the right powerhold mask for tps65917 The powerhold mask for TPS65917 is different when comapred to the other palmas versions. Hence assign the right mask that enables power off of tps65917 pmic correctly. Signed-off-by: Keerthy Signed-off-by: Lee Jones --- drivers/mfd/palmas.c | 10 +++++++++- include/linux/mfd/palmas.h | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index 3922a93f9f92..663a2398b6b1 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -430,6 +430,7 @@ static void palmas_power_off(void) { unsigned int addr; int ret, slave; + u8 powerhold_mask; struct device_node *np = palmas_dev->dev->of_node; if (of_property_read_bool(np, "ti,palmas-override-powerhold")) { @@ -437,8 +438,15 @@ static void palmas_power_off(void) PALMAS_PRIMARY_SECONDARY_PAD2); slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE); + if (of_device_is_compatible(np, "ti,tps65917")) + powerhold_mask = + TPS65917_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK; + else + powerhold_mask = + PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK; + ret = regmap_update_bits(palmas_dev->regmap[slave], addr, - PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK, 0); + powerhold_mask, 0); if (ret) dev_err(palmas_dev->dev, "Unable to write PRIMARY_SECONDARY_PAD2 %d\n", diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index 3c8568aa82a5..75e5c8ff85fc 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -3733,6 +3733,9 @@ enum usb_irq_events { #define TPS65917_REGEN3_CTRL_MODE_ACTIVE 0x01 #define TPS65917_REGEN3_CTRL_MODE_ACTIVE_SHIFT 0x00 +/* POWERHOLD Mask field for PRIMARY_SECONDARY_PAD2 register */ +#define TPS65917_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK 0xC + /* Registers for function RESOURCE */ #define TPS65917_REGEN1_CTRL 0x2 #define TPS65917_PLLEN_CTRL 0x3 -- cgit v1.2.3 From d501ff903bdd735b215bded10958d8f794ca0339 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 14 Nov 2017 14:43:28 +0000 Subject: mfd: cros ec: spi: Simplify delay handling between SPI messages The EC SPI driver prevents SPI transfers being to rapidly by keeping track of the time the last transfer was issued via the 'last_transfer_ns' variable. Previously, if the 'last_transfer_ns' variable was zero, this indicated that no previous transfer had been sent and that no delay was needed. However, the EC SPI driver has been updated to always initialise the 'last_transfer_ns' variable during probe and therefore, it is no longer necessary to test if it is zero. Remove the code that checks if this variable is zero. Signed-off-by: Jon Hunter Reviewed-by: Brian Norris Reviewed-by: Douglas Anderson Acked-by: Benson Leung Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_spi.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index c9714072e224..54cb760342f5 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c @@ -72,8 +72,7 @@ * struct cros_ec_spi - information about a SPI-connected EC * * @spi: SPI device we are connected to - * @last_transfer_ns: time that we last finished a transfer, or 0 if there - * if no record + * @last_transfer_ns: time that we last finished a transfer. * @start_of_msg_delay: used to set the delay_usecs on the spi_transfer that * is sent when we want to turn on CS at the start of a transaction. * @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that @@ -378,18 +377,15 @@ static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev, u8 *rx_buf; u8 sum; int ret = 0, final_ret; + unsigned long delay; len = cros_ec_prepare_tx(ec_dev, ec_msg); dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); /* If it's too soon to do another transaction, wait */ - if (ec_spi->last_transfer_ns) { - unsigned long delay; /* The delay completed so far */ - - delay = ktime_get_ns() - ec_spi->last_transfer_ns; - if (delay < EC_SPI_RECOVERY_TIME_NS) - ndelay(EC_SPI_RECOVERY_TIME_NS - delay); - } + delay = ktime_get_ns() - ec_spi->last_transfer_ns; + if (delay < EC_SPI_RECOVERY_TIME_NS) + ndelay(EC_SPI_RECOVERY_TIME_NS - delay); rx_buf = kzalloc(len, GFP_KERNEL); if (!rx_buf) @@ -510,18 +506,15 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev, u8 *rx_buf; int sum; int ret = 0, final_ret; + unsigned long delay; len = cros_ec_prepare_tx(ec_dev, ec_msg); dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); /* If it's too soon to do another transaction, wait */ - if (ec_spi->last_transfer_ns) { - unsigned long delay; /* The delay completed so far */ - - delay = ktime_get_ns() - ec_spi->last_transfer_ns; - if (delay < EC_SPI_RECOVERY_TIME_NS) - ndelay(EC_SPI_RECOVERY_TIME_NS - delay); - } + delay = ktime_get_ns() - ec_spi->last_transfer_ns; + if (delay < EC_SPI_RECOVERY_TIME_NS) + ndelay(EC_SPI_RECOVERY_TIME_NS - delay); rx_buf = kzalloc(len, GFP_KERNEL); if (!rx_buf) -- cgit v1.2.3 From 299fad6b9b6e4b50929861c701af64a36cde0f31 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 7 Nov 2017 17:14:12 +0900 Subject: mfd: tmio: Move register macros to tmio_core.c These registers are only used in drivers/mfd/tmio_core.c Signed-off-by: Masahiro Yamada Acked-by: Wolfram Sang Signed-off-by: Lee Jones --- drivers/mfd/tmio_core.c | 20 ++++++++++++++++++++ include/linux/mfd/tmio.h | 20 -------------------- 2 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tmio_core.c b/drivers/mfd/tmio_core.c index 83af78c1b0eb..ebf54cc28f7a 100644 --- a/drivers/mfd/tmio_core.c +++ b/drivers/mfd/tmio_core.c @@ -9,6 +9,26 @@ #include #include +#define CNF_CMD 0x04 +#define CNF_CTL_BASE 0x10 +#define CNF_INT_PIN 0x3d +#define CNF_STOP_CLK_CTL 0x40 +#define CNF_GCLK_CTL 0x41 +#define CNF_SD_CLK_MODE 0x42 +#define CNF_PIN_STATUS 0x44 +#define CNF_PWR_CTL_1 0x48 +#define CNF_PWR_CTL_2 0x49 +#define CNF_PWR_CTL_3 0x4a +#define CNF_CARD_DETECT_MODE 0x4c +#define CNF_SD_SLOT 0x50 +#define CNF_EXT_GCLK_CTL_1 0xf0 +#define CNF_EXT_GCLK_CTL_2 0xf1 +#define CNF_EXT_GCLK_CTL_3 0xf9 +#define CNF_SD_LED_EN_1 0xfa +#define CNF_SD_LED_EN_2 0xfe + +#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/ + int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base) { /* Enable the MMC/SD Control registers */ diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index e1cfe9194129..396a103c8bc6 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -25,26 +25,6 @@ writew((val) >> 16, (addr) + 2); \ } while (0) -#define CNF_CMD 0x04 -#define CNF_CTL_BASE 0x10 -#define CNF_INT_PIN 0x3d -#define CNF_STOP_CLK_CTL 0x40 -#define CNF_GCLK_CTL 0x41 -#define CNF_SD_CLK_MODE 0x42 -#define CNF_PIN_STATUS 0x44 -#define CNF_PWR_CTL_1 0x48 -#define CNF_PWR_CTL_2 0x49 -#define CNF_PWR_CTL_3 0x4a -#define CNF_CARD_DETECT_MODE 0x4c -#define CNF_SD_SLOT 0x50 -#define CNF_EXT_GCLK_CTL_1 0xf0 -#define CNF_EXT_GCLK_CTL_2 0xf1 -#define CNF_EXT_GCLK_CTL_3 0xf9 -#define CNF_SD_LED_EN_1 0xfa -#define CNF_SD_LED_EN_2 0xfe - -#define SDCREN 0x2 /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/ - #define sd_config_write8(base, shift, reg, val) \ tmio_iowrite8((val), (base) + ((reg) << (shift))) #define sd_config_write16(base, shift, reg, val) \ -- cgit v1.2.3 From 263a7c57db8d59f7fdea39ea525f48d3d42ba697 Mon Sep 17 00:00:00 2001 From: Vasyl Gomonovych Date: Mon, 20 Nov 2017 22:02:55 +0100 Subject: mfd: kempld-core: Use resource_size function on resource object drivers/mfd/kempld-core.c:461:13-16: WARNING: Suspicious code. resource_size is maybe missing with ioport Generated by: scripts/coccinelle/api/resource_size.cocci Signed-off-by: Vasyl Gomonovych Signed-off-by: Lee Jones --- drivers/mfd/kempld-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index 55d824b3a808..390b27cb2c2e 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -458,7 +458,7 @@ static int kempld_probe(struct platform_device *pdev) return -EINVAL; pld->io_base = devm_ioport_map(dev, ioport->start, - ioport->end - ioport->start); + resource_size(ioport)); if (!pld->io_base) return -ENOMEM; -- cgit v1.2.3 From a23670df27829558965a3b96a43bd67ed3064988 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 29 Nov 2017 09:00:43 +0100 Subject: mfd: pm8xxx: Make elegible for COMPILE_TEST This should be enabled so that we get full compile coverage of the PM8xxx MFD core with the different subdrivers. Tested on the build servers. Suggested-by: Jonathan Cameron Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index fb884fab0b8d..b860eb5aa194 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -887,7 +887,7 @@ config UCB1400_CORE config MFD_PM8XXX tristate "Qualcomm PM8xxx PMIC chips driver" - depends on (ARM || HEXAGON) + depends on (ARM || HEXAGON || COMPILE_TEST) select IRQ_DOMAIN select MFD_CORE select REGMAP -- cgit v1.2.3 From 2bb3253c30d517f3d574610ed0523a469f58562d Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Tue, 5 Dec 2017 15:46:47 +0100 Subject: mfd: axp20x: Add pinctrl cell for AXP813 As GPIO/pinctrl driver now supports AXP813, add a cell for it. Signed-off-by: Quentin Schulz Acked-by: Maxime Ripard Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/axp20x.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 2468b431bb22..d8c92fbbd170 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -878,6 +878,9 @@ static struct mfd_cell axp813_cells[] = { .resources = axp803_pek_resources, }, { .name = "axp20x-regulator", + }, { + .name = "axp20x-gpio", + .of_compatible = "x-powers,axp813-gpio", } }; -- cgit v1.2.3 From fa93f5b7aac54f08dea386fa4d79aa29bf54370e Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Tue, 5 Dec 2017 16:24:18 +0100 Subject: mfd: stm32: Adopt SPDX identifier Add SPDX identifier Signed-off-by: Benjamin Gaignard Acked-by: Philippe Ombredanne Signed-off-by: Lee Jones --- drivers/mfd/stm32-lptimer.c | 6 +----- drivers/mfd/stm32-timers.c | 4 +--- include/linux/mfd/stm32-lptimer.h | 6 +----- include/linux/mfd/stm32-timers.h | 4 +--- 4 files changed, 4 insertions(+), 16 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/stm32-lptimer.c b/drivers/mfd/stm32-lptimer.c index 075330a25f61..a00f99f36559 100644 --- a/drivers/mfd/stm32-lptimer.c +++ b/drivers/mfd/stm32-lptimer.c @@ -1,13 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * STM32 Low-Power Timer parent driver. - * * Copyright (C) STMicroelectronics 2017 - * * Author: Fabrice Gasnier - * * Inspired by Benjamin Gaignard's stm32-timers driver - * - * License terms: GNU General Public License (GPL), version 2 */ #include diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c index a6675a449409..1d347e5dfa79 100644 --- a/drivers/mfd/stm32-timers.c +++ b/drivers/mfd/stm32-timers.c @@ -1,9 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) STMicroelectronics 2016 - * * Author: Benjamin Gaignard - * - * License terms: GNU General Public License (GPL), version 2 */ #include diff --git a/include/linux/mfd/stm32-lptimer.h b/include/linux/mfd/stm32-lptimer.h index 77c7cf40d9b4..605f62264825 100644 --- a/include/linux/mfd/stm32-lptimer.h +++ b/include/linux/mfd/stm32-lptimer.h @@ -1,13 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * STM32 Low-Power Timer parent driver. - * * Copyright (C) STMicroelectronics 2017 - * * Author: Fabrice Gasnier - * * Inspired by Benjamin Gaignard's stm32-timers driver - * - * License terms: GNU General Public License (GPL), version 2 */ #ifndef _LINUX_STM32_LPTIMER_H_ diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h index ce7346e7f77a..2aadab6f34a1 100644 --- a/include/linux/mfd/stm32-timers.h +++ b/include/linux/mfd/stm32-timers.h @@ -1,9 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (C) STMicroelectronics 2016 - * * Author: Benjamin Gaignard - * - * License terms: GNU General Public License (GPL), version 2 */ #ifndef _LINUX_STM32_GPTIMER_H_ -- cgit v1.2.3 From 63fb9cb51da257e48af9db6bbfe4ace8ade04ff3 Mon Sep 17 00:00:00 2001 From: Pravin Shedge Date: Wed, 6 Dec 2017 22:23:09 +0530 Subject: mfd: Remove duplicate includes These duplicate includes have been found with scripts/checkincludes.pl but they have been removed manually to avoid removing false positives. Signed-off-by: Pravin Shedge Signed-off-by: Lee Jones --- drivers/mfd/intel_soc_pmic_core.c | 1 - drivers/mfd/max77843.c | 1 - 2 files changed, 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c index 36adf9e8153e..274306d98ac1 100644 --- a/drivers/mfd/intel_soc_pmic_core.c +++ b/drivers/mfd/intel_soc_pmic_core.c @@ -16,7 +16,6 @@ * Author: Zhu, Lejun */ -#include #include #include #include diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c index dc5caeaaa6a1..da9612dbb222 100644 --- a/drivers/mfd/max77843.c +++ b/drivers/mfd/max77843.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 7fdec11015c374a6f0b29ceccf35f559c2208042 Mon Sep 17 00:00:00 2001 From: Romain Izard Date: Tue, 12 Dec 2017 17:21:19 +0100 Subject: atmel_flexcom: Support resuming after a chip reset The controller used by a flexcom module is configured at boot, and left alone after this. In the suspend mode called "backup with self-refresh" available on SAMA5D2, the chip will resume with most of its registers reset. In this case, we need to restore the state of the flexcom driver on resume. Signed-off-by: Romain Izard Acked-by: Alexandre Belloni Acked-by: Nicolas Ferre Tested-by: Nicolas Ferre Signed-off-by: Lee Jones --- drivers/mfd/atmel-flexcom.c | 63 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 15 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c index 064bde9cff5a..f684a93a3340 100644 --- a/drivers/mfd/atmel-flexcom.c +++ b/drivers/mfd/atmel-flexcom.c @@ -39,34 +39,43 @@ #define FLEX_MR_OPMODE(opmode) (((opmode) << FLEX_MR_OPMODE_OFFSET) & \ FLEX_MR_OPMODE_MASK) +struct atmel_flexcom { + void __iomem *base; + u32 opmode; + struct clk *clk; +}; static int atmel_flexcom_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - struct clk *clk; struct resource *res; - void __iomem *base; - u32 opmode; + struct atmel_flexcom *ddata; int err; - err = of_property_read_u32(np, "atmel,flexcom-mode", &opmode); + ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + platform_set_drvdata(pdev, ddata); + + err = of_property_read_u32(np, "atmel,flexcom-mode", &ddata->opmode); if (err) return err; - if (opmode < ATMEL_FLEXCOM_MODE_USART || - opmode > ATMEL_FLEXCOM_MODE_TWI) + if (ddata->opmode < ATMEL_FLEXCOM_MODE_USART || + ddata->opmode > ATMEL_FLEXCOM_MODE_TWI) return -EINVAL; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); + ddata->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ddata->base)) + return PTR_ERR(ddata->base); - clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(clk)) - return PTR_ERR(clk); + ddata->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ddata->clk)) + return PTR_ERR(ddata->clk); - err = clk_prepare_enable(clk); + err = clk_prepare_enable(ddata->clk); if (err) return err; @@ -76,9 +85,9 @@ static int atmel_flexcom_probe(struct platform_device *pdev) * inaccessible and are read as zero. Also the external I/O lines of the * Flexcom are muxed to reach the selected device. */ - writel(FLEX_MR_OPMODE(opmode), base + FLEX_MR); + writel(FLEX_MR_OPMODE(ddata->opmode), ddata->base + FLEX_MR); - clk_disable_unprepare(clk); + clk_disable_unprepare(ddata->clk); return devm_of_platform_populate(&pdev->dev); } @@ -89,10 +98,34 @@ static const struct of_device_id atmel_flexcom_of_match[] = { }; MODULE_DEVICE_TABLE(of, atmel_flexcom_of_match); +#ifdef CONFIG_PM_SLEEP +static int atmel_flexcom_resume(struct device *dev) +{ + struct atmel_flexcom *ddata = dev_get_drvdata(dev); + int err; + u32 val; + + err = clk_prepare_enable(ddata->clk); + if (err) + return err; + + val = FLEX_MR_OPMODE(ddata->opmode), + writel(val, ddata->base + FLEX_MR); + + clk_disable_unprepare(ddata->clk); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(atmel_flexcom_pm_ops, NULL, + atmel_flexcom_resume); + static struct platform_driver atmel_flexcom_driver = { .probe = atmel_flexcom_probe, .driver = { .name = "atmel_flexcom", + .pm = &atmel_flexcom_pm_ops, .of_match_table = atmel_flexcom_of_match, }, }; -- cgit v1.2.3 From 156d07050b34605dafc8a6bf493d69b2b998d239 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 14 Dec 2017 12:51:21 +0200 Subject: mfd: ab8500: Introduce DEFINE_SHOW_ATTRIBUTE() macro This macro deduplicates a lot of similar code in the ab8500-debugfs.c module. Targeting to be moved to seq_file.h eventually. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ab8500-debugfs.c | 406 +++++++------------------------------------ 1 file changed, 62 insertions(+), 344 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 37f39b2a1aa1..1afa27de7191 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -1258,6 +1258,19 @@ static struct ab8500_prcmu_ranges ab8540_debug_ranges[AB8500_NUM_BANKS] = { }, }; +#define DEFINE_SHOW_ATTRIBUTE(__name) \ +static int __name ## _open(struct inode *inode, struct file *file) \ +{ \ + return single_open(file, __name ## _show, inode->i_private); \ +} \ + \ +static const struct file_operations __name ## _fops = { \ + .owner = THIS_MODULE, \ + .open = __name ## _open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ +} \ static irqreturn_t ab8500_debug_handler(int irq, void *data) { @@ -1318,7 +1331,7 @@ static int ab8500_registers_print(struct device *dev, u32 bank, return 0; } -static int ab8500_print_bank_registers(struct seq_file *s, void *p) +static int ab8500_bank_registers_show(struct seq_file *s, void *p) { struct device *dev = s->private; u32 bank = debug_bank; @@ -1330,18 +1343,7 @@ static int ab8500_print_bank_registers(struct seq_file *s, void *p) return ab8500_registers_print(dev, bank, s); } -static int ab8500_registers_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_print_bank_registers, inode->i_private); -} - -static const struct file_operations ab8500_registers_fops = { - .open = ab8500_registers_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(ab8500_bank_registers); static int ab8500_print_all_banks(struct seq_file *s, void *p) { @@ -1528,7 +1530,7 @@ void ab8500_debug_register_interrupt(int line) num_interrupts[line]++; } -static int ab8500_interrupts_print(struct seq_file *s, void *p) +static int ab8500_interrupts_show(struct seq_file *s, void *p) { int line; @@ -1557,10 +1559,7 @@ static int ab8500_interrupts_print(struct seq_file *s, void *p) return 0; } -static int ab8500_interrupts_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_interrupts_print, inode->i_private); -} +DEFINE_SHOW_ATTRIBUTE(ab8500_interrupts); /* * - HWREG DB8500 formated routines @@ -1603,7 +1602,7 @@ static int ab8500_hwreg_open(struct inode *inode, struct file *file) #define AB8500_LAST_SIM_REG 0x8B #define AB8505_LAST_SIM_REG 0x8C -static int ab8500_print_modem_registers(struct seq_file *s, void *p) +static int ab8500_modem_show(struct seq_file *s, void *p) { struct device *dev = s->private; struct ab8500 *ab8500; @@ -1659,21 +1658,9 @@ report_write_failure: return err; } -static int ab8500_modem_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_print_modem_registers, - inode->i_private); -} - -static const struct file_operations ab8500_modem_fops = { - .open = ab8500_modem_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(ab8500_modem); -static int ab8500_gpadc_bat_ctrl_print(struct seq_file *s, void *p) +static int ab8500_gpadc_bat_ctrl_show(struct seq_file *s, void *p) { int bat_ctrl_raw; int bat_ctrl_convert; @@ -1690,21 +1677,9 @@ static int ab8500_gpadc_bat_ctrl_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_bat_ctrl_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_gpadc_bat_ctrl_print, - inode->i_private); -} - -static const struct file_operations ab8500_gpadc_bat_ctrl_fops = { - .open = ab8500_gpadc_bat_ctrl_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_bat_ctrl); -static int ab8500_gpadc_btemp_ball_print(struct seq_file *s, void *p) +static int ab8500_gpadc_btemp_ball_show(struct seq_file *s, void *p) { int btemp_ball_raw; int btemp_ball_convert; @@ -1721,22 +1696,9 @@ static int ab8500_gpadc_btemp_ball_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_btemp_ball_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ab8500_gpadc_btemp_ball_print, - inode->i_private); -} +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_btemp_ball); -static const struct file_operations ab8500_gpadc_btemp_ball_fops = { - .open = ab8500_gpadc_btemp_ball_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8500_gpadc_main_charger_v_print(struct seq_file *s, void *p) +static int ab8500_gpadc_main_charger_v_show(struct seq_file *s, void *p) { int main_charger_v_raw; int main_charger_v_convert; @@ -1753,22 +1715,9 @@ static int ab8500_gpadc_main_charger_v_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_main_charger_v_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ab8500_gpadc_main_charger_v_print, - inode->i_private); -} +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_main_charger_v); -static const struct file_operations ab8500_gpadc_main_charger_v_fops = { - .open = ab8500_gpadc_main_charger_v_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8500_gpadc_acc_detect1_print(struct seq_file *s, void *p) +static int ab8500_gpadc_acc_detect1_show(struct seq_file *s, void *p) { int acc_detect1_raw; int acc_detect1_convert; @@ -1785,22 +1734,9 @@ static int ab8500_gpadc_acc_detect1_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_acc_detect1_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ab8500_gpadc_acc_detect1_print, - inode->i_private); -} - -static const struct file_operations ab8500_gpadc_acc_detect1_fops = { - .open = ab8500_gpadc_acc_detect1_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_acc_detect1); -static int ab8500_gpadc_acc_detect2_print(struct seq_file *s, void *p) +static int ab8500_gpadc_acc_detect2_show(struct seq_file *s, void *p) { int acc_detect2_raw; int acc_detect2_convert; @@ -1817,22 +1753,9 @@ static int ab8500_gpadc_acc_detect2_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_acc_detect2_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ab8500_gpadc_acc_detect2_print, - inode->i_private); -} +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_acc_detect2); -static const struct file_operations ab8500_gpadc_acc_detect2_fops = { - .open = ab8500_gpadc_acc_detect2_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8500_gpadc_aux1_print(struct seq_file *s, void *p) +static int ab8500_gpadc_aux1_show(struct seq_file *s, void *p) { int aux1_raw; int aux1_convert; @@ -1849,20 +1772,9 @@ static int ab8500_gpadc_aux1_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_aux1_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_gpadc_aux1_print, inode->i_private); -} - -static const struct file_operations ab8500_gpadc_aux1_fops = { - .open = ab8500_gpadc_aux1_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_aux1); -static int ab8500_gpadc_aux2_print(struct seq_file *s, void *p) +static int ab8500_gpadc_aux2_show(struct seq_file *s, void *p) { int aux2_raw; int aux2_convert; @@ -1879,20 +1791,9 @@ static int ab8500_gpadc_aux2_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_aux2_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_gpadc_aux2_print, inode->i_private); -} - -static const struct file_operations ab8500_gpadc_aux2_fops = { - .open = ab8500_gpadc_aux2_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_aux2); -static int ab8500_gpadc_main_bat_v_print(struct seq_file *s, void *p) +static int ab8500_gpadc_main_bat_v_show(struct seq_file *s, void *p) { int main_bat_v_raw; int main_bat_v_convert; @@ -1909,22 +1810,9 @@ static int ab8500_gpadc_main_bat_v_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_main_bat_v_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ab8500_gpadc_main_bat_v_print, - inode->i_private); -} +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_main_bat_v); -static const struct file_operations ab8500_gpadc_main_bat_v_fops = { - .open = ab8500_gpadc_main_bat_v_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8500_gpadc_vbus_v_print(struct seq_file *s, void *p) +static int ab8500_gpadc_vbus_v_show(struct seq_file *s, void *p) { int vbus_v_raw; int vbus_v_convert; @@ -1941,20 +1829,9 @@ static int ab8500_gpadc_vbus_v_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_vbus_v_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_gpadc_vbus_v_print, inode->i_private); -} +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_vbus_v); -static const struct file_operations ab8500_gpadc_vbus_v_fops = { - .open = ab8500_gpadc_vbus_v_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8500_gpadc_main_charger_c_print(struct seq_file *s, void *p) +static int ab8500_gpadc_main_charger_c_show(struct seq_file *s, void *p) { int main_charger_c_raw; int main_charger_c_convert; @@ -1971,22 +1848,9 @@ static int ab8500_gpadc_main_charger_c_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_main_charger_c_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ab8500_gpadc_main_charger_c_print, - inode->i_private); -} - -static const struct file_operations ab8500_gpadc_main_charger_c_fops = { - .open = ab8500_gpadc_main_charger_c_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_main_charger_c); -static int ab8500_gpadc_usb_charger_c_print(struct seq_file *s, void *p) +static int ab8500_gpadc_usb_charger_c_show(struct seq_file *s, void *p) { int usb_charger_c_raw; int usb_charger_c_convert; @@ -2003,22 +1867,9 @@ static int ab8500_gpadc_usb_charger_c_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_usb_charger_c_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ab8500_gpadc_usb_charger_c_print, - inode->i_private); -} +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_usb_charger_c); -static const struct file_operations ab8500_gpadc_usb_charger_c_fops = { - .open = ab8500_gpadc_usb_charger_c_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8500_gpadc_bk_bat_v_print(struct seq_file *s, void *p) +static int ab8500_gpadc_bk_bat_v_show(struct seq_file *s, void *p) { int bk_bat_v_raw; int bk_bat_v_convert; @@ -2035,21 +1886,9 @@ static int ab8500_gpadc_bk_bat_v_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_bk_bat_v_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_gpadc_bk_bat_v_print, - inode->i_private); -} - -static const struct file_operations ab8500_gpadc_bk_bat_v_fops = { - .open = ab8500_gpadc_bk_bat_v_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_bk_bat_v); -static int ab8500_gpadc_die_temp_print(struct seq_file *s, void *p) +static int ab8500_gpadc_die_temp_show(struct seq_file *s, void *p) { int die_temp_raw; int die_temp_convert; @@ -2066,21 +1905,9 @@ static int ab8500_gpadc_die_temp_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_die_temp_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_gpadc_die_temp_print, - inode->i_private); -} +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_die_temp); -static const struct file_operations ab8500_gpadc_die_temp_fops = { - .open = ab8500_gpadc_die_temp_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8500_gpadc_usb_id_print(struct seq_file *s, void *p) +static int ab8500_gpadc_usb_id_show(struct seq_file *s, void *p) { int usb_id_raw; int usb_id_convert; @@ -2097,20 +1924,9 @@ static int ab8500_gpadc_usb_id_print(struct seq_file *s, void *p) return 0; } -static int ab8500_gpadc_usb_id_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_gpadc_usb_id_print, inode->i_private); -} - -static const struct file_operations ab8500_gpadc_usb_id_fops = { - .open = ab8500_gpadc_usb_id_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_usb_id); -static int ab8540_gpadc_xtal_temp_print(struct seq_file *s, void *p) +static int ab8540_gpadc_xtal_temp_show(struct seq_file *s, void *p) { int xtal_temp_raw; int xtal_temp_convert; @@ -2127,21 +1943,9 @@ static int ab8540_gpadc_xtal_temp_print(struct seq_file *s, void *p) return 0; } -static int ab8540_gpadc_xtal_temp_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8540_gpadc_xtal_temp_print, - inode->i_private); -} +DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_xtal_temp); -static const struct file_operations ab8540_gpadc_xtal_temp_fops = { - .open = ab8540_gpadc_xtal_temp_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8540_gpadc_vbat_true_meas_print(struct seq_file *s, void *p) +static int ab8540_gpadc_vbat_true_meas_show(struct seq_file *s, void *p) { int vbat_true_meas_raw; int vbat_true_meas_convert; @@ -2159,22 +1963,9 @@ static int ab8540_gpadc_vbat_true_meas_print(struct seq_file *s, void *p) return 0; } -static int ab8540_gpadc_vbat_true_meas_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ab8540_gpadc_vbat_true_meas_print, - inode->i_private); -} - -static const struct file_operations ab8540_gpadc_vbat_true_meas_fops = { - .open = ab8540_gpadc_vbat_true_meas_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_vbat_true_meas); -static int ab8540_gpadc_bat_ctrl_and_ibat_print(struct seq_file *s, void *p) +static int ab8540_gpadc_bat_ctrl_and_ibat_show(struct seq_file *s, void *p) { int bat_ctrl_raw; int bat_ctrl_convert; @@ -2200,22 +1991,9 @@ static int ab8540_gpadc_bat_ctrl_and_ibat_print(struct seq_file *s, void *p) return 0; } -static int ab8540_gpadc_bat_ctrl_and_ibat_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ab8540_gpadc_bat_ctrl_and_ibat_print, - inode->i_private); -} +DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_bat_ctrl_and_ibat); -static const struct file_operations ab8540_gpadc_bat_ctrl_and_ibat_fops = { - .open = ab8540_gpadc_bat_ctrl_and_ibat_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8540_gpadc_vbat_meas_and_ibat_print(struct seq_file *s, void *p) +static int ab8540_gpadc_vbat_meas_and_ibat_show(struct seq_file *s, void *p) { int vbat_meas_raw; int vbat_meas_convert; @@ -2240,23 +2018,9 @@ static int ab8540_gpadc_vbat_meas_and_ibat_print(struct seq_file *s, void *p) return 0; } -static int ab8540_gpadc_vbat_meas_and_ibat_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ab8540_gpadc_vbat_meas_and_ibat_print, - inode->i_private); -} +DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_vbat_meas_and_ibat); -static const struct file_operations ab8540_gpadc_vbat_meas_and_ibat_fops = { - .open = ab8540_gpadc_vbat_meas_and_ibat_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8540_gpadc_vbat_true_meas_and_ibat_print(struct seq_file *s, - void *p) +static int ab8540_gpadc_vbat_true_meas_and_ibat_show(struct seq_file *s, void *p) { int vbat_true_meas_raw; int vbat_true_meas_convert; @@ -2282,23 +2046,9 @@ static int ab8540_gpadc_vbat_true_meas_and_ibat_print(struct seq_file *s, return 0; } -static int ab8540_gpadc_vbat_true_meas_and_ibat_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ab8540_gpadc_vbat_true_meas_and_ibat_print, - inode->i_private); -} - -static const struct file_operations -ab8540_gpadc_vbat_true_meas_and_ibat_fops = { - .open = ab8540_gpadc_vbat_true_meas_and_ibat_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_vbat_true_meas_and_ibat); -static int ab8540_gpadc_bat_temp_and_ibat_print(struct seq_file *s, void *p) +static int ab8540_gpadc_bat_temp_and_ibat_show(struct seq_file *s, void *p) { int bat_temp_raw; int bat_temp_convert; @@ -2323,22 +2073,9 @@ static int ab8540_gpadc_bat_temp_and_ibat_print(struct seq_file *s, void *p) return 0; } -static int ab8540_gpadc_bat_temp_and_ibat_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ab8540_gpadc_bat_temp_and_ibat_print, - inode->i_private); -} +DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_bat_temp_and_ibat); -static const struct file_operations ab8540_gpadc_bat_temp_and_ibat_fops = { - .open = ab8540_gpadc_bat_temp_and_ibat_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8540_gpadc_otp_cal_print(struct seq_file *s, void *p) +static int ab8540_gpadc_otp_calib_show(struct seq_file *s, void *p) { struct ab8500_gpadc *gpadc; u16 vmain_l, vmain_h, btemp_l, btemp_h; @@ -2362,18 +2099,7 @@ static int ab8540_gpadc_otp_cal_print(struct seq_file *s, void *p) return 0; } -static int ab8540_gpadc_otp_cal_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8540_gpadc_otp_cal_print, inode->i_private); -} - -static const struct file_operations ab8540_gpadc_otp_calib_fops = { - .open = ab8540_gpadc_otp_cal_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; +DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_otp_calib); static int ab8500_gpadc_avg_sample_print(struct seq_file *s, void *p) { @@ -2906,14 +2632,6 @@ static const struct file_operations ab8500_val_fops = { .owner = THIS_MODULE, }; -static const struct file_operations ab8500_interrupts_fops = { - .open = ab8500_interrupts_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - static const struct file_operations ab8500_subscribe_fops = { .open = ab8500_subscribe_unsubscribe_open, .write = ab8500_subscribe_write, @@ -3000,7 +2718,7 @@ static int ab8500_debug_probe(struct platform_device *plf) goto err; file = debugfs_create_file("all-bank-registers", S_IRUGO, ab8500_dir, - &plf->dev, &ab8500_registers_fops); + &plf->dev, &ab8500_bank_registers_fops); if (!file) goto err; -- cgit v1.2.3 From 0c384fc8620f3cfd886ba969200b79a3563a92df Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 22 Dec 2017 13:35:09 +0100 Subject: mfd: axp20x: Mark axp288 CHRG_BAK_CTRL register volatile The input current limit bits get updated by the charger detection logic, so we should not cache the contents of this register. Signed-off-by: Hans de Goede Signed-off-by: Lee Jones --- drivers/mfd/axp20x.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index d8c92fbbd170..e94c72c2faa2 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -129,6 +129,7 @@ static const struct regmap_range axp288_volatile_ranges[] = { regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP288_POWER_REASON), regmap_reg_range(AXP288_BC_GLOBAL, AXP288_BC_GLOBAL), regmap_reg_range(AXP288_BC_DET_STAT, AXP288_BC_DET_STAT), + regmap_reg_range(AXP20X_CHRG_BAK_CTRL, AXP20X_CHRG_BAK_CTRL), regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L), regmap_reg_range(AXP20X_TIMER_CTRL, AXP20X_TIMER_CTRL), regmap_reg_range(AXP22X_GPIO_STATE, AXP22X_GPIO_STATE), -- cgit v1.2.3 From 0f89ffefa4e122e7e9bc1c2d716c6052b4601b76 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 4 Jan 2018 12:20:18 +0300 Subject: mfd: lpc_ich: Do not touch SPI-NOR write protection bit on Apollo Lake Just to be on the safe side, don't touch the bit. If write access to the flash chip is needed, the BIOS needs to enable it explicitly. Signed-off-by: Mika Westerberg Signed-off-by: Lee Jones --- drivers/mfd/lpc_ich.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index cf1120abbf52..53dc1a43472c 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -1143,11 +1143,6 @@ static int lpc_ich_init_spi(struct pci_dev *dev) res->end = res->start + SPIBASE_APL_SZ - 1; pci_bus_read_config_dword(bus, spi, BCR, &bcr); - if (!(bcr & BCR_WPD)) { - bcr |= BCR_WPD; - pci_bus_write_config_dword(bus, spi, BCR, bcr); - pci_bus_read_config_dword(bus, spi, BCR, &bcr); - } info->writeable = !!(bcr & BCR_WPD); } -- cgit v1.2.3