MMC core:

- Cleanup BKOPS support
  - Introduce MMC_CAP_SYNC_RUNTIME_PM
  - slot-gpio: Delete legacy slot GPIO handling
 
 MMC host:
  - alcor: Add new mmc host driver for Alcor Micro PCI based cardreader
  - bcm2835: Several improvements to better recover from errors
  - jz4740: Rework and fixup pre|post_req support
  - mediatek: Add support for SDIO IRQs
  - meson-gx: Improve clock phase management
  - meson-gx: Stop descriptor on errors
  - mmci: Complete the sbc error path by sending a stop command
  - renesas_sdhi/tmio: Fixup reset/resume operations
  - renesas_sdhi: Add support for r8a774c0 and R7S9210
  - renesas_sdhi: Whitelist R8A77990 SDHI
  - renesas_sdhi: Fixup eMMC HS400 compatibility issues for H3 and M3-W
  - rtsx_usb_sdmmc: Re-work card detection/removal support
  - rtsx_usb_sdmmc: Re-work runtime PM support
  - sdhci: Fix timeout loops for some variant drivers
  - sdhci: Improve support for error handling due to failing commands
  - sdhci-acpi/pci: Disable LED control for Intel BYT-based controllers
  - sdhci_am654: Add new SDHCI variant driver to support TI's AM654 SOCs
  - sdhci-of-esdhc: Add support for eMMC HS400 mode
  - sdhci-omap: Fixup reset support
  - sdhci-omap: Workaround errata regarding SDR104/HS200 tuning failures
  - sdhci-msm: Fixup sporadic write transfers issues for SDR104/HS200
  - sdhci-msm: Fixup dynamical clock gating issues
  - various: Complete converting all hosts into using slot GPIO descriptors
 
 Other:
  - Move GPIO mmc platform data for mips/sh/arm to GPIO descriptors
  - Add new Alcor Micro cardreader PCI driver
  - Support runtime power management for memstick rtsx_usb_ms driver
  - Use USB remote wakeups for card detection for rtsx_usb misc driver
 -----BEGIN PGP SIGNATURE-----
 
 iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAlwk3CcXHHVsZi5oYW5z
 c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCn3ug/+Kra3JxvVcD9I6NZV5CEBWRdw
 nlNN/hexyzpf+zJ6Gb/YS1PSNVQl3a/gND+7mQRHQxJobhkSzaJ3vkZqRMo2HN8p
 D1Gh1j2qBfX2uKj87Svy8nygIulbDbeiBYWrNV070JQaOki9osWTv2JRGl2zufc8
 zonoW1Aou9K6AkrFoFKiaiIZFG9+h5imGSdZTTZ17iOMvs/3DzhjV8UgIvye0Tzm
 Pic/4m6C7YeU7cj+aWyJFRgVuR3AG041d1likIuufxKwwhMSPf16L/xK1q8P8CCQ
 ErScSODqo0hGPmRLNQ7lBN+3A3NLBWOw2Ph5OabfNIPWz1kr6s2ixN9pxkPT7usE
 YMnVQ0YA0fJ13SbtdZ/mjr2A2zMkHN+4PNQC6DRDiDt4WWdNC/1aedOk0CKxRPME
 ppw8MnbSl3lranNoz+opU10spSXZ2m5sGI3t7gD032PJfM3dOcJgLNTpcES5NdTR
 jxqD/RYrtlg4IwZoLZgNt6BPIHBIo+D7JobqcLbELC3MKSSrO9nTKGHF2HxF6Nes
 YvCzKrUAsuxKSVAuNSq/f0ZP0Uk2Nic6iN7Kt2tmkpiMZ2CmynXNtyk/Ff1b1FF/
 urqOSjKYvq2bvyej5fVMGg6cieEsPZr3CiHYNWq3vwpDK87HsraO3op/qj3ud0Y0
 nAPkQbeHfKKhwPGtSQU=
 =mB5P
 -----END PGP SIGNATURE-----

Merge tag 'mmc-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC updates from Ulf Hansson:
 "This time, this pull request contains changes crossing subsystems and
  archs/platforms, which is mainly because of a bigger modernization of
  moving from legacy GPIO to GPIO descriptors for MMC (by Linus
  Walleij).

  Additionally, once again, I am funneling changes to
  drivers/misc/cardreader/* and drivers/memstick/* through my MMC tree,
  mostly due to that we lack a maintainer for these.

  Summary:

  MMC core:
   - Cleanup BKOPS support
   - Introduce MMC_CAP_SYNC_RUNTIME_PM
   - slot-gpio: Delete legacy slot GPIO handling

  MMC host:
   - alcor: Add new mmc host driver for Alcor Micro PCI based cardreader
   - bcm2835: Several improvements to better recover from errors
   - jz4740: Rework and fixup pre|post_req support
   - mediatek: Add support for SDIO IRQs
   - meson-gx: Improve clock phase management
   - meson-gx: Stop descriptor on errors
   - mmci: Complete the sbc error path by sending a stop command
   - renesas_sdhi/tmio: Fixup reset/resume operations
   - renesas_sdhi: Add support for r8a774c0 and R7S9210
   - renesas_sdhi: Whitelist R8A77990 SDHI
   - renesas_sdhi: Fixup eMMC HS400 compatibility issues for H3 and M3-W
   - rtsx_usb_sdmmc: Re-work card detection/removal support
   - rtsx_usb_sdmmc: Re-work runtime PM support
   - sdhci: Fix timeout loops for some variant drivers
   - sdhci: Improve support for error handling due to failing commands
   - sdhci-acpi/pci: Disable LED control for Intel BYT-based controllers
   - sdhci_am654: Add new SDHCI variant driver to support TI's AM654 SOCs
   - sdhci-of-esdhc: Add support for eMMC HS400 mode
   - sdhci-omap: Fixup reset support
   - sdhci-omap: Workaround errata regarding SDR104/HS200 tuning failures
   - sdhci-msm: Fixup sporadic write transfers issues for SDR104/HS200
   - sdhci-msm: Fixup dynamical clock gating issues
   - various: Complete converting all hosts into using slot GPIO descriptors

  Other:
   - Move GPIO mmc platform data for mips/sh/arm to GPIO descriptors
   - Add new Alcor Micro cardreader PCI driver
   - Support runtime power management for memstick rtsx_usb_ms driver
   - Use USB remote wakeups for card detection for rtsx_usb misc driver"

* tag 'mmc-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (99 commits)
  mmc: mediatek: Add MMC_CAP_SDIO_IRQ support
  mmc: renesas_sdhi_internal_dmac: Whitelist r8a774c0
  dt-bindings: mmc: renesas_sdhi: Add r8a774c0 support
  mmc: core: Cleanup BKOPS support
  mmc: core: Drop redundant check in mmc_send_hpi_cmd()
  mmc: sdhci-omap: Workaround errata regarding SDR104/HS200 tuning failures (i929)
  dt-bindings: sdhci-omap: Add note for cpu_thermal
  mmc: sdhci-acpi: Disable LED control for Intel BYT-based controllers
  mmc: sdhci-pci: Disable LED control for Intel BYT-based controllers
  mmc: sdhci: Add quirk to disable LED control
  mmc: mmci: add variant property to set command stop bit
  misc: alcor_pci: fix spelling mistake "invailid" -> "invalid"
  mmc: meson-gx: add signal resampling
  mmc: meson-gx: align default phase on soc vendor tree
  mmc: meson-gx: remove useless lock
  mmc: meson-gx: make sure the descriptor is stopped on errors
  mmc: sdhci_am654: Add Initial Support for AM654 SDHCI driver
  dt-bindings: mmc: sdhci-of-arasan: Add deprecated message for AM65
  dt-bindings: mmc: sdhci-am654: Document bindings for the host controllers on TI's AM654 SOCs
  mmc: sdhci-msm: avoid unused function warning
  ...
This commit is contained in:
Linus Torvalds 2018-12-28 16:52:18 -08:00
commit 00d59fde85
117 changed files with 4019 additions and 1106 deletions

View File

@ -16,6 +16,10 @@ Required Properties:
- "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1": rk3399 eMMC PHY
For this device it is strongly suggested to include arasan,soc-ctl-syscon.
- "ti,am654-sdhci-5.1", "arasan,sdhci-5.1": TI AM654 MMC PHY
Note: This binding has been deprecated and moved to [5].
[5] Documentation/devicetree/bindings/mmc/sdhci-am654.txt
- reg: From mmc bindings: Register location and length.
- clocks: From clock bindings: Handles to clock inputs.
- clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb"

View File

@ -16,6 +16,7 @@ Required properties:
"fsl,imx6sl-usdhc"
"fsl,imx6sx-usdhc"
"fsl,imx7d-usdhc"
"fsl,imx8qxp-usdhc"
Optional properties:
- fsl,wp-controller : Indicate to use controller internal write protection

View File

@ -0,0 +1,36 @@
Device Tree Bindings for the SDHCI Controllers present on TI's AM654 SOCs
The bindings follow the mmc[1], clock[2] and interrupt[3] bindings.
Only deviations are documented here.
[1] Documentation/devicetree/bindings/mmc/mmc.txt
[2] Documentation/devicetree/bindings/clock/clock-bindings.txt
[3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
Required Properties:
- compatible: should be "ti,am654-sdhci-5.1"
- reg: Must be two entries.
- The first should be the sdhci register space
- The second should the subsystem/phy register space
- clocks: Handles to the clock inputs.
- clock-names: Tuple including "clk_xin" and "clk_ahb"
- interrupts: Interrupt specifiers
- ti,otap-del-sel: Output Tap Delay select
- ti,trm-icp: DLL trim select
- ti,driver-strength-ohm: driver strength in ohms.
Valid values are 33, 40, 50, 66 and 100 ohms.
Example:
sdhci0: sdhci@4f80000 {
compatible = "ti,am654-sdhci-5.1";
reg = <0x0 0x4f80000 0x0 0x260>, <0x0 0x4f90000 0x0 0x134>;
power-domains = <&k3_pds 47>;
clocks = <&k3_clks 47 0>, <&k3_clks 47 1>;
clock-names = "clk_ahb", "clk_xin";
interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
sdhci-caps-mask = <0x80000007 0x0>;
mmc-ddr-1_8v;
ti,otap-del-sel = <0x2>;
ti,trm-icp = <0x8>;
};

View File

@ -4,15 +4,28 @@ This file documents differences between the core properties in mmc.txt
and the properties used by the sdhci-msm driver.
Required properties:
- compatible: Should contain:
- compatible: Should contain a SoC-specific string and a IP version string:
version strings:
"qcom,sdhci-msm-v4" for sdcc versions less than 5.0
"qcom,sdhci-msm-v5" for sdcc versions >= 5.0
"qcom,sdhci-msm-v5" for sdcc version 5.0
For SDCC version 5.0.0, MCI registers are removed from SDCC
interface and some registers are moved to HC. New compatible
string is added to support this change - "qcom,sdhci-msm-v5".
full compatible strings with SoC and version:
"qcom,apq8084-sdhci", "qcom,sdhci-msm-v4"
"qcom,msm8974-sdhci", "qcom,sdhci-msm-v4"
"qcom,msm8916-sdhci", "qcom,sdhci-msm-v4"
"qcom,msm8992-sdhci", "qcom,sdhci-msm-v4"
"qcom,msm8996-sdhci", "qcom,sdhci-msm-v4"
"qcom,sdm845-sdhci", "qcom,sdhci-msm-v5"
"qcom,qcs404-sdhci", "qcom,sdhci-msm-v5"
NOTE that some old device tree files may be floating around that only
have the string "qcom,sdhci-msm-v4" without the SoC compatible string
but doing that should be considered a deprecated practice.
- reg: Base address and length of the register in the following order:
- Host controller register map (required)
- SD Core register map (required)
- SD Core register map (required for msm-v4 and below)
- interrupts: Should contain an interrupt-specifiers for the interrupts:
- Host controller interrupt (required)
- pinctrl-names: Should contain only one value - "default".
@ -29,7 +42,7 @@ Required properties:
Example:
sdhc_1: sdhci@f9824900 {
compatible = "qcom,sdhci-msm-v4";
compatible = "qcom,msm8974-sdhci", "qcom,sdhci-msm-v4";
reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
interrupts = <0 123 0>;
bus-width = <8>;
@ -46,7 +59,7 @@ Example:
};
sdhc_2: sdhci@f98a4900 {
compatible = "qcom,sdhci-msm-v4";
compatible = "qcom,msm8974-sdhci", "qcom,sdhci-msm-v4";
reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
interrupts = <0 125 0>;
bus-width = <4>;

View File

@ -2,6 +2,8 @@
Refer to mmc.txt for standard MMC bindings.
For UHS devices which require tuning, the device tree should have a "cpu_thermal" node which maps to the appropriate thermal zone. This is used to get the temperature of the zone during tuning.
Required properties:
- compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers
Should be "ti,k2g-sdhci" for K2G

View File

@ -13,12 +13,14 @@ Required properties:
- compatible: should contain one or more of the following:
"renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC
"renesas,sdhi-r7s72100" - SDHI IP on R7S72100 SoC
"renesas,sdhi-r7s9210" - SDHI IP on R7S9210 SoC
"renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
"renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
"renesas,sdhi-r8a7743" - SDHI IP on R8A7743 SoC
"renesas,sdhi-r8a7744" - SDHI IP on R8A7744 SoC
"renesas,sdhi-r8a7745" - SDHI IP on R8A7745 SoC
"renesas,sdhi-r8a774a1" - SDHI IP on R8A774A1 SoC
"renesas,sdhi-r8a774c0" - SDHI IP on R8A774C0 SoC
"renesas,sdhi-r8a77470" - SDHI IP on R8A77470 SoC
"renesas,sdhi-mmc-r8a77470" - SDHI/MMC IP on R8A77470 SoC
"renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC
@ -56,7 +58,7 @@ Required properties:
"core" and "cd". If the controller only has 1 clock, naming is not
required.
Devices which have more than 1 clock are listed below:
2: R7S72100
2: R7S72100, R7S9210
Optional properties:
- pinctrl-names: should be "default", "state_uhs"

View File

@ -25,6 +25,7 @@
#include <linux/platform_data/video-ep93xx.h>
#include <linux/platform_data/spi-ep93xx.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <mach/hardware.h>
#include <mach/gpio-ep93xx.h>
@ -45,9 +46,15 @@ static struct ep93xxfb_mach_info __initdata simone_fb_info = {
static struct mmc_spi_platform_data simone_mmc_spi_data = {
.detect_delay = 500,
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.flags = MMC_SPI_USE_CD_GPIO,
.cd_gpio = EP93XX_GPIO_LINE_EGPIO0,
.cd_debounce = 1,
};
static struct gpiod_lookup_table simone_mmc_spi_gpio_table = {
.dev_id = "mmc_spi.0", /* "mmc_spi" @ CS0 */
.table = {
/* Card detect */
GPIO_LOOKUP_IDX("A", 0, NULL, 0, GPIO_ACTIVE_LOW),
{ },
},
};
static struct spi_board_info simone_spi_devices[] __initdata = {
@ -105,6 +112,7 @@ static void __init simone_init_machine(void)
ep93xx_register_fb(&simone_fb_info);
ep93xx_register_i2c(simone_i2c_board_info,
ARRAY_SIZE(simone_i2c_board_info));
gpiod_add_lookup_table(&simone_mmc_spi_gpio_table);
ep93xx_register_spi(&simone_spi_info, simone_spi_devices,
ARRAY_SIZE(simone_spi_devices));
simone_register_audio();

View File

@ -18,6 +18,7 @@
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/fb.h>
#include <linux/io.h>
#include <linux/mtd/partitions.h>
@ -202,13 +203,20 @@ static struct mmc_spi_platform_data vision_spi_mmc_data = {
.detect_delay = 100,
.powerup_msecs = 100,
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.flags = MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO,
.cd_gpio = EP93XX_GPIO_LINE_EGPIO15,
.cd_debounce = 1,
.ro_gpio = EP93XX_GPIO_LINE_F(0),
.caps2 = MMC_CAP2_RO_ACTIVE_HIGH,
};
static struct gpiod_lookup_table vision_spi_mmc_gpio_table = {
.dev_id = "mmc_spi.2", /* "mmc_spi @ CS2 */
.table = {
/* Card detect */
GPIO_LOOKUP_IDX("B", 7, NULL, 0, GPIO_ACTIVE_LOW),
/* Write protect */
GPIO_LOOKUP_IDX("F", 0, NULL, 1, GPIO_ACTIVE_HIGH),
{ },
},
};
/*************************************************************************
* SPI Bus
*************************************************************************/
@ -286,6 +294,7 @@ static void __init vision_init_machine(void)
ep93xx_register_i2c(vision_i2c_info,
ARRAY_SIZE(vision_i2c_info));
gpiod_add_lookup_table(&vision_spi_mmc_gpio_table);
ep93xx_register_spi(&vision_spi_master, vision_spi_board_info,
ARRAY_SIZE(vision_spi_board_info));
vision_register_i2s();

View File

@ -20,6 +20,7 @@
#include <linux/mtd/plat-ram.h>
#include <linux/memory.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/smc911x.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@ -214,8 +215,6 @@ static const iomux_v3_cfg_t pcm043_pads[] __initconst = {
#define AC97_GPIO_TXFS IMX_GPIO_NR(2, 31)
#define AC97_GPIO_TXD IMX_GPIO_NR(2, 28)
#define AC97_GPIO_RESET IMX_GPIO_NR(2, 0)
#define SD1_GPIO_WP IMX_GPIO_NR(2, 23)
#define SD1_GPIO_CD IMX_GPIO_NR(2, 24)
static void pcm043_ac97_warm_reset(struct snd_ac97 *ac97)
{
@ -341,12 +340,21 @@ static int __init pcm043_otg_mode(char *options)
__setup("otg_mode=", pcm043_otg_mode);
static struct esdhc_platform_data sd1_pdata = {
.wp_gpio = SD1_GPIO_WP,
.cd_gpio = SD1_GPIO_CD,
.wp_type = ESDHC_WP_GPIO,
.cd_type = ESDHC_CD_GPIO,
};
static struct gpiod_lookup_table sd1_gpio_table = {
.dev_id = "sdhci-esdhc-imx35.0",
.table = {
/* Card detect: bank 2 offset 24 */
GPIO_LOOKUP("imx35-gpio.2", 24, "cd", GPIO_ACTIVE_LOW),
/* Write protect: bank 2 offset 23 */
GPIO_LOOKUP("imx35-gpio.2", 23, "wp", GPIO_ACTIVE_LOW),
{ },
},
};
/*
* Board specific initialization.
*/
@ -391,6 +399,7 @@ static void __init pcm043_late_init(void)
{
imx35_add_imx_ssi(0, &pcm043_ssi_pdata);
gpiod_add_lookup_table(&sd1_gpio_table);
imx35_add_sdhci_esdhc_imx(0, &sd1_pdata);
}

View File

@ -290,9 +290,6 @@ static unsigned long balloon3_mmc_pin_config[] __initdata = {
static struct pxamci_platform_data balloon3_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.gpio_card_detect = -1,
.gpio_card_ro = -1,
.gpio_power = -1,
.detect_delay_ms = 200,
};

View File

@ -12,6 +12,7 @@
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/delay.h>
#include <linux/platform_data/rtc-v3020.h>
@ -288,14 +289,23 @@ static inline void cmx270_init_ohci(void) {}
#if defined(CONFIG_MMC) || defined(CONFIG_MMC_MODULE)
static struct pxamci_platform_data cmx270_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.gpio_card_detect = GPIO83_MMC_IRQ,
.gpio_card_ro = -1,
.gpio_power = GPIO105_MMC_POWER,
.gpio_power_invert = 1,
};
static struct gpiod_lookup_table cmx270_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
/* Card detect on GPIO 83 */
GPIO_LOOKUP("gpio-pxa", GPIO83_MMC_IRQ, "cd", GPIO_ACTIVE_LOW),
/* Power on GPIO 105 */
GPIO_LOOKUP("gpio-pxa", GPIO105_MMC_POWER,
"power", GPIO_ACTIVE_LOW),
{ },
},
};
static void __init cmx270_init_mmc(void)
{
gpiod_add_lookup_table(&cmx270_mci_gpio_table);
pxa_set_mci_info(&cmx270_mci_platform_data);
}
#else

View File

@ -459,9 +459,17 @@ static inline void cm_x300_init_nand(void) {}
static struct pxamci_platform_data cm_x300_mci_platform_data = {
.detect_delay_ms = 200,
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.gpio_card_detect = GPIO82_MMC_IRQ,
.gpio_card_ro = GPIO85_MMC_WP,
.gpio_power = -1,
};
static struct gpiod_lookup_table cm_x300_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
/* Card detect on GPIO 82 */
GPIO_LOOKUP("gpio-pxa", GPIO82_MMC_IRQ, "cd", GPIO_ACTIVE_LOW),
/* Write protect on GPIO 85 */
GPIO_LOOKUP("gpio-pxa", GPIO85_MMC_WP, "wp", GPIO_ACTIVE_LOW),
{ },
},
};
/* The second MMC slot of CM-X300 is hardwired to Libertas card and has
@ -482,13 +490,11 @@ static struct pxamci_platform_data cm_x300_mci2_platform_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.init = cm_x300_mci2_init,
.exit = cm_x300_mci2_exit,
.gpio_card_detect = -1,
.gpio_card_ro = -1,
.gpio_power = -1,
};
static void __init cm_x300_init_mmc(void)
{
gpiod_add_lookup_table(&cm_x300_mci_gpio_table);
pxa_set_mci_info(&cm_x300_mci_platform_data);
pxa3xx_set_mci2_info(&cm_x300_mci2_platform_data);
}

View File

@ -14,7 +14,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include <asm/mach/arch.h>
@ -37,22 +37,44 @@
#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
static struct pxamci_platform_data colibri_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.gpio_power = -1,
.gpio_card_ro = -1,
.detect_delay_ms = 200,
};
static struct gpiod_lookup_table colibri_pxa270_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO0_COLIBRI_PXA270_SD_DETECT,
"cd", GPIO_ACTIVE_LOW),
{ },
},
};
static struct gpiod_lookup_table colibri_pxa300_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO13_COLIBRI_PXA300_SD_DETECT,
"cd", GPIO_ACTIVE_LOW),
{ },
},
};
static struct gpiod_lookup_table colibri_pxa320_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO28_COLIBRI_PXA320_SD_DETECT,
"cd", GPIO_ACTIVE_LOW),
{ },
},
};
static void __init colibri_mmc_init(void)
{
if (machine_is_colibri()) /* PXA270 Colibri */
colibri_mci_platform_data.gpio_card_detect =
GPIO0_COLIBRI_PXA270_SD_DETECT;
gpiod_add_lookup_table(&colibri_pxa270_mci_gpio_table);
if (machine_is_colibri300()) /* PXA300 Colibri */
colibri_mci_platform_data.gpio_card_detect =
GPIO13_COLIBRI_PXA300_SD_DETECT;
gpiod_add_lookup_table(&colibri_pxa300_mci_gpio_table);
else /* PXA320 Colibri */
colibri_mci_platform_data.gpio_card_detect =
GPIO28_COLIBRI_PXA320_SD_DETECT;
gpiod_add_lookup_table(&colibri_pxa320_mci_gpio_table);
pxa_set_mci_info(&colibri_mci_platform_data);
}

View File

@ -14,7 +14,7 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/leds.h>
@ -51,14 +51,25 @@
#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
static struct pxamci_platform_data income_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.gpio_power = -1,
.gpio_card_detect = GPIO0_INCOME_SD_DETECT,
.gpio_card_ro = GPIO0_INCOME_SD_RO,
.detect_delay_ms = 200,
};
static struct gpiod_lookup_table income_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
/* Card detect on GPIO 0 */
GPIO_LOOKUP("gpio-pxa", GPIO0_INCOME_SD_DETECT,
"cd", GPIO_ACTIVE_LOW),
/* Write protect on GPIO 1 */
GPIO_LOOKUP("gpio-pxa", GPIO0_INCOME_SD_RO,
"wp", GPIO_ACTIVE_LOW),
{ },
},
};
static void __init income_mmc_init(void)
{
gpiod_add_lookup_table(&income_mci_gpio_table);
pxa_set_mci_info(&income_mci_platform_data);
}
#else

View File

@ -24,6 +24,7 @@
#include <linux/mtd/physmap.h>
#include <linux/pm.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/backlight.h>
#include <linux/i2c.h>
#include <linux/platform_data/i2c-pxa.h>
@ -493,11 +494,23 @@ static struct platform_device corgi_audio_device = {
static struct pxamci_platform_data corgi_mci_platform_data = {
.detect_delay_ms = 250,
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.gpio_card_detect = CORGI_GPIO_nSD_DETECT,
.gpio_card_ro = CORGI_GPIO_nSD_WP,
.gpio_power = CORGI_GPIO_SD_PWR,
};
static struct gpiod_lookup_table corgi_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
/* Card detect on GPIO 9 */
GPIO_LOOKUP("gpio-pxa", CORGI_GPIO_nSD_DETECT,
"cd", GPIO_ACTIVE_LOW),
/* Write protect on GPIO 7 */
GPIO_LOOKUP("gpio-pxa", CORGI_GPIO_nSD_WP,
"wp", GPIO_ACTIVE_LOW),
/* Power on GPIO 33 */
GPIO_LOOKUP("gpio-pxa", CORGI_GPIO_SD_PWR,
"power", GPIO_ACTIVE_HIGH),
{ },
},
};
/*
* Irda
@ -731,6 +744,7 @@ static void __init corgi_init(void)
corgi_init_spi();
pxa_set_udc_info(&udc_info);
gpiod_add_lookup_table(&corgi_mci_gpio_table);
pxa_set_mci_info(&corgi_mci_platform_data);
pxa_set_ficp_info(&corgi_ficp_platform_data);
pxa_set_i2c_info(NULL);

View File

@ -11,7 +11,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/platform_device.h>
#include <linux/mtd/physmap.h>
#include <linux/mtd/partitions.h>
@ -129,9 +129,19 @@ static struct pxamci_platform_data csb726_mci = {
.detect_delay_ms = 500,
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
/* FIXME setpower */
.gpio_card_detect = CSB726_GPIO_MMC_DETECT,
.gpio_card_ro = CSB726_GPIO_MMC_RO,
.gpio_power = -1,
};
static struct gpiod_lookup_table csb726_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
/* Card detect on GPIO 100 */
GPIO_LOOKUP("gpio-pxa", CSB726_GPIO_MMC_DETECT,
"cd", GPIO_ACTIVE_LOW),
/* Write protect on GPIO 101 */
GPIO_LOOKUP("gpio-pxa", CSB726_GPIO_MMC_RO,
"wp", GPIO_ACTIVE_LOW),
{ },
},
};
static struct pxaohci_platform_data csb726_ohci_platform_data = {
@ -264,6 +274,7 @@ static void __init csb726_init(void)
pxa_set_stuart_info(NULL);
pxa_set_i2c_info(NULL);
pxa27x_set_i2c_power_info(NULL);
gpiod_add_lookup_table(&csb726_mci_gpio_table);
pxa_set_mci_info(&csb726_mci);
pxa_set_ohci_info(&csb726_ohci_platform_data);
pxa_set_ac97_info(NULL);

View File

@ -20,6 +20,7 @@
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/mfd/da903x.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
@ -546,6 +547,15 @@ static inline void em_x270_init_ohci(void) {}
#if defined(CONFIG_MMC) || defined(CONFIG_MMC_MODULE)
static struct regulator *em_x270_sdio_ldo;
static struct gpiod_lookup_table em_x270_mci_wp_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
/* Write protect on GPIO 95 */
GPIO_LOOKUP("gpio-pxa", GPIO95_MMC_WP, "wp", GPIO_ACTIVE_LOW),
{ },
},
};
static int em_x270_mci_init(struct device *dev,
irq_handler_t em_x270_detect_int,
void *data)
@ -567,15 +577,7 @@ static int em_x270_mci_init(struct device *dev,
goto err_irq;
}
if (machine_is_em_x270()) {
err = gpio_request(GPIO95_MMC_WP, "MMC WP");
if (err) {
dev_err(dev, "can't request MMC write protect: %d\n",
err);
goto err_gpio_wp;
}
gpio_direction_input(GPIO95_MMC_WP);
} else {
if (!machine_is_em_x270()) {
err = gpio_request(GPIO38_SD_PWEN, "sdio power");
if (err) {
dev_err(dev, "can't request MMC power control : %d\n",
@ -615,17 +617,10 @@ static void em_x270_mci_exit(struct device *dev, void *data)
free_irq(gpio_to_irq(mmc_cd), data);
regulator_put(em_x270_sdio_ldo);
if (machine_is_em_x270())
gpio_free(GPIO95_MMC_WP);
else
if (!machine_is_em_x270())
gpio_free(GPIO38_SD_PWEN);
}
static int em_x270_mci_get_ro(struct device *dev)
{
return gpio_get_value(GPIO95_MMC_WP);
}
static struct pxamci_platform_data em_x270_mci_platform_data = {
.detect_delay_ms = 250,
.ocr_mask = MMC_VDD_20_21|MMC_VDD_21_22|MMC_VDD_22_23|
@ -635,15 +630,12 @@ static struct pxamci_platform_data em_x270_mci_platform_data = {
.init = em_x270_mci_init,
.setpower = em_x270_mci_setpower,
.exit = em_x270_mci_exit,
.gpio_card_detect = -1,
.gpio_card_ro = -1,
.gpio_power = -1,
};
static void __init em_x270_init_mmc(void)
{
if (machine_is_em_x270())
em_x270_mci_platform_data.get_ro = em_x270_mci_get_ro;
gpiod_add_lookup_table(&em_x270_mci_wp_gpio_table);
pxa_set_mci_info(&em_x270_mci_platform_data);
}

View File

@ -90,9 +90,6 @@ static struct platform_device *devices[] __initdata = {
#ifdef CONFIG_MMC_PXA
static struct pxamci_platform_data gumstix_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.gpio_card_detect = -1,
.gpio_card_ro = -1,
.gpio_power = -1,
};
static void __init gumstix_mmc_init(void)

View File

@ -160,9 +160,6 @@ static struct pxafb_mach_info sharp_lm8v31 = {
static struct pxamci_platform_data idp_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.gpio_card_detect = -1,
.gpio_card_ro = -1,
.gpio_power = -1,
};
static void __init idp_init(void)

View File

@ -20,7 +20,7 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/smc91x.h>
@ -51,8 +51,6 @@
#include "generic.h"
#define GPIO_MMC1_CARD_DETECT mfp_to_gpio(MFP_PIN_GPIO15)
/* Littleton MFP configurations */
static mfp_cfg_t littleton_mfp_cfg[] __initdata = {
/* LCD */
@ -278,13 +276,21 @@ static inline void littleton_init_keypad(void) {}
static struct pxamci_platform_data littleton_mci_platform_data = {
.detect_delay_ms = 200,
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.gpio_card_detect = GPIO_MMC1_CARD_DETECT,
.gpio_card_ro = -1,
.gpio_power = -1,
};
static struct gpiod_lookup_table littleton_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
/* Card detect on MFP (gpio-pxa) GPIO 15 */
GPIO_LOOKUP("gpio-pxa", MFP_PIN_GPIO15,
"cd", GPIO_ACTIVE_LOW),
{ },
},
};
static void __init littleton_init_mmc(void)
{
gpiod_add_lookup_table(&littleton_mci_gpio_table);
pxa_set_mci_info(&littleton_mci_platform_data);
}
#else

View File

@ -440,9 +440,6 @@ static struct pxamci_platform_data lubbock_mci_platform_data = {
.init = lubbock_mci_init,
.get_ro = lubbock_mci_get_ro,
.exit = lubbock_mci_exit,
.gpio_card_detect = -1,
.gpio_card_ro = -1,
.gpio_power = -1,
};
static void lubbock_irda_transceiver_mode(struct device *dev, int mode)

View File

@ -775,12 +775,31 @@ static struct pxamci_platform_data magician_mci_info = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.init = magician_mci_init,
.exit = magician_mci_exit,
.gpio_card_detect = -1,
.gpio_card_ro = EGPIO_MAGICIAN_nSD_READONLY,
.gpio_card_ro_invert = 1,
.gpio_power = EGPIO_MAGICIAN_SD_POWER,
};
/*
* Write protect on EGPIO register 5 index 4, this is on the second HTC
* EGPIO chip which starts at register 4, so we need offset 8+4=12 on that
* particular chip.
*/
#define EGPIO_MAGICIAN_nSD_READONLY_OFFSET 12
/*
* Power on EGPIO register 2 index 0, so this is on the first HTC EGPIO chip
* starting at register 0 so we need offset 2*8+0 = 16 on that chip.
*/
#define EGPIO_MAGICIAN_nSD_POWER_OFFSET 16
static struct gpiod_lookup_table magician_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("htc-egpio-1", EGPIO_MAGICIAN_nSD_READONLY_OFFSET,
"wp", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("htc-egpio-0", EGPIO_MAGICIAN_nSD_POWER_OFFSET,
"power", GPIO_ACTIVE_HIGH),
{ },
},
};
/*
* USB OHCI
@ -979,6 +998,7 @@ static void __init magician_init(void)
i2c_register_board_info(1,
ARRAY_AND_SIZE(magician_pwr_i2c_board_info));
gpiod_add_lookup_table(&magician_mci_gpio_table);
pxa_set_mci_info(&magician_mci_info);
pxa_set_ohci_info(&magician_ohci_info);
pxa_set_udc_info(&magician_udc_info);

View File

@ -361,9 +361,6 @@ static struct pxamci_platform_data mainstone_mci_platform_data = {
.init = mainstone_mci_init,
.setpower = mainstone_mci_setpower,
.exit = mainstone_mci_exit,
.gpio_card_detect = -1,
.gpio_card_ro = -1,
.gpio_power = -1,
};
static void mainstone_irda_transceiver_mode(struct device *dev, int mode)

View File

@ -31,6 +31,7 @@
#include <linux/rtc.h>
#include <linux/leds.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/pda_power.h>
@ -397,9 +398,22 @@ struct gpio_vbus_mach_info gpio_vbus_data = {
static struct pxamci_platform_data mioa701_mci_info = {
.detect_delay_ms = 250,
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.gpio_card_detect = GPIO15_SDIO_INSERT,
.gpio_card_ro = GPIO78_SDIO_RO,
.gpio_power = GPIO91_SDIO_EN,
};
static struct gpiod_lookup_table mioa701_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
/* Card detect on GPIO 15 */
GPIO_LOOKUP("gpio-pxa", GPIO15_SDIO_INSERT,
"cd", GPIO_ACTIVE_LOW),
/* Write protect on GPIO 78 */
GPIO_LOOKUP("gpio-pxa", GPIO78_SDIO_RO,
"wp", GPIO_ACTIVE_LOW),
/* Power on GPIO 91 */
GPIO_LOOKUP("gpio-pxa", GPIO91_SDIO_EN,
"power", GPIO_ACTIVE_HIGH),
{ },
},
};
/* FlashRAM */
@ -743,6 +757,7 @@ static void __init mioa701_machine_init(void)
pr_err("MioA701: Failed to request GPIOs: %d", rc);
bootstrap_init();
pxa_set_fb_info(NULL, &mioa701_pxafb_info);
gpiod_add_lookup_table(&mioa701_mci_gpio_table);
pxa_set_mci_info(&mioa701_mci_info);
pxa_set_keypad_info(&mioa701_keypad_info);
pxa_set_udc_info(&mioa701_udc_info);

View File

@ -21,7 +21,7 @@
#include <linux/serial_8250.h>
#include <linux/dm9000.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/platform_data/i2c-pxa.h>
#include <linux/platform_data/mtd-nand-pxa3xx.h>
@ -326,13 +326,24 @@ static mfp_cfg_t mfp_cfg[] __initdata = {
static struct pxamci_platform_data mxm_8x10_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.detect_delay_ms = 10,
.gpio_card_detect = MXM_8X10_SD_nCD,
.gpio_card_ro = MXM_8X10_SD_WP,
.gpio_power = -1
};
static struct gpiod_lookup_table mxm_8x10_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
/* Card detect on GPIO 72 */
GPIO_LOOKUP("gpio-pxa", MXM_8X10_SD_nCD,
"cd", GPIO_ACTIVE_LOW),
/* Write protect on GPIO 84 */
GPIO_LOOKUP("gpio-pxa", MXM_8X10_SD_WP,
"wp", GPIO_ACTIVE_LOW),
{ },
},
};
void __init mxm_8x10_mmc_init(void)
{
gpiod_add_lookup_table(&mxm_8x10_mci_gpio_table);
pxa_set_mci_info(&mxm_8x10_mci_platform_data);
}
#endif

View File

@ -49,14 +49,10 @@ static struct pxamci_platform_data palm27x_mci_platform_data = {
.detect_delay_ms = 200,
};
void __init palm27x_mmc_init(int detect, int ro, int power,
int power_inverted)
void __init palm27x_mmc_init(struct gpiod_lookup_table *gtable)
{
palm27x_mci_platform_data.gpio_card_detect = detect;
palm27x_mci_platform_data.gpio_card_ro = ro;
palm27x_mci_platform_data.gpio_power = power;
palm27x_mci_platform_data.gpio_power_invert = power_inverted;
if (gtable)
gpiod_add_lookup_table(gtable);
pxa_set_mci_info(&palm27x_mci_platform_data);
}
#endif

View File

@ -15,11 +15,9 @@
#include <linux/gpio/machine.h>
#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
extern void __init palm27x_mmc_init(int detect, int ro, int power,
int power_inverted);
extern void __init palm27x_mmc_init(struct gpiod_lookup_table *gtable);
#else
static inline void palm27x_mmc_init(int detect, int ro, int power,
int power_inverted)
static inline void palm27x_mmc_init(struct gpiod_lookup_table *gtable)
{}
#endif

View File

@ -332,6 +332,19 @@ static void __init palmld_map_io(void)
iotable_init(palmld_io_desc, ARRAY_SIZE(palmld_io_desc));
}
static struct gpiod_lookup_table palmld_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMLD_SD_DETECT_N,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMLD_SD_READONLY,
"wp", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMLD_SD_POWER,
"power", GPIO_ACTIVE_HIGH),
{ },
},
};
static void __init palmld_init(void)
{
pxa2xx_mfp_config(ARRAY_AND_SIZE(palmld_pin_config));
@ -339,8 +352,7 @@ static void __init palmld_init(void)
pxa_set_btuart_info(NULL);
pxa_set_stuart_info(NULL);
palm27x_mmc_init(GPIO_NR_PALMLD_SD_DETECT_N, GPIO_NR_PALMLD_SD_READONLY,
GPIO_NR_PALMLD_SD_POWER, 0);
palm27x_mmc_init(&palmld_mci_gpio_table);
palm27x_pm_init(PALMLD_STR_BASE);
palm27x_lcd_init(-1, &palm_320x480_lcd_mode);
palm27x_irda_init(GPIO_NR_PALMLD_IR_DISABLE);

View File

@ -182,6 +182,19 @@ static void __init palmt5_reserve(void)
memblock_reserve(0xa0200000, 0x1000);
}
static struct gpiod_lookup_table palmt5_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMT5_SD_DETECT_N,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMT5_SD_READONLY,
"wp", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMT5_SD_POWER,
"power", GPIO_ACTIVE_HIGH),
{ },
},
};
static void __init palmt5_init(void)
{
pxa2xx_mfp_config(ARRAY_AND_SIZE(palmt5_pin_config));
@ -189,8 +202,7 @@ static void __init palmt5_init(void)
pxa_set_btuart_info(NULL);
pxa_set_stuart_info(NULL);
palm27x_mmc_init(GPIO_NR_PALMT5_SD_DETECT_N, GPIO_NR_PALMT5_SD_READONLY,
GPIO_NR_PALMT5_SD_POWER, 0);
palm27x_mmc_init(&palmt5_mci_gpio_table);
palm27x_pm_init(PALMT5_STR_BASE);
palm27x_lcd_init(-1, &palm_320x480_lcd_mode);
palm27x_udc_init(GPIO_NR_PALMT5_USB_DETECT_N,

View File

@ -20,7 +20,7 @@
#include <linux/input.h>
#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/input/matrix_keypad.h>
#include <linux/ucb1400.h>
#include <linux/power_supply.h>
@ -120,14 +120,25 @@ static unsigned long palmtc_pin_config[] __initdata = {
#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
static struct pxamci_platform_data palmtc_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.gpio_power = GPIO_NR_PALMTC_SD_POWER,
.gpio_card_ro = GPIO_NR_PALMTC_SD_READONLY,
.gpio_card_detect = GPIO_NR_PALMTC_SD_DETECT_N,
.detect_delay_ms = 200,
};
static struct gpiod_lookup_table palmtc_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTC_SD_DETECT_N,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTC_SD_READONLY,
"wp", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTC_SD_POWER,
"power", GPIO_ACTIVE_HIGH),
{ },
},
};
static void __init palmtc_mmc_init(void)
{
gpiod_add_lookup_table(&palmtc_mci_gpio_table);
pxa_set_mci_info(&palmtc_mci_platform_data);
}
#else

View File

@ -19,6 +19,7 @@
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/gpio_keys.h>
#include <linux/gpio/machine.h>
#include <linux/input.h>
#include <linux/pda_power.h>
#include <linux/pwm.h>
@ -101,9 +102,19 @@ static unsigned long palmte2_pin_config[] __initdata = {
******************************************************************************/
static struct pxamci_platform_data palmte2_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.gpio_card_detect = GPIO_NR_PALMTE2_SD_DETECT_N,
.gpio_card_ro = GPIO_NR_PALMTE2_SD_READONLY,
.gpio_power = GPIO_NR_PALMTE2_SD_POWER,
};
static struct gpiod_lookup_table palmte2_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTE2_SD_DETECT_N,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTE2_SD_READONLY,
"wp", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTE2_SD_POWER,
"power", GPIO_ACTIVE_HIGH),
{ },
},
};
#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
@ -354,6 +365,7 @@ static void __init palmte2_init(void)
pxa_set_stuart_info(NULL);
pxa_set_fb_info(NULL, &palmte2_lcd_screen);
gpiod_add_lookup_table(&palmte2_mci_gpio_table);
pxa_set_mci_info(&palmte2_mci_platform_data);
palmte2_udc_init();
pxa_set_ac97_info(&palmte2_ac97_pdata);

View File

@ -480,23 +480,46 @@ void __init treo680_gpio_init(void)
gpio_free(GPIO_NR_TREO680_LCD_EN_N);
}
static struct gpiod_lookup_table treo680_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO_NR_TREO_SD_DETECT_N,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_TREO680_SD_READONLY,
"wp", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_TREO680_SD_POWER,
"power", GPIO_ACTIVE_HIGH),
{ },
},
};
static void __init treo680_init(void)
{
pxa2xx_mfp_config(ARRAY_AND_SIZE(treo680_pin_config));
palmphone_common_init();
treo680_gpio_init();
palm27x_mmc_init(GPIO_NR_TREO_SD_DETECT_N, GPIO_NR_TREO680_SD_READONLY,
GPIO_NR_TREO680_SD_POWER, 0);
palm27x_mmc_init(&treo680_mci_gpio_table);
}
#endif
#ifdef CONFIG_MACH_CENTRO
static struct gpiod_lookup_table centro685_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO_NR_TREO_SD_DETECT_N,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_CENTRO_SD_POWER,
"power", GPIO_ACTIVE_LOW),
{ },
},
};
static void __init centro_init(void)
{
pxa2xx_mfp_config(ARRAY_AND_SIZE(centro685_pin_config));
palmphone_common_init();
palm27x_mmc_init(GPIO_NR_TREO_SD_DETECT_N, -1,
GPIO_NR_CENTRO_SD_POWER, 1);
palm27x_mmc_init(&centro685_mci_gpio_table);
}
#endif

View File

@ -337,6 +337,19 @@ static void __init palmtx_map_io(void)
iotable_init(palmtx_io_desc, ARRAY_SIZE(palmtx_io_desc));
}
static struct gpiod_lookup_table palmtx_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTX_SD_DETECT_N,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTX_SD_READONLY,
"wp", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTX_SD_POWER,
"power", GPIO_ACTIVE_HIGH),
{ },
},
};
static void __init palmtx_init(void)
{
pxa2xx_mfp_config(ARRAY_AND_SIZE(palmtx_pin_config));
@ -344,8 +357,7 @@ static void __init palmtx_init(void)
pxa_set_btuart_info(NULL);
pxa_set_stuart_info(NULL);
palm27x_mmc_init(GPIO_NR_PALMTX_SD_DETECT_N, GPIO_NR_PALMTX_SD_READONLY,
GPIO_NR_PALMTX_SD_POWER, 0);
palm27x_mmc_init(&palmtx_mci_gpio_table);
palm27x_pm_init(PALMTX_STR_BASE);
palm27x_lcd_init(-1, &palm_320x480_lcd_mode);
palm27x_udc_init(GPIO_NR_PALMTX_USB_DETECT_N,

View File

@ -386,6 +386,19 @@ static void __init palmz72_camera_init(void)
static inline void palmz72_camera_init(void) {}
#endif
static struct gpiod_lookup_table palmz72_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMZ72_SD_DETECT_N,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMZ72_SD_RO,
"wp", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMZ72_SD_POWER_N,
"power", GPIO_ACTIVE_LOW),
{ },
},
};
/******************************************************************************
* Machine init
******************************************************************************/
@ -396,8 +409,7 @@ static void __init palmz72_init(void)
pxa_set_btuart_info(NULL);
pxa_set_stuart_info(NULL);
palm27x_mmc_init(GPIO_NR_PALMZ72_SD_DETECT_N, GPIO_NR_PALMZ72_SD_RO,
GPIO_NR_PALMZ72_SD_POWER_N, 1);
palm27x_mmc_init(&palmz72_mci_gpio_table);
palm27x_lcd_init(-1, &palm_320x320_lcd_mode);
palm27x_udc_init(GPIO_NR_PALMZ72_USB_DETECT_N,
GPIO_NR_PALMZ72_USB_PULLUP, 0);

View File

@ -370,9 +370,6 @@ static struct pxamci_platform_data pcm990_mci_platform_data = {
.init = pcm990_mci_init,
.setpower = pcm990_mci_setpower,
.exit = pcm990_mci_exit,
.gpio_card_detect = -1,
.gpio_card_ro = -1,
.gpio_power = -1,
};
static struct pxaohci_platform_data pcm990_ohci_platform_data = {

View File

@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/mtd/physmap.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/i2c.h>
#include <linux/platform_data/i2c-pxa.h>
#include <linux/regulator/machine.h>
@ -288,11 +289,18 @@ static struct pxamci_platform_data poodle_mci_platform_data = {
.init = poodle_mci_init,
.setpower = poodle_mci_setpower,
.exit = poodle_mci_exit,
.gpio_card_detect = POODLE_GPIO_nSD_DETECT,
.gpio_card_ro = POODLE_GPIO_nSD_WP,
.gpio_power = -1,
};
static struct gpiod_lookup_table poodle_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", POODLE_GPIO_nSD_DETECT,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", POODLE_GPIO_nSD_WP,
"wp", GPIO_ACTIVE_LOW),
{ },
},
};
/*
* Irda
@ -439,6 +447,7 @@ static void __init poodle_init(void)
pxa_set_fb_info(&poodle_locomo_device.dev, &poodle_fb_info);
pxa_set_udc_info(&udc_info);
gpiod_add_lookup_table(&poodle_mci_gpio_table);
pxa_set_mci_info(&poodle_mci_platform_data);
pxa_set_ficp_info(&poodle_ficp_platform_data);
pxa_set_i2c_info(NULL);

View File

@ -749,9 +749,6 @@ static struct pxamci_platform_data raumfeld_mci_platform_data = {
.init = raumfeld_mci_init,
.exit = raumfeld_mci_exit,
.detect_delay_ms = 200,
.gpio_card_detect = -1,
.gpio_card_ro = -1,
.gpio_power = -1,
};
/*

View File

@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/gpio_keys.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/leds.h>
#include <linux/i2c.h>
#include <linux/platform_data/i2c-pxa.h>
@ -615,13 +616,22 @@ static struct pxamci_platform_data spitz_mci_platform_data = {
.detect_delay_ms = 250,
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.setpower = spitz_mci_setpower,
.gpio_card_detect = SPITZ_GPIO_nSD_DETECT,
.gpio_card_ro = SPITZ_GPIO_nSD_WP,
.gpio_power = -1,
};
static struct gpiod_lookup_table spitz_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", SPITZ_GPIO_nSD_DETECT,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", SPITZ_GPIO_nSD_WP,
"wp", GPIO_ACTIVE_LOW),
{ },
},
};
static void __init spitz_mmc_init(void)
{
gpiod_add_lookup_table(&spitz_mci_gpio_table);
pxa_set_mci_info(&spitz_mci_platform_data);
}
#else

View File

@ -436,9 +436,6 @@ static int imote2_mci_get_ro(struct device *dev)
static struct pxamci_platform_data imote2_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, /* default anyway */
.get_ro = imote2_mci_get_ro,
.gpio_card_detect = -1,
.gpio_card_ro = -1,
.gpio_power = -1,
};
static struct gpio_led imote2_led_pins[] = {

View File

@ -31,6 +31,7 @@
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/power/gpio-charger.h>
#include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
@ -291,9 +292,19 @@ static struct pxamci_platform_data tosa_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.init = tosa_mci_init,
.exit = tosa_mci_exit,
.gpio_card_detect = TOSA_GPIO_nSD_DETECT,
.gpio_card_ro = TOSA_GPIO_SD_WP,
.gpio_power = TOSA_GPIO_PWR_ON,
};
static struct gpiod_lookup_table tosa_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_nSD_DETECT,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_SD_WP,
"wp", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_PWR_ON,
"power", GPIO_ACTIVE_HIGH),
{ },
},
};
/*
@ -908,6 +919,7 @@ static void __init tosa_init(void)
/* enable batt_fault */
PMCR = 0x01;
gpiod_add_lookup_table(&tosa_mci_gpio_table);
pxa_set_mci_info(&tosa_mci_platform_data);
pxa_set_ficp_info(&tosa_ficp_platform_data);
pxa_set_i2c_info(NULL);

View File

@ -355,9 +355,6 @@ static struct pxamci_platform_data trizeps4_mci_platform_data = {
.exit = trizeps4_mci_exit,
.get_ro = NULL, /* write-protection not supported */
.setpower = NULL, /* power-switching not supported */
.gpio_card_detect = -1,
.gpio_card_ro = -1,
.gpio_power = -1,
};
/****************************************************************************

View File

@ -17,6 +17,7 @@
#include <linux/input.h>
#include <linux/leds.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/usb/gpio_vbus.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@ -240,14 +241,23 @@ static void __init vpac270_onenand_init(void) {}
#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
static struct pxamci_platform_data vpac270_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.gpio_power = -1,
.gpio_card_detect = GPIO53_VPAC270_SD_DETECT_N,
.gpio_card_ro = GPIO52_VPAC270_SD_READONLY,
.detect_delay_ms = 200,
};
static struct gpiod_lookup_table vpac270_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO53_VPAC270_SD_DETECT_N,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", GPIO52_VPAC270_SD_READONLY,
"wp", GPIO_ACTIVE_LOW),
{ },
},
};
static void __init vpac270_mmc_init(void)
{
gpiod_add_lookup_table(&vpac270_mci_gpio_table);
pxa_set_mci_info(&vpac270_mci_platform_data);
}
#else

View File

@ -27,6 +27,7 @@
#include <linux/power_supply.h>
#include <linux/mtd/physmap.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/gpio_keys.h>
#include <linux/delay.h>
#include <linux/regulator/machine.h>
@ -290,14 +291,21 @@ static inline void z2_lcd_init(void) {}
#if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
static struct pxamci_platform_data z2_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.gpio_card_detect = GPIO96_ZIPITZ2_SD_DETECT,
.gpio_power = -1,
.gpio_card_ro = -1,
.detect_delay_ms = 200,
};
static struct gpiod_lookup_table z2_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", GPIO96_ZIPITZ2_SD_DETECT,
"cd", GPIO_ACTIVE_LOW),
{ },
},
};
static void __init z2_mmc_init(void)
{
gpiod_add_lookup_table(&z2_mci_gpio_table);
pxa_set_mci_info(&z2_mci_platform_data);
}
#else

View File

@ -663,10 +663,18 @@ static struct pxafb_mach_info zeus_fb_info = {
static struct pxamci_platform_data zeus_mci_platform_data = {
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.detect_delay_ms = 250,
.gpio_card_detect = ZEUS_MMC_CD_GPIO,
.gpio_card_ro = ZEUS_MMC_WP_GPIO,
.gpio_card_ro_invert = 1,
.gpio_power = -1
};
static struct gpiod_lookup_table zeus_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("gpio-pxa", ZEUS_MMC_CD_GPIO,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("gpio-pxa", ZEUS_MMC_WP_GPIO,
"wp", GPIO_ACTIVE_HIGH),
{ },
},
};
/*
@ -883,6 +891,7 @@ static void __init zeus_init(void)
else
pxa_set_fb_info(NULL, &zeus_fb_info);
gpiod_add_lookup_table(&zeus_mci_gpio_table);
pxa_set_mci_info(&zeus_mci_platform_data);
pxa_set_udc_info(&zeus_udc_info);
pxa_set_ac97_info(&zeus_ac97_info);

View File

@ -19,7 +19,7 @@
#include <linux/leds.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/smc91x.h>
@ -227,33 +227,68 @@ static inline void zylonite_init_lcd(void) {}
static struct pxamci_platform_data zylonite_mci_platform_data = {
.detect_delay_ms= 200,
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.gpio_card_detect = EXT_GPIO(0),
.gpio_card_ro = EXT_GPIO(2),
.gpio_power = -1,
};
#define PCA9539A_MCI_CD 0
#define PCA9539A_MCI1_CD 1
#define PCA9539A_MCI_WP 2
#define PCA9539A_MCI1_WP 3
#define PCA9539A_MCI3_CD 30
#define PCA9539A_MCI3_WP 31
static struct gpiod_lookup_table zylonite_mci_gpio_table = {
.dev_id = "pxa2xx-mci.0",
.table = {
GPIO_LOOKUP("i2c-pca9539-a", PCA9539A_MCI_CD,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("i2c-pca9539-a", PCA9539A_MCI_WP,
"wp", GPIO_ACTIVE_LOW),
{ },
},
};
static struct pxamci_platform_data zylonite_mci2_platform_data = {
.detect_delay_ms= 200,
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.gpio_card_detect = EXT_GPIO(1),
.gpio_card_ro = EXT_GPIO(3),
.gpio_power = -1,
};
static struct gpiod_lookup_table zylonite_mci2_gpio_table = {
.dev_id = "pxa2xx-mci.1",
.table = {
GPIO_LOOKUP("i2c-pca9539-a", PCA9539A_MCI1_CD,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("i2c-pca9539-a", PCA9539A_MCI1_WP,
"wp", GPIO_ACTIVE_LOW),
{ },
},
};
static struct pxamci_platform_data zylonite_mci3_platform_data = {
.detect_delay_ms= 200,
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
.gpio_card_detect = EXT_GPIO(30),
.gpio_card_ro = EXT_GPIO(31),
.gpio_power = -1,
};
static struct gpiod_lookup_table zylonite_mci3_gpio_table = {
.dev_id = "pxa2xx-mci.2",
.table = {
GPIO_LOOKUP("i2c-pca9539-a", PCA9539A_MCI3_CD,
"cd", GPIO_ACTIVE_LOW),
GPIO_LOOKUP("i2c-pca9539-a", PCA9539A_MCI3_WP,
"wp", GPIO_ACTIVE_LOW),
{ },
},
};
static void __init zylonite_init_mmc(void)
{
gpiod_add_lookup_table(&zylonite_mci_gpio_table);
pxa_set_mci_info(&zylonite_mci_platform_data);
gpiod_add_lookup_table(&zylonite_mci2_gpio_table);
pxa3xx_set_mci2_info(&zylonite_mci2_platform_data);
if (cpu_is_pxa310())
if (cpu_is_pxa310()) {
gpiod_add_lookup_table(&zylonite_mci3_gpio_table);
pxa3xx_set_mci3_info(&zylonite_mci3_platform_data);
}
}
#else
static inline void zylonite_init_mmc(void) {}

View File

@ -230,11 +230,13 @@ static struct pca953x_platform_data gpio_exp[] = {
static struct i2c_board_info zylonite_i2c_board_info[] = {
{
.type = "pca9539",
.dev_name = "pca9539-a",
.addr = 0x74,
.platform_data = &gpio_exp[0],
.irq = PXA_GPIO_TO_IRQ(18),
}, {
.type = "pca9539",
.dev_name = "pca9539-b",
.addr = 0x75,
.platform_data = &gpio_exp[1],
.irq = PXA_GPIO_TO_IRQ(19),

View File

@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
@ -136,7 +136,16 @@ static struct platform_device at2440evb_device_eth = {
};
static struct s3c24xx_mci_pdata at2440evb_mci_pdata __initdata = {
.gpio_detect = S3C2410_GPG(10),
/* Intentionally left blank */
};
static struct gpiod_lookup_table at2440evb_mci_gpio_table = {
.dev_id = "s3c2410-sdi",
.table = {
/* Card detect S3C2410_GPG(10) */
GPIO_LOOKUP("GPG", 10, "cd", GPIO_ACTIVE_LOW),
{ },
},
};
/* 7" LCD panel */
@ -200,6 +209,7 @@ static void __init at2440evb_init_time(void)
static void __init at2440evb_init(void)
{
s3c24xx_fb_set_platdata(&at2440evb_fb_info);
gpiod_add_lookup_table(&at2440evb_mci_gpio_table);
s3c24xx_mci_set_platdata(&at2440evb_mci_pdata);
s3c_nand_set_platdata(&at2440evb_nand_info);
s3c_i2c0_set_platdata(NULL);

View File

@ -18,6 +18,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/pwm.h>
@ -459,12 +460,21 @@ static void h1940_set_mmc_power(unsigned char power_mode, unsigned short vdd)
}
static struct s3c24xx_mci_pdata h1940_mmc_cfg __initdata = {
.gpio_detect = S3C2410_GPF(5),
.gpio_wprotect = S3C2410_GPH(8),
.set_power = h1940_set_mmc_power,
.ocr_avail = MMC_VDD_32_33,
};
static struct gpiod_lookup_table h1940_mmc_gpio_table = {
.dev_id = "s3c2410-sdi",
.table = {
/* Card detect S3C2410_GPF(5) */
GPIO_LOOKUP("GPF", 5, "cd", GPIO_ACTIVE_LOW),
/* Write protect S3C2410_GPH(8) */
GPIO_LOOKUP("GPH", 8, "wp", GPIO_ACTIVE_LOW),
{ },
},
};
static struct pwm_lookup h1940_pwm_lookup[] = {
PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight", NULL, 36296,
PWM_POLARITY_NORMAL),
@ -680,6 +690,7 @@ static void __init h1940_init(void)
u32 tmp;
s3c24xx_fb_set_platdata(&h1940_fb_info);
gpiod_add_lookup_table(&h1940_mmc_gpio_table);
s3c24xx_mci_set_platdata(&h1940_mmc_cfg);
s3c24xx_udc_set_platdata(&h1940_udc_cfg);
s3c24xx_ts_set_platdata(&h1940_ts_cfg);

View File

@ -15,6 +15,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/input.h>
#include <linux/io.h>
#include <linux/serial_core.h>
@ -234,13 +235,22 @@ static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
/* MMC/SD */
static struct s3c24xx_mci_pdata mini2440_mmc_cfg __initdata = {
.gpio_detect = S3C2410_GPG(8),
.gpio_wprotect = S3C2410_GPH(8),
.wprotect_invert = 1,
.set_power = NULL,
.ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34,
};
static struct gpiod_lookup_table mini2440_mmc_gpio_table = {
.dev_id = "s3c2410-sdi",
.table = {
/* Card detect S3C2410_GPG(8) */
GPIO_LOOKUP("GPG", 8, "cd", GPIO_ACTIVE_LOW),
/* Write protect S3C2410_GPH(8) */
GPIO_LOOKUP("GPH", 8, "wp", GPIO_ACTIVE_HIGH),
{ },
},
};
/* NAND Flash on MINI2440 board */
static struct mtd_partition mini2440_default_nand_part[] __initdata = {
@ -696,6 +706,7 @@ static void __init mini2440_init(void)
}
s3c24xx_udc_set_platdata(&mini2440_udc_cfg);
gpiod_add_lookup_table(&mini2440_mmc_gpio_table);
s3c24xx_mci_set_platdata(&mini2440_mmc_cfg);
s3c_nand_set_platdata(&mini2440_nand_info);
s3c_i2c0_set_platdata(NULL);

View File

@ -17,6 +17,7 @@
#include <linux/gpio_keys.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
@ -350,12 +351,21 @@ static void n30_sdi_set_power(unsigned char power_mode, unsigned short vdd)
}
static struct s3c24xx_mci_pdata n30_mci_cfg __initdata = {
.gpio_detect = S3C2410_GPF(1),
.gpio_wprotect = S3C2410_GPG(10),
.ocr_avail = MMC_VDD_32_33,
.set_power = n30_sdi_set_power,
};
static struct gpiod_lookup_table n30_mci_gpio_table = {
.dev_id = "s3c2410-sdi",
.table = {
/* Card detect S3C2410_GPF(1) */
GPIO_LOOKUP("GPF", 1, "cd", GPIO_ACTIVE_LOW),
/* Write protect S3C2410_GPG(10) */
GPIO_LOOKUP("GPG", 10, "wp", GPIO_ACTIVE_LOW),
{ },
},
};
static struct platform_device *n30_devices[] __initdata = {
&s3c_device_lcd,
&s3c_device_wdt,
@ -549,6 +559,7 @@ static void __init n30_init(void)
s3c24xx_fb_set_platdata(&n30_fb_info);
s3c24xx_udc_set_platdata(&n30_udc_cfg);
gpiod_add_lookup_table(&n30_mci_gpio_table);
s3c24xx_mci_set_platdata(&n30_mci_cfg);
s3c_i2c0_set_platdata(&n30_i2ccfg);

View File

@ -14,6 +14,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/gpio/machine.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/serial_s3c.h>
@ -558,12 +559,21 @@ static void rx1950_set_mmc_power(unsigned char power_mode, unsigned short vdd)
}
static struct s3c24xx_mci_pdata rx1950_mmc_cfg __initdata = {
.gpio_detect = S3C2410_GPF(5),
.gpio_wprotect = S3C2410_GPH(8),
.set_power = rx1950_set_mmc_power,
.ocr_avail = MMC_VDD_32_33,
};
static struct gpiod_lookup_table rx1950_mmc_gpio_table = {
.dev_id = "s3c2410-sdi",
.table = {
/* Card detect S3C2410_GPF(5) */
GPIO_LOOKUP("GPF", 5, "cd", GPIO_ACTIVE_LOW),
/* Write protect S3C2410_GPH(8) */
GPIO_LOOKUP("GPH", 8, "wp", GPIO_ACTIVE_LOW),
{ },
},
};
static struct mtd_partition rx1950_nand_part[] = {
[0] = {
.name = "Boot0",
@ -762,6 +772,7 @@ static void __init rx1950_init_machine(void)
s3c24xx_fb_set_platdata(&rx1950_lcd_cfg);
s3c24xx_udc_set_platdata(&rx1950_udc_cfg);
s3c24xx_ts_set_platdata(&rx1950_ts_cfg);
gpiod_add_lookup_table(&rx1950_mmc_gpio_table);
s3c24xx_mci_set_platdata(&rx1950_mmc_cfg);
s3c_i2c0_set_platdata(NULL);
s3c_nand_set_platdata(&rx1950_nand_info);

View File

@ -3,12 +3,8 @@
#define __LINUX_MMC_JZ4740_MMC
struct jz4740_mmc_platform_data {
int gpio_power;
int gpio_card_detect;
int gpio_read_only;
unsigned card_detect_active_low:1;
unsigned read_only_active_low:1;
unsigned power_active_low:1;
unsigned data_1bit:1;
};

View File

@ -43,9 +43,6 @@
#include "clock.h"
/* GPIOs */
#define QI_LB60_GPIO_SD_CD JZ_GPIO_PORTD(0)
#define QI_LB60_GPIO_SD_VCC_EN_N JZ_GPIO_PORTD(2)
#define QI_LB60_GPIO_KEYOUT(x) (JZ_GPIO_PORTC(10) + (x))
#define QI_LB60_GPIO_KEYIN(x) (JZ_GPIO_PORTD(18) + (x))
#define QI_LB60_GPIO_KEYIN8 JZ_GPIO_PORTD(26)
@ -386,10 +383,16 @@ static struct platform_device qi_lb60_gpio_keys = {
};
static struct jz4740_mmc_platform_data qi_lb60_mmc_pdata = {
.gpio_card_detect = QI_LB60_GPIO_SD_CD,
.gpio_read_only = -1,
.gpio_power = QI_LB60_GPIO_SD_VCC_EN_N,
.power_active_low = 1,
/* Intentionally left blank */
};
static struct gpiod_lookup_table qi_lb60_mmc_gpio_table = {
.dev_id = "jz4740-mmc.0",
.table = {
GPIO_LOOKUP("GPIOD", 0, "cd", GPIO_ACTIVE_HIGH),
GPIO_LOOKUP("GPIOD", 2, "power", GPIO_ACTIVE_LOW),
{ },
},
};
/* beeper */
@ -500,6 +503,7 @@ static int __init qi_lb60_init_platform_devices(void)
gpiod_add_lookup_table(&qi_lb60_audio_gpio_table);
gpiod_add_lookup_table(&qi_lb60_nand_gpio_table);
gpiod_add_lookup_table(&qi_lb60_spigpio_gpio_table);
gpiod_add_lookup_table(&qi_lb60_mmc_gpio_table);
spi_register_board_info(qi_lb60_spi_board_info,
ARRAY_SIZE(qi_lb60_spi_board_info));

View File

@ -696,13 +696,20 @@ static struct gpiod_lookup_table sdhi0_power_gpiod_table = {
},
};
static struct gpiod_lookup_table sdhi0_gpio_table = {
.dev_id = "sh_mobile_sdhi.0",
.table = {
/* Card detect */
GPIO_LOOKUP("sh7724_pfc", GPIO_PTY7, "cd", GPIO_ACTIVE_LOW),
{ },
},
};
static struct tmio_mmc_data sdhi0_info = {
.chan_priv_tx = (void *)SHDMA_SLAVE_SDHI0_TX,
.chan_priv_rx = (void *)SHDMA_SLAVE_SDHI0_RX,
.capabilities = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD |
MMC_CAP_NEEDS_POLL,
.flags = TMIO_MMC_USE_GPIO_CD,
.cd_gpio = GPIO_PTY7,
};
static struct resource sdhi0_resources[] = {
@ -735,8 +742,15 @@ static struct tmio_mmc_data sdhi1_info = {
.chan_priv_rx = (void *)SHDMA_SLAVE_SDHI1_RX,
.capabilities = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD |
MMC_CAP_NEEDS_POLL,
.flags = TMIO_MMC_USE_GPIO_CD,
.cd_gpio = GPIO_PTW7,
};
static struct gpiod_lookup_table sdhi1_gpio_table = {
.dev_id = "sh_mobile_sdhi.1",
.table = {
/* Card detect */
GPIO_LOOKUP("sh7724_pfc", GPIO_PTW7, "cd", GPIO_ACTIVE_LOW),
{ },
},
};
static struct resource sdhi1_resources[] = {
@ -776,9 +790,19 @@ static struct mmc_spi_platform_data mmc_spi_info = {
.caps2 = MMC_CAP2_RO_ACTIVE_HIGH,
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, /* 3.3V only */
.setpower = mmc_spi_setpower,
.flags = MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO,
.cd_gpio = GPIO_PTY7,
.ro_gpio = GPIO_PTY6,
};
static struct gpiod_lookup_table mmc_spi_gpio_table = {
.dev_id = "mmc_spi.0", /* device "mmc_spi" @ CS0 */
.table = {
/* Card detect */
GPIO_LOOKUP_IDX("sh7724_pfc", GPIO_PTY7, NULL, 0,
GPIO_ACTIVE_LOW),
/* Write protect */
GPIO_LOOKUP_IDX("sh7724_pfc", GPIO_PTY6, NULL, 1,
GPIO_ACTIVE_HIGH),
{ },
},
};
static struct spi_board_info spi_bus[] = {
@ -1282,6 +1306,7 @@ static int __init arch_setup(void)
gpio_request(GPIO_PTB6, NULL); /* 3.3V power control */
gpio_direction_output(GPIO_PTB6, 0); /* disable power by default */
gpiod_add_lookup_table(&mmc_spi_gpio_table);
spi_register_board_info(spi_bus, ARRAY_SIZE(spi_bus));
#endif
@ -1434,6 +1459,10 @@ static int __init arch_setup(void)
gpiod_add_lookup_table(&cn12_power_gpiod_table);
#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
gpiod_add_lookup_table(&sdhi0_power_gpiod_table);
gpiod_add_lookup_table(&sdhi0_gpio_table);
#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
gpiod_add_lookup_table(&sdhi1_gpio_table);
#endif
#endif
return platform_add_devices(ecovec_devices,

View File

@ -449,7 +449,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
gc->base = chip->gpio_start;
gc->ngpio = gpios;
gc->label = chip->client->name;
gc->label = dev_name(&chip->client->dev);
gc->parent = &chip->client->dev;
gc->owner = THIS_MODULE;
gc->names = chip->names;

View File

@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#define DRIVER_NAME "memstick"
@ -436,6 +437,7 @@ static void memstick_check(struct work_struct *work)
struct memstick_dev *card;
dev_dbg(&host->dev, "memstick_check started\n");
pm_runtime_get_noresume(host->dev.parent);
mutex_lock(&host->lock);
if (!host->card) {
if (memstick_power_on(host))
@ -479,6 +481,7 @@ out_power_off:
host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF);
mutex_unlock(&host->lock);
pm_runtime_put(host->dev.parent);
dev_dbg(&host->dev, "memstick_check finished\n");
}

View File

@ -40,15 +40,14 @@ struct rtsx_usb_ms {
struct mutex host_mutex;
struct work_struct handle_req;
struct task_struct *detect_ms;
struct completion detect_ms_exit;
struct delayed_work poll_card;
u8 ssc_depth;
unsigned int clock;
int power_mode;
unsigned char ifmode;
bool eject;
bool system_suspending;
};
static inline struct device *ms_dev(struct rtsx_usb_ms *host)
@ -545,7 +544,7 @@ static void rtsx_usb_ms_handle_req(struct work_struct *work)
host->req->error);
}
} while (!rc);
pm_runtime_put(ms_dev(host));
pm_runtime_put_sync(ms_dev(host));
}
}
@ -585,14 +584,14 @@ static int rtsx_usb_ms_set_param(struct memstick_host *msh,
break;
if (value == MEMSTICK_POWER_ON) {
pm_runtime_get_sync(ms_dev(host));
pm_runtime_get_noresume(ms_dev(host));
err = ms_power_on(host);
if (err)
pm_runtime_put_noidle(ms_dev(host));
} else if (value == MEMSTICK_POWER_OFF) {
err = ms_power_off(host);
if (host->msh->card)
if (!err)
pm_runtime_put_noidle(ms_dev(host));
else
pm_runtime_put(ms_dev(host));
} else
err = -EINVAL;
if (!err)
@ -638,12 +637,16 @@ static int rtsx_usb_ms_set_param(struct memstick_host *msh,
}
out:
mutex_unlock(&ucr->dev_mutex);
pm_runtime_put(ms_dev(host));
pm_runtime_put_sync(ms_dev(host));
/* power-on delay */
if (param == MEMSTICK_POWER && value == MEMSTICK_POWER_ON)
if (param == MEMSTICK_POWER && value == MEMSTICK_POWER_ON) {
usleep_range(10000, 12000);
if (!host->eject)
schedule_delayed_work(&host->poll_card, 100);
}
dev_dbg(ms_dev(host), "%s: return = %d\n", __func__, err);
return err;
}
@ -654,9 +657,24 @@ static int rtsx_usb_ms_suspend(struct device *dev)
struct rtsx_usb_ms *host = dev_get_drvdata(dev);
struct memstick_host *msh = host->msh;
dev_dbg(ms_dev(host), "--> %s\n", __func__);
/* Since we use rtsx_usb's resume callback to runtime resume its
* children to implement remote wakeup signaling, this causes
* rtsx_usb_ms' runtime resume callback runs after its suspend
* callback:
* rtsx_usb_ms_suspend()
* rtsx_usb_resume()
* -> rtsx_usb_ms_runtime_resume()
* -> memstick_detect_change()
*
* rtsx_usb_suspend()
*
* To avoid this, skip runtime resume/suspend if system suspend is
* underway.
*/
host->system_suspending = true;
memstick_suspend_host(msh);
return 0;
}
@ -665,58 +683,85 @@ static int rtsx_usb_ms_resume(struct device *dev)
struct rtsx_usb_ms *host = dev_get_drvdata(dev);
struct memstick_host *msh = host->msh;
dev_dbg(ms_dev(host), "--> %s\n", __func__);
memstick_resume_host(msh);
host->system_suspending = false;
return 0;
}
#endif /* CONFIG_PM_SLEEP */
/*
* Thread function of ms card slot detection. The thread starts right after
* successful host addition. It stops while the driver removal function sets
* host->eject true.
*/
static int rtsx_usb_detect_ms_card(void *__host)
#ifdef CONFIG_PM
static int rtsx_usb_ms_runtime_suspend(struct device *dev)
{
struct rtsx_usb_ms *host = (struct rtsx_usb_ms *)__host;
struct rtsx_usb_ms *host = dev_get_drvdata(dev);
if (host->system_suspending)
return 0;
if (host->msh->card || host->power_mode != MEMSTICK_POWER_OFF)
return -EAGAIN;
return 0;
}
static int rtsx_usb_ms_runtime_resume(struct device *dev)
{
struct rtsx_usb_ms *host = dev_get_drvdata(dev);
if (host->system_suspending)
return 0;
memstick_detect_change(host->msh);
return 0;
}
#endif /* CONFIG_PM */
static const struct dev_pm_ops rtsx_usb_ms_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(rtsx_usb_ms_suspend, rtsx_usb_ms_resume)
SET_RUNTIME_PM_OPS(rtsx_usb_ms_runtime_suspend, rtsx_usb_ms_runtime_resume, NULL)
};
static void rtsx_usb_ms_poll_card(struct work_struct *work)
{
struct rtsx_usb_ms *host = container_of(work, struct rtsx_usb_ms,
poll_card.work);
struct rtsx_ucr *ucr = host->ucr;
u8 val = 0;
int err;
u8 val;
for (;;) {
pm_runtime_get_sync(ms_dev(host));
mutex_lock(&ucr->dev_mutex);
if (host->eject || host->power_mode != MEMSTICK_POWER_ON)
return;
/* Check pending MS card changes */
err = rtsx_usb_read_register(ucr, CARD_INT_PEND, &val);
if (err) {
mutex_unlock(&ucr->dev_mutex);
goto poll_again;
}
/* Clear the pending */
rtsx_usb_write_register(ucr, CARD_INT_PEND,
XD_INT | MS_INT | SD_INT,
XD_INT | MS_INT | SD_INT);
pm_runtime_get_sync(ms_dev(host));
mutex_lock(&ucr->dev_mutex);
/* Check pending MS card changes */
err = rtsx_usb_read_register(ucr, CARD_INT_PEND, &val);
if (err) {
mutex_unlock(&ucr->dev_mutex);
if (val & MS_INT) {
dev_dbg(ms_dev(host), "MS slot change detected\n");
memstick_detect_change(host->msh);
}
poll_again:
pm_runtime_put(ms_dev(host));
if (host->eject)
break;
schedule_timeout_idle(HZ);
goto poll_again;
}
complete(&host->detect_ms_exit);
return 0;
/* Clear the pending */
rtsx_usb_write_register(ucr, CARD_INT_PEND,
XD_INT | MS_INT | SD_INT,
XD_INT | MS_INT | SD_INT);
mutex_unlock(&ucr->dev_mutex);
if (val & MS_INT) {
dev_dbg(ms_dev(host), "MS slot change detected\n");
memstick_detect_change(host->msh);
}
poll_again:
pm_runtime_put_sync(ms_dev(host));
if (!host->eject && host->power_mode == MEMSTICK_POWER_ON)
schedule_delayed_work(&host->poll_card, 100);
}
static int rtsx_usb_ms_drv_probe(struct platform_device *pdev)
@ -747,45 +792,42 @@ static int rtsx_usb_ms_drv_probe(struct platform_device *pdev)
mutex_init(&host->host_mutex);
INIT_WORK(&host->handle_req, rtsx_usb_ms_handle_req);
init_completion(&host->detect_ms_exit);
host->detect_ms = kthread_create(rtsx_usb_detect_ms_card, host,
"rtsx_usb_ms_%d", pdev->id);
if (IS_ERR(host->detect_ms)) {
dev_dbg(&(pdev->dev),
"Unable to create polling thread.\n");
err = PTR_ERR(host->detect_ms);
goto err_out;
}
INIT_DELAYED_WORK(&host->poll_card, rtsx_usb_ms_poll_card);
msh->request = rtsx_usb_ms_request;
msh->set_param = rtsx_usb_ms_set_param;
msh->caps = MEMSTICK_CAP_PAR4;
pm_runtime_enable(&pdev->dev);
pm_runtime_get_noresume(ms_dev(host));
pm_runtime_set_active(ms_dev(host));
pm_runtime_enable(ms_dev(host));
err = memstick_add_host(msh);
if (err)
goto err_out;
wake_up_process(host->detect_ms);
pm_runtime_put(ms_dev(host));
return 0;
err_out:
memstick_free_host(msh);
pm_runtime_disable(ms_dev(host));
pm_runtime_put_noidle(ms_dev(host));
return err;
}
static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
{
struct rtsx_usb_ms *host = platform_get_drvdata(pdev);
struct memstick_host *msh;
struct memstick_host *msh = host->msh;
int err;
msh = host->msh;
host->eject = true;
cancel_work_sync(&host->handle_req);
mutex_lock(&host->host_mutex);
if (host->req) {
dev_dbg(&(pdev->dev),
dev_dbg(ms_dev(host),
"%s: Controller removed during transfer\n",
dev_name(&msh->dev));
host->req->error = -ENOMEDIUM;
@ -797,7 +839,6 @@ static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
}
mutex_unlock(&host->host_mutex);
wait_for_completion(&host->detect_ms_exit);
memstick_remove_host(msh);
memstick_free_host(msh);
@ -807,18 +848,15 @@ static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
if (pm_runtime_active(ms_dev(host)))
pm_runtime_put(ms_dev(host));
pm_runtime_disable(&pdev->dev);
pm_runtime_disable(ms_dev(host));
platform_set_drvdata(pdev, NULL);
dev_dbg(&(pdev->dev),
dev_dbg(ms_dev(host),
": Realtek USB Memstick controller has been removed\n");
return 0;
}
static SIMPLE_DEV_PM_OPS(rtsx_usb_ms_pm_ops,
rtsx_usb_ms_suspend, rtsx_usb_ms_resume);
static struct platform_device_id rtsx_usb_ms_ids[] = {
{
.name = "rtsx_usb_ms",

View File

@ -57,4 +57,4 @@ obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o
obj-$(CONFIG_OCXL) += ocxl/
obj-$(CONFIG_MISC_RTSX) += cardreader/
obj-y += cardreader/

View File

@ -1,3 +1,14 @@
config MISC_ALCOR_PCI
tristate "Alcor Micro/Alcor Link PCI-E card reader"
depends on PCI
select MFD_CORE
help
This supports for Alcor Micro PCI-Express card reader including au6601,
au6621.
Alcor Micro card readers support access to many types of memory cards,
such as Memory Stick, Memory Stick Pro, Secure Digital and
MultiMediaCard.
config MISC_RTSX_PCI
tristate "Realtek PCI-E card reader"
depends on PCI

View File

@ -1,4 +1,4 @@
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o rts5260.o
obj-$(CONFIG_MISC_ALCOR_PCI) += alcor_pci.o
obj-$(CONFIG_MISC_RTSX_PCI) += rtsx_pci.o
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o rts5260.o
obj-$(CONFIG_MISC_RTSX_USB) += rtsx_usb.o

View File

@ -0,0 +1,371 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2018 Oleksij Rempel <linux@rempel-privat.de>
*
* Driver for Alcor Micro AU6601 and AU6621 controllers
*/
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/alcor_pci.h>
#define DRV_NAME_ALCOR_PCI "alcor_pci"
static DEFINE_IDA(alcor_pci_idr);
static struct mfd_cell alcor_pci_cells[] = {
[ALCOR_SD_CARD] = {
.name = DRV_NAME_ALCOR_PCI_SDMMC,
},
[ALCOR_MS_CARD] = {
.name = DRV_NAME_ALCOR_PCI_MS,
},
};
static const struct alcor_dev_cfg alcor_cfg = {
.dma = 0,
};
static const struct alcor_dev_cfg au6621_cfg = {
.dma = 1,
};
static const struct pci_device_id pci_ids[] = {
{ PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6601),
.driver_data = (kernel_ulong_t)&alcor_cfg },
{ PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6621),
.driver_data = (kernel_ulong_t)&au6621_cfg },
{ },
};
MODULE_DEVICE_TABLE(pci, pci_ids);
void alcor_write8(struct alcor_pci_priv *priv, u8 val, unsigned int addr)
{
writeb(val, priv->iobase + addr);
}
EXPORT_SYMBOL_GPL(alcor_write8);
void alcor_write16(struct alcor_pci_priv *priv, u16 val, unsigned int addr)
{
writew(val, priv->iobase + addr);
}
EXPORT_SYMBOL_GPL(alcor_write16);
void alcor_write32(struct alcor_pci_priv *priv, u32 val, unsigned int addr)
{
writel(val, priv->iobase + addr);
}
EXPORT_SYMBOL_GPL(alcor_write32);
void alcor_write32be(struct alcor_pci_priv *priv, u32 val, unsigned int addr)
{
iowrite32be(val, priv->iobase + addr);
}
EXPORT_SYMBOL_GPL(alcor_write32be);
u8 alcor_read8(struct alcor_pci_priv *priv, unsigned int addr)
{
return readb(priv->iobase + addr);
}
EXPORT_SYMBOL_GPL(alcor_read8);
u32 alcor_read32(struct alcor_pci_priv *priv, unsigned int addr)
{
return readl(priv->iobase + addr);
}
EXPORT_SYMBOL_GPL(alcor_read32);
u32 alcor_read32be(struct alcor_pci_priv *priv, unsigned int addr)
{
return ioread32be(priv->iobase + addr);
}
EXPORT_SYMBOL_GPL(alcor_read32be);
static int alcor_pci_find_cap_offset(struct alcor_pci_priv *priv,
struct pci_dev *pci)
{
int where;
u8 val8;
u32 val32;
where = ALCOR_CAP_START_OFFSET;
pci_read_config_byte(pci, where, &val8);
if (!val8)
return 0;
where = (int)val8;
while (1) {
pci_read_config_dword(pci, where, &val32);
if (val32 == 0xffffffff) {
dev_dbg(priv->dev, "find_cap_offset invalid value %x.\n",
val32);
return 0;
}
if ((val32 & 0xff) == 0x10) {
dev_dbg(priv->dev, "pcie cap offset: %x\n", where);
return where;
}
if ((val32 & 0xff00) == 0x00) {
dev_dbg(priv->dev, "pci_find_cap_offset invalid value %x.\n",
val32);
break;
}
where = (int)((val32 >> 8) & 0xff);
}
return 0;
}
static void alcor_pci_init_check_aspm(struct alcor_pci_priv *priv)
{
struct pci_dev *pci;
int where;
u32 val32;
priv->pdev_cap_off = alcor_pci_find_cap_offset(priv, priv->pdev);
priv->parent_cap_off = alcor_pci_find_cap_offset(priv,
priv->parent_pdev);
if ((priv->pdev_cap_off == 0) || (priv->parent_cap_off == 0)) {
dev_dbg(priv->dev, "pci_cap_off: %x, parent_cap_off: %x\n",
priv->pdev_cap_off, priv->parent_cap_off);
return;
}
/* link capability */
pci = priv->pdev;
where = priv->pdev_cap_off + ALCOR_PCIE_LINK_CAP_OFFSET;
pci_read_config_dword(pci, where, &val32);
priv->pdev_aspm_cap = (u8)(val32 >> 10) & 0x03;
pci = priv->parent_pdev;
where = priv->parent_cap_off + ALCOR_PCIE_LINK_CAP_OFFSET;
pci_read_config_dword(pci, where, &val32);
priv->parent_aspm_cap = (u8)(val32 >> 10) & 0x03;
if (priv->pdev_aspm_cap != priv->parent_aspm_cap) {
u8 aspm_cap;
dev_dbg(priv->dev, "pdev_aspm_cap: %x, parent_aspm_cap: %x\n",
priv->pdev_aspm_cap, priv->parent_aspm_cap);
aspm_cap = priv->pdev_aspm_cap & priv->parent_aspm_cap;
priv->pdev_aspm_cap = aspm_cap;
priv->parent_aspm_cap = aspm_cap;
}
dev_dbg(priv->dev, "ext_config_dev_aspm: %x, pdev_aspm_cap: %x\n",
priv->ext_config_dev_aspm, priv->pdev_aspm_cap);
priv->ext_config_dev_aspm &= priv->pdev_aspm_cap;
}
static void alcor_pci_aspm_ctrl(struct alcor_pci_priv *priv, u8 aspm_enable)
{
struct pci_dev *pci;
u8 aspm_ctrl, i;
int where;
u32 val32;
if ((!priv->pdev_cap_off) || (!priv->parent_cap_off)) {
dev_dbg(priv->dev, "pci_cap_off: %x, parent_cap_off: %x\n",
priv->pdev_cap_off, priv->parent_cap_off);
return;
}
if (!priv->pdev_aspm_cap)
return;
aspm_ctrl = 0;
if (aspm_enable) {
aspm_ctrl = priv->ext_config_dev_aspm;
if (!aspm_ctrl) {
dev_dbg(priv->dev, "aspm_ctrl == 0\n");
return;
}
}
for (i = 0; i < 2; i++) {
if (i) {
pci = priv->parent_pdev;
where = priv->parent_cap_off
+ ALCOR_PCIE_LINK_CTRL_OFFSET;
} else {
pci = priv->pdev;
where = priv->pdev_cap_off
+ ALCOR_PCIE_LINK_CTRL_OFFSET;
}
pci_read_config_dword(pci, where, &val32);
val32 &= (~0x03);
val32 |= (aspm_ctrl & priv->pdev_aspm_cap);
pci_write_config_byte(pci, where, (u8)val32);
}
}
static inline void alcor_mask_sd_irqs(struct alcor_pci_priv *priv)
{
alcor_write32(priv, 0, AU6601_REG_INT_ENABLE);
}
static inline void alcor_unmask_sd_irqs(struct alcor_pci_priv *priv)
{
alcor_write32(priv, AU6601_INT_CMD_MASK | AU6601_INT_DATA_MASK |
AU6601_INT_CARD_INSERT | AU6601_INT_CARD_REMOVE |
AU6601_INT_OVER_CURRENT_ERR,
AU6601_REG_INT_ENABLE);
}
static inline void alcor_mask_ms_irqs(struct alcor_pci_priv *priv)
{
alcor_write32(priv, 0, AU6601_MS_INT_ENABLE);
}
static inline void alcor_unmask_ms_irqs(struct alcor_pci_priv *priv)
{
alcor_write32(priv, 0x3d00fa, AU6601_MS_INT_ENABLE);
}
static int alcor_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct alcor_dev_cfg *cfg;
struct alcor_pci_priv *priv;
int ret, i, bar = 0;
cfg = (void *)ent->driver_data;
ret = pcim_enable_device(pdev);
if (ret)
return ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
ret = ida_simple_get(&alcor_pci_idr, 0, 0, GFP_KERNEL);
if (ret < 0)
return ret;
priv->id = ret;
priv->pdev = pdev;
priv->parent_pdev = pdev->bus->self;
priv->dev = &pdev->dev;
priv->cfg = cfg;
priv->irq = pdev->irq;
ret = pci_request_regions(pdev, DRV_NAME_ALCOR_PCI);
if (ret) {
dev_err(&pdev->dev, "Cannot request region\n");
return -ENOMEM;
}
if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar);
ret = -ENODEV;
goto error_release_regions;
}
priv->iobase = pcim_iomap(pdev, bar, 0);
if (!priv->iobase) {
ret = -ENOMEM;
goto error_release_regions;
}
/* make sure irqs are disabled */
alcor_write32(priv, 0, AU6601_REG_INT_ENABLE);
alcor_write32(priv, 0, AU6601_MS_INT_ENABLE);
ret = dma_set_mask_and_coherent(priv->dev, AU6601_SDMA_MASK);
if (ret) {
dev_err(priv->dev, "Failed to set DMA mask\n");
goto error_release_regions;
}
pci_set_master(pdev);
pci_set_drvdata(pdev, priv);
alcor_pci_init_check_aspm(priv);
for (i = 0; i < ARRAY_SIZE(alcor_pci_cells); i++) {
alcor_pci_cells[i].platform_data = priv;
alcor_pci_cells[i].pdata_size = sizeof(*priv);
}
ret = mfd_add_devices(&pdev->dev, priv->id, alcor_pci_cells,
ARRAY_SIZE(alcor_pci_cells), NULL, 0, NULL);
if (ret < 0)
goto error_release_regions;
alcor_pci_aspm_ctrl(priv, 0);
return 0;
error_release_regions:
pci_release_regions(pdev);
return ret;
}
static void alcor_pci_remove(struct pci_dev *pdev)
{
struct alcor_pci_priv *priv;
priv = pci_get_drvdata(pdev);
alcor_pci_aspm_ctrl(priv, 1);
mfd_remove_devices(&pdev->dev);
ida_simple_remove(&alcor_pci_idr, priv->id);
pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
}
#ifdef CONFIG_PM_SLEEP
static int alcor_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct alcor_pci_priv *priv = pci_get_drvdata(pdev);
alcor_pci_aspm_ctrl(priv, 1);
return 0;
}
static int alcor_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct alcor_pci_priv *priv = pci_get_drvdata(pdev);
alcor_pci_aspm_ctrl(priv, 0);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(alcor_pci_pm_ops, alcor_suspend, alcor_resume);
static struct pci_driver alcor_driver = {
.name = DRV_NAME_ALCOR_PCI,
.id_table = pci_ids,
.probe = alcor_pci_probe,
.remove = alcor_pci_remove,
.driver = {
.pm = &alcor_pci_pm_ops
},
};
module_pci_driver(alcor_driver);
MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>");
MODULE_DESCRIPTION("PCI driver for Alcor Micro AU6601 Secure Digital Host Controller Interface");
MODULE_LICENSE("GPL");

View File

@ -723,8 +723,15 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
return 0;
}
static int rtsx_usb_resume_child(struct device *dev, void *data)
{
pm_request_resume(dev);
return 0;
}
static int rtsx_usb_resume(struct usb_interface *intf)
{
device_for_each_child(&intf->dev, NULL, rtsx_usb_resume_child);
return 0;
}
@ -734,6 +741,7 @@ static int rtsx_usb_reset_resume(struct usb_interface *intf)
(struct rtsx_ucr *)usb_get_intfdata(intf);
rtsx_usb_reset_chip(ucr);
device_for_each_child(&intf->dev, NULL, rtsx_usb_resume_child);
return 0;
}

View File

@ -1960,7 +1960,7 @@ static void mmc_blk_urgent_bkops(struct mmc_queue *mq,
struct mmc_queue_req *mqrq)
{
if (mmc_blk_urgent_bkops_needed(mq, mqrq))
mmc_start_bkops(mq->card, true);
mmc_run_bkops(mq->card);
}
void mmc_blk_mq_complete(struct request *req)

View File

@ -23,15 +23,13 @@
#define MMC_STATE_BLOCKADDR (1<<2) /* card uses block-addressing */
#define MMC_CARD_SDXC (1<<3) /* card is SDXC */
#define MMC_CARD_REMOVED (1<<4) /* card has been removed */
#define MMC_STATE_DOING_BKOPS (1<<5) /* card is doing BKOPS */
#define MMC_STATE_SUSPENDED (1<<6) /* card is suspended */
#define MMC_STATE_SUSPENDED (1<<5) /* card is suspended */
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
#define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS)
#define mmc_card_suspended(c) ((c)->state & MMC_STATE_SUSPENDED)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
@ -39,8 +37,6 @@
#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
#define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS)
#define mmc_card_clr_doing_bkops(c) ((c)->state &= ~MMC_STATE_DOING_BKOPS)
#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
#define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)

View File

@ -887,7 +887,10 @@ void mmc_release_host(struct mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags);
wake_up(&host->wq);
pm_runtime_mark_last_busy(mmc_dev(host));
pm_runtime_put_autosuspend(mmc_dev(host));
if (host->caps & MMC_CAP_SYNC_RUNTIME_PM)
pm_runtime_put_sync_suspend(mmc_dev(host));
else
pm_runtime_put_autosuspend(mmc_dev(host));
}
}
EXPORT_SYMBOL(mmc_release_host);
@ -2413,20 +2416,6 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
}
EXPORT_SYMBOL(mmc_set_blocklen);
int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
bool is_rel_write)
{
struct mmc_command cmd = {};
cmd.opcode = MMC_SET_BLOCK_COUNT;
cmd.arg = blockcount & 0x0000FFFF;
if (is_rel_write)
cmd.arg |= 1 << 31;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
return mmc_wait_for_cmd(card->host, &cmd, 5);
}
EXPORT_SYMBOL(mmc_set_blockcount);
static void mmc_hw_reset_for_init(struct mmc_host *host)
{
mmc_pwrseq_reset(host);

View File

@ -118,8 +118,6 @@ int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
unsigned int mmc_calc_max_discard(struct mmc_card *card);
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
bool is_rel_write);
int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
atomic_t *abort);

View File

@ -1181,6 +1181,9 @@ static int mmc_select_hs400(struct mmc_card *card)
if (err)
goto out_err;
if (host->ops->hs400_prepare_ddr)
host->ops->hs400_prepare_ddr(host);
/* Switch card to DDR */
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
@ -2011,12 +2014,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
if (mmc_card_suspended(host->card))
goto out;
if (mmc_card_doing_bkops(host->card)) {
err = mmc_stop_bkops(host->card);
if (err)
goto out;
}
err = mmc_flush_cache(host->card);
if (err)
goto out;

View File

@ -802,12 +802,6 @@ static int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
unsigned int opcode;
int err;
if (!card->ext_csd.hpi) {
pr_warn("%s: Card didn't support HPI command\n",
mmc_hostname(card->host));
return -EINVAL;
}
opcode = card->ext_csd.hpi_cmd;
if (opcode == MMC_STOP_TRANSMISSION)
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
@ -897,34 +891,6 @@ int mmc_can_ext_csd(struct mmc_card *card)
return (card && card->csd.mmca_vsn > CSD_SPEC_VER_3);
}
/**
* mmc_stop_bkops - stop ongoing BKOPS
* @card: MMC card to check BKOPS
*
* Send HPI command to stop ongoing background operations to
* allow rapid servicing of foreground operations, e.g. read/
* writes. Wait until the card comes out of the programming state
* to avoid errors in servicing read/write requests.
*/
int mmc_stop_bkops(struct mmc_card *card)
{
int err = 0;
err = mmc_interrupt_hpi(card);
/*
* If err is EINVAL, we can't issue an HPI.
* It should complete the BKOPS.
*/
if (!err || (err == -EINVAL)) {
mmc_card_clr_doing_bkops(card);
mmc_retune_release(card->host);
err = 0;
}
return err;
}
static int mmc_read_bkops_status(struct mmc_card *card)
{
int err;
@ -941,22 +907,17 @@ static int mmc_read_bkops_status(struct mmc_card *card)
}
/**
* mmc_start_bkops - start BKOPS for supported cards
* @card: MMC card to start BKOPS
* @from_exception: A flag to indicate if this function was
* called due to an exception raised by the card
* mmc_run_bkops - Run BKOPS for supported cards
* @card: MMC card to run BKOPS for
*
* Start background operations whenever requested.
* When the urgent BKOPS bit is set in a R1 command response
* then background operations should be started immediately.
* Run background operations synchronously for cards having manual BKOPS
* enabled and in case it reports urgent BKOPS level.
*/
void mmc_start_bkops(struct mmc_card *card, bool from_exception)
void mmc_run_bkops(struct mmc_card *card)
{
int err;
int timeout;
bool use_busy_signal;
if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card))
if (!card->ext_csd.man_bkops_en)
return;
err = mmc_read_bkops_status(card);
@ -966,44 +927,26 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
return;
}
if (!card->ext_csd.raw_bkops_status)
if (!card->ext_csd.raw_bkops_status ||
card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2)
return;
if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2 &&
from_exception)
return;
if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) {
timeout = MMC_OPS_TIMEOUT_MS;
use_busy_signal = true;
} else {
timeout = 0;
use_busy_signal = false;
}
mmc_retune_hold(card->host);
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BKOPS_START, 1, timeout, 0,
use_busy_signal, true, false);
if (err) {
/*
* For urgent BKOPS status, LEVEL_2 and higher, let's execute
* synchronously. Future wise, we may consider to start BKOPS, for less
* urgent levels by using an asynchronous background task, when idle.
*/
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BKOPS_START, 1, MMC_OPS_TIMEOUT_MS);
if (err)
pr_warn("%s: Error %d starting bkops\n",
mmc_hostname(card->host), err);
mmc_retune_release(card->host);
return;
}
/*
* For urgent bkops status (LEVEL_2 and more)
* bkops executed synchronously, otherwise
* the operation is in progress
*/
if (!use_busy_signal)
mmc_card_set_doing_bkops(card);
else
mmc_retune_release(card->host);
mmc_retune_release(card->host);
}
EXPORT_SYMBOL(mmc_start_bkops);
EXPORT_SYMBOL(mmc_run_bkops);
/*
* Flush the cache to the non-volatile storage.

View File

@ -40,8 +40,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
bool use_busy_signal, bool send_status, bool retry_crc_err);
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms);
int mmc_stop_bkops(struct mmc_card *card);
void mmc_start_bkops(struct mmc_card *card, bool from_exception);
void mmc_run_bkops(struct mmc_card *card);
int mmc_flush_cache(struct mmc_card *card);
int mmc_cmdq_enable(struct mmc_card *card);
int mmc_cmdq_disable(struct mmc_card *card);

View File

@ -3145,17 +3145,7 @@ static int mtf_testlist_show(struct seq_file *sf, void *data)
return 0;
}
static int mtf_testlist_open(struct inode *inode, struct file *file)
{
return single_open(file, mtf_testlist_show, inode->i_private);
}
static const struct file_operations mmc_test_fops_testlist = {
.open = mtf_testlist_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(mtf_testlist);
static void mmc_test_free_dbgfs_file(struct mmc_card *card)
{
@ -3216,7 +3206,7 @@ static int mmc_test_register_dbgfs_file(struct mmc_card *card)
goto err;
ret = __mmc_test_register_dbgfs_file(card, "testlist", S_IRUGO,
&mmc_test_fops_testlist);
&mtf_testlist_fops);
if (ret)
goto err;

View File

@ -9,7 +9,6 @@
*/
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
@ -27,8 +26,8 @@ struct mmc_gpio {
bool override_cd_active_level;
irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id);
char *ro_label;
char *cd_label;
u32 cd_debounce_delay_ms;
char cd_label[];
};
static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
@ -45,15 +44,19 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
int mmc_gpio_alloc(struct mmc_host *host)
{
size_t len = strlen(dev_name(host->parent)) + 4;
struct mmc_gpio *ctx = devm_kzalloc(host->parent,
sizeof(*ctx) + 2 * len, GFP_KERNEL);
sizeof(*ctx), GFP_KERNEL);
if (ctx) {
ctx->ro_label = ctx->cd_label + len;
ctx->cd_debounce_delay_ms = 200;
snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent));
ctx->cd_label = devm_kasprintf(host->parent, GFP_KERNEL,
"%s cd", dev_name(host->parent));
if (!ctx->cd_label)
return -ENOMEM;
ctx->ro_label = devm_kasprintf(host->parent, GFP_KERNEL,
"%s ro", dev_name(host->parent));
if (!ctx->ro_label)
return -ENOMEM;
host->slot.handler_priv = ctx;
host->slot.cd_irq = -EINVAL;
}
@ -98,36 +101,6 @@ int mmc_gpio_get_cd(struct mmc_host *host)
}
EXPORT_SYMBOL(mmc_gpio_get_cd);
/**
* mmc_gpio_request_ro - request a gpio for write-protection
* @host: mmc host
* @gpio: gpio number requested
*
* As devm_* managed functions are used in mmc_gpio_request_ro(), client
* drivers do not need to worry about freeing up memory.
*
* Returns zero on success, else an error.
*/
int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
int ret;
if (!gpio_is_valid(gpio))
return -EINVAL;
ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN,
ctx->ro_label);
if (ret < 0)
return ret;
ctx->override_ro_active_level = true;
ctx->ro_gpio = gpio_to_desc(gpio);
return 0;
}
EXPORT_SYMBOL(mmc_gpio_request_ro);
void mmc_gpiod_request_cd_irq(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
@ -196,50 +169,6 @@ void mmc_gpio_set_cd_isr(struct mmc_host *host,
}
EXPORT_SYMBOL(mmc_gpio_set_cd_isr);
/**
* mmc_gpio_request_cd - request a gpio for card-detection
* @host: mmc host
* @gpio: gpio number requested
* @debounce: debounce time in microseconds
*
* As devm_* managed functions are used in mmc_gpio_request_cd(), client
* drivers do not need to worry about freeing up memory.
*
* If GPIO debouncing is desired, set the debounce parameter to a non-zero
* value. The caller is responsible for ensuring that the GPIO driver associated
* with the GPIO supports debouncing, otherwise an error will be returned.
*
* Returns zero on success, else an error.
*/
int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
unsigned int debounce)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
int ret;
ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN,
ctx->cd_label);
if (ret < 0)
/*
* don't bother freeing memory. It might still get used by other
* slot functions, in any case it will be freed, when the device
* is destroyed.
*/
return ret;
if (debounce) {
ret = gpio_set_debounce(gpio, debounce);
if (ret < 0)
return ret;
}
ctx->override_cd_active_level = true;
ctx->cd_gpio = gpio_to_desc(gpio);
return 0;
}
EXPORT_SYMBOL(mmc_gpio_request_cd);
/**
* mmc_gpiod_request_cd - request a gpio descriptor for card-detection
* @host: mmc host
@ -250,8 +179,7 @@ EXPORT_SYMBOL(mmc_gpio_request_cd);
* @gpio_invert: will return whether the GPIO line is inverted or not, set
* to NULL to ignore
*
* Use this function in place of mmc_gpio_request_cd() to use the GPIO
* descriptor API. Note that it must be called prior to mmc_add_host()
* Note that this must be called prior to mmc_add_host()
* otherwise the caller must also call mmc_gpiod_request_cd_irq().
*
* Returns zero on success, else an error.
@ -302,9 +230,6 @@ EXPORT_SYMBOL(mmc_can_gpio_cd);
* @gpio_invert: will return whether the GPIO line is inverted or not,
* set to NULL to ignore
*
* Use this function in place of mmc_gpio_request_ro() to use the GPIO
* descriptor API.
*
* Returns zero on success, else an error.
*/
int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,

View File

@ -441,6 +441,13 @@ config MMC_WBSD
If unsure, say N.
config MMC_ALCOR
tristate "Alcor Micro/Alcor Link SD/MMC controller"
depends on MISC_ALCOR_PCI
help
Say Y here to include driver code to support SD/MMC card interface
of Alcor Micro PCI-E card reader
config MMC_AU1X
tristate "Alchemy AU1XX0 MMC Card Interface support"
depends on MIPS_ALCHEMY
@ -646,13 +653,14 @@ config MMC_SDHI_SYS_DMAC
config MMC_SDHI_INTERNAL_DMAC
tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering"
depends on ARM64 || ARCH_R8A77470 || COMPILE_TEST
depends on ARM64 || ARCH_R7S9210 || ARCH_R8A77470 || COMPILE_TEST
depends on MMC_SDHI
default MMC_SDHI if (ARM64 || ARCH_R8A77470)
default MMC_SDHI if (ARM64 || ARCH_R7S9210 || ARCH_R8A77470)
help
This provides DMA support for SDHI SD/SDIO controllers
using on-chip bus mastering. This supports the controllers
found in arm64 based SoCs.
found in arm64 based SoCs. This controller is also found in
some RZ family SoCs.
config MMC_UNIPHIER
tristate "UniPhier SD/eMMC Host Controller support"
@ -969,6 +977,8 @@ config MMC_SDHCI_XENON
config MMC_SDHCI_OMAP
tristate "TI SDHCI Controller Support"
depends on MMC_SDHCI_PLTFM && OF
select THERMAL
select TI_SOC_THERMAL
help
This selects the Secure Digital Host Controller Interface (SDHCI)
support present in TI's DRA7 SOCs. The controller supports
@ -977,3 +987,15 @@ config MMC_SDHCI_OMAP
If you have a controller with this interface, say Y or M here.
If unsure, say N.
config MMC_SDHCI_AM654
tristate "Support for the SDHCI Controller in TI's AM654 SOCs"
depends on MMC_SDHCI_PLTFM && OF
help
This selects the Secure Digital Host Controller Interface (SDHCI)
support present in TI's AM654 SOCs. The controller supports
SD/MMC/SDIO devices.
If you have a controller with this interface, say Y or M here.
If unsure, say N.

View File

@ -22,8 +22,10 @@ obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o
obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o
obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
obj-$(CONFIG_MMC_SDHCI_AM654) += sdhci_am654.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_ALCOR) += alcor.o
obj-$(CONFIG_MMC_MTK) += mtk-sd.o
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o

1162
drivers/mmc/host/alcor.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -446,18 +446,7 @@ static int atmci_req_show(struct seq_file *s, void *v)
return 0;
}
static int atmci_req_open(struct inode *inode, struct file *file)
{
return single_open(file, atmci_req_show, inode->i_private);
}
static const struct file_operations atmci_req_fops = {
.owner = THIS_MODULE,
.open = atmci_req_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(atmci_req);
static void atmci_show_status_reg(struct seq_file *s,
const char *regname, u32 value)
@ -583,18 +572,7 @@ static int atmci_regs_show(struct seq_file *s, void *v)
return ret;
}
static int atmci_regs_open(struct inode *inode, struct file *file)
{
return single_open(file, atmci_regs_show, inode->i_private);
}
static const struct file_operations atmci_regs_fops = {
.owner = THIS_MODULE,
.open = atmci_regs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(atmci_regs);
static void atmci_init_debugfs(struct atmel_mci_slot *slot)
{
@ -608,13 +586,14 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot)
return;
node = debugfs_create_file("regs", S_IRUSR, root, host,
&atmci_regs_fops);
&atmci_regs_fops);
if (IS_ERR(node))
return;
if (!node)
goto err;
node = debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
node = debugfs_create_file("req", S_IRUSR, root, slot,
&atmci_req_fops);
if (!node)
goto err;
@ -1954,13 +1933,14 @@ static void atmci_tasklet_func(unsigned long priv)
}
atmci_request_end(host, host->mrq);
state = STATE_IDLE;
goto unlock; /* atmci_request_end() sets host->state */
break;
}
} while (state != prev_state);
host->state = state;
unlock:
spin_unlock(&host->lock);
}

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* bcm2835 sdhost driver.
*
@ -25,18 +26,6 @@
* sdhci-bcm2708.c by Broadcom
* sdhci-bcm2835.c by Stephen Warren and Oleksandr Tymoshenko
* sdhci.c and sdhci-pci.c by Pierre Ossman
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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 <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
#include <linux/delay.h>
@ -286,6 +275,7 @@ static void bcm2835_reset(struct mmc_host *mmc)
if (host->dma_chan)
dmaengine_terminate_sync(host->dma_chan);
host->dma_chan = NULL;
bcm2835_reset_internal(host);
}
@ -463,7 +453,7 @@ static void bcm2835_transfer_pio(struct bcm2835_host *host)
static
void bcm2835_prepare_dma(struct bcm2835_host *host, struct mmc_data *data)
{
int len, dir_data, dir_slave;
int sg_len, dir_data, dir_slave;
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *dma_chan;
@ -509,23 +499,24 @@ void bcm2835_prepare_dma(struct bcm2835_host *host, struct mmc_data *data)
&host->dma_cfg_rx :
&host->dma_cfg_tx);
len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len,
dir_data);
sg_len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len,
dir_data);
if (!sg_len)
return;
if (len > 0) {
desc = dmaengine_prep_slave_sg(dma_chan, data->sg,
len, dir_slave,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK);
desc = dmaengine_prep_slave_sg(dma_chan, data->sg, sg_len, dir_slave,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
dma_unmap_sg(dma_chan->device->dev, data->sg, sg_len, dir_data);
return;
}
if (desc) {
desc->callback = bcm2835_dma_complete;
desc->callback_param = host;
host->dma_desc = desc;
host->dma_chan = dma_chan;
host->dma_dir = dir_data;
}
desc->callback = bcm2835_dma_complete;
desc->callback_param = host;
host->dma_desc = desc;
host->dma_chan = dma_chan;
host->dma_dir = dir_data;
}
static void bcm2835_start_dma(struct bcm2835_host *host)
@ -607,7 +598,7 @@ static void bcm2835_finish_request(struct bcm2835_host *host)
struct dma_chan *terminate_chan = NULL;
struct mmc_request *mrq;
cancel_delayed_work(&host->timeout_work);
cancel_delayed_work_sync(&host->timeout_work);
mrq = host->mrq;
@ -772,6 +763,8 @@ static void bcm2835_finish_command(struct bcm2835_host *host)
if (!(sdhsts & SDHSTS_CRC7_ERROR) ||
(host->cmd->opcode != MMC_SEND_OP_COND)) {
u32 edm, fsm;
if (sdhsts & SDHSTS_CMD_TIME_OUT) {
host->cmd->error = -ETIMEDOUT;
} else {
@ -780,6 +773,13 @@ static void bcm2835_finish_command(struct bcm2835_host *host)
bcm2835_dumpregs(host);
host->cmd->error = -EILSEQ;
}
edm = readl(host->ioaddr + SDEDM);
fsm = edm & SDEDM_FSM_MASK;
if (fsm == SDEDM_FSM_READWAIT ||
fsm == SDEDM_FSM_WRITESTART1)
/* Kick the FSM out of its wait */
writel(edm | SDEDM_FORCE_DATA_MODE,
host->ioaddr + SDEDM);
bcm2835_finish_request(host);
return;
}
@ -837,6 +837,8 @@ static void bcm2835_timeout(struct work_struct *work)
dev_err(dev, "timeout waiting for hardware interrupt.\n");
bcm2835_dumpregs(host);
bcm2835_reset(host->mmc);
if (host->data) {
host->data->error = -ETIMEDOUT;
bcm2835_finish_data(host);
@ -1052,10 +1054,12 @@ static void bcm2835_dma_complete_work(struct work_struct *work)
{
struct bcm2835_host *host =
container_of(work, struct bcm2835_host, dma_work);
struct mmc_data *data = host->data;
struct mmc_data *data;
mutex_lock(&host->mutex);
data = host->data;
if (host->dma_chan) {
dma_unmap_sg(host->dma_chan->device->dev,
data->sg, data->sg_len,
@ -1180,9 +1184,6 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq)
return;
}
if (host->use_dma && mrq->data && (mrq->data->blocks > PIO_THRESHOLD))
bcm2835_prepare_dma(host, mrq->data);
mutex_lock(&host->mutex);
WARN_ON(host->mrq);
@ -1206,6 +1207,9 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq)
return;
}
if (host->use_dma && mrq->data && (mrq->data->blocks > PIO_THRESHOLD))
bcm2835_prepare_dma(host, mrq->data);
host->use_sbc = !!mrq->sbc && host->mrq->data &&
(host->mrq->data->flags & MMC_DATA_READ);
if (host->use_sbc) {
@ -1445,6 +1449,9 @@ static int bcm2835_remove(struct platform_device *pdev)
cancel_work_sync(&host->dma_work);
cancel_delayed_work_sync(&host->timeout_work);
if (host->dma_chan_rxtx)
dma_release_channel(host->dma_chan_rxtx);
mmc_free_host(host->mmc);
platform_set_drvdata(pdev, NULL);

View File

@ -52,16 +52,7 @@ MODULE_DEVICE_TABLE(of, dw_mci_bluefield_match);
static int dw_mci_bluefield_probe(struct platform_device *pdev)
{
const struct dw_mci_drv_data *drv_data = NULL;
const struct of_device_id *match;
if (pdev->dev.of_node) {
match = of_match_node(dw_mci_bluefield_match,
pdev->dev.of_node);
drv_data = match->data;
}
return dw_mci_pltfm_register(pdev, drv_data);
return dw_mci_pltfm_register(pdev, &bluefield_drv_data);
}
static struct platform_driver dw_mci_bluefield_pltfm_driver = {

View File

@ -21,7 +21,7 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
@ -126,9 +126,23 @@ enum jz4740_mmc_state {
JZ4740_MMC_STATE_DONE,
};
struct jz4740_mmc_host_next {
int sg_len;
s32 cookie;
/*
* The MMC core allows to prepare a mmc_request while another mmc_request
* is in-flight. This is used via the pre_req/post_req hooks.
* This driver uses the pre_req/post_req hooks to map/unmap the mmc_request.
* Following what other drivers do (sdhci, dw_mmc) we use the following cookie
* flags to keep track of the mmc_request mapping state.
*
* COOKIE_UNMAPPED: the request is not mapped.
* COOKIE_PREMAPPED: the request was mapped in pre_req,
* and should be unmapped in post_req.
* COOKIE_MAPPED: the request was mapped in the irq handler,
* and should be unmapped before mmc_request_done is called..
*/
enum jz4780_cookie {
COOKIE_UNMAPPED = 0,
COOKIE_PREMAPPED,
COOKIE_MAPPED,
};
struct jz4740_mmc_host {
@ -136,6 +150,7 @@ struct jz4740_mmc_host {
struct platform_device *pdev;
struct jz4740_mmc_platform_data *pdata;
struct clk *clk;
struct gpio_desc *power;
enum jz4740_mmc_version version;
@ -162,9 +177,7 @@ struct jz4740_mmc_host {
/* DMA support */
struct dma_chan *dma_rx;
struct dma_chan *dma_tx;
struct jz4740_mmc_host_next next_data;
bool use_dma;
int sg_len;
/* The DMA trigger level is 8 words, that is to say, the DMA read
* trigger is when data words in MSC_RXFIFO is >= 8 and the DMA write
@ -226,9 +239,6 @@ static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host)
return PTR_ERR(host->dma_rx);
}
/* Initialize DMA pre request cookie */
host->next_data.cookie = 1;
return 0;
}
@ -245,60 +255,44 @@ static void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host,
enum dma_data_direction dir = mmc_get_dma_dir(data);
dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
data->host_cookie = COOKIE_UNMAPPED;
}
/* Prepares DMA data for current/next transfer, returns non-zero on failure */
/* Prepares DMA data for current or next transfer.
* A request can be in-flight when this is called.
*/
static int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host,
struct mmc_data *data,
struct jz4740_mmc_host_next *next,
struct dma_chan *chan)
int cookie)
{
struct jz4740_mmc_host_next *next_data = &host->next_data;
struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
enum dma_data_direction dir = mmc_get_dma_dir(data);
int sg_len;
int sg_count;
if (!next && data->host_cookie &&
data->host_cookie != host->next_data.cookie) {
dev_warn(mmc_dev(host->mmc),
"[%s] invalid cookie: data->host_cookie %d host->next_data.cookie %d\n",
__func__,
data->host_cookie,
host->next_data.cookie);
data->host_cookie = 0;
}
if (data->host_cookie == COOKIE_PREMAPPED)
return data->sg_count;
/* Check if next job is already prepared */
if (next || data->host_cookie != host->next_data.cookie) {
sg_len = dma_map_sg(chan->device->dev,
data->sg,
data->sg_len,
dir);
sg_count = dma_map_sg(chan->device->dev,
data->sg,
data->sg_len,
dir);
} else {
sg_len = next_data->sg_len;
next_data->sg_len = 0;
}
if (sg_len <= 0) {
if (sg_count <= 0) {
dev_err(mmc_dev(host->mmc),
"Failed to map scatterlist for DMA operation\n");
return -EINVAL;
}
if (next) {
next->sg_len = sg_len;
data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
} else
host->sg_len = sg_len;
data->sg_count = sg_count;
data->host_cookie = cookie;
return 0;
return data->sg_count;
}
static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host,
struct mmc_data *data)
{
int ret;
struct dma_chan *chan;
struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
struct dma_async_tx_descriptor *desc;
struct dma_slave_config conf = {
.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
@ -306,29 +300,26 @@ static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host,
.src_maxburst = JZ4740_MMC_FIFO_HALF_SIZE,
.dst_maxburst = JZ4740_MMC_FIFO_HALF_SIZE,
};
int sg_count;
if (data->flags & MMC_DATA_WRITE) {
conf.direction = DMA_MEM_TO_DEV;
conf.dst_addr = host->mem_res->start + JZ_REG_MMC_TXFIFO;
conf.slave_id = JZ4740_DMA_TYPE_MMC_TRANSMIT;
chan = host->dma_tx;
} else {
conf.direction = DMA_DEV_TO_MEM;
conf.src_addr = host->mem_res->start + JZ_REG_MMC_RXFIFO;
conf.slave_id = JZ4740_DMA_TYPE_MMC_RECEIVE;
chan = host->dma_rx;
}
ret = jz4740_mmc_prepare_dma_data(host, data, NULL, chan);
if (ret)
return ret;
sg_count = jz4740_mmc_prepare_dma_data(host, data, COOKIE_MAPPED);
if (sg_count < 0)
return sg_count;
dmaengine_slave_config(chan, &conf);
desc = dmaengine_prep_slave_sg(chan,
data->sg,
host->sg_len,
conf.direction,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
desc = dmaengine_prep_slave_sg(chan, data->sg, sg_count,
conf.direction,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
dev_err(mmc_dev(host->mmc),
"Failed to allocate DMA %s descriptor",
@ -342,7 +333,8 @@ static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host,
return 0;
dma_unmap:
jz4740_mmc_dma_unmap(host, data);
if (data->host_cookie == COOKIE_MAPPED)
jz4740_mmc_dma_unmap(host, data);
return -ENOMEM;
}
@ -351,16 +343,13 @@ static void jz4740_mmc_pre_request(struct mmc_host *mmc,
{
struct jz4740_mmc_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
struct jz4740_mmc_host_next *next_data = &host->next_data;
BUG_ON(data->host_cookie);
if (!host->use_dma)
return;
if (host->use_dma) {
struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
if (jz4740_mmc_prepare_dma_data(host, data, next_data, chan))
data->host_cookie = 0;
}
data->host_cookie = COOKIE_UNMAPPED;
if (jz4740_mmc_prepare_dma_data(host, data, COOKIE_PREMAPPED) < 0)
data->host_cookie = COOKIE_UNMAPPED;
}
static void jz4740_mmc_post_request(struct mmc_host *mmc,
@ -370,10 +359,8 @@ static void jz4740_mmc_post_request(struct mmc_host *mmc,
struct jz4740_mmc_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
if (host->use_dma && data->host_cookie) {
if (data && data->host_cookie != COOKIE_UNMAPPED)
jz4740_mmc_dma_unmap(host, data);
data->host_cookie = 0;
}
if (err) {
struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
@ -436,10 +423,14 @@ static void jz4740_mmc_reset(struct jz4740_mmc_host *host)
static void jz4740_mmc_request_done(struct jz4740_mmc_host *host)
{
struct mmc_request *req;
struct mmc_data *data;
req = host->req;
data = req->data;
host->req = NULL;
if (data && data->host_cookie == COOKIE_MAPPED)
jz4740_mmc_dma_unmap(host, data);
mmc_request_done(host->mmc, req);
}
@ -903,18 +894,16 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_UP:
jz4740_mmc_reset(host);
if (host->pdata && gpio_is_valid(host->pdata->gpio_power))
gpio_set_value(host->pdata->gpio_power,
!host->pdata->power_active_low);
if (host->power)
gpiod_set_value(host->power, 1);
host->cmdat |= JZ_MMC_CMDAT_INIT;
clk_prepare_enable(host->clk);
break;
case MMC_POWER_ON:
break;
default:
if (host->pdata && gpio_is_valid(host->pdata->gpio_power))
gpio_set_value(host->pdata->gpio_power,
host->pdata->power_active_low);
if (host->power)
gpiod_set_value(host->power, 0);
clk_disable_unprepare(host->clk);
break;
}
@ -947,30 +936,9 @@ static const struct mmc_host_ops jz4740_mmc_ops = {
.enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
};
static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
const char *name, bool output, int value)
{
int ret;
if (!gpio_is_valid(gpio))
return 0;
ret = gpio_request(gpio, name);
if (ret) {
dev_err(dev, "Failed to request %s gpio: %d\n", name, ret);
return ret;
}
if (output)
gpio_direction_output(gpio, value);
else
gpio_direction_input(gpio);
return 0;
}
static int jz4740_mmc_request_gpios(struct mmc_host *mmc,
struct platform_device *pdev)
static int jz4740_mmc_request_gpios(struct jz4740_mmc_host *host,
struct mmc_host *mmc,
struct platform_device *pdev)
{
struct jz4740_mmc_platform_data *pdata = dev_get_platdata(&pdev->dev);
int ret = 0;
@ -983,31 +951,21 @@ static int jz4740_mmc_request_gpios(struct mmc_host *mmc,
if (!pdata->read_only_active_low)
mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
if (gpio_is_valid(pdata->gpio_card_detect)) {
ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect, 0);
if (ret)
return ret;
}
/*
* Get optional card detect and write protect GPIOs,
* only back out on probe deferral.
*/
ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL);
if (ret == -EPROBE_DEFER)
return ret;
if (gpio_is_valid(pdata->gpio_read_only)) {
ret = mmc_gpio_request_ro(mmc, pdata->gpio_read_only);
if (ret)
return ret;
}
ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL);
if (ret == -EPROBE_DEFER)
return ret;
return jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power,
"MMC read only", true, pdata->power_active_low);
}
static void jz4740_mmc_free_gpios(struct platform_device *pdev)
{
struct jz4740_mmc_platform_data *pdata = dev_get_platdata(&pdev->dev);
if (!pdata)
return;
if (gpio_is_valid(pdata->gpio_power))
gpio_free(pdata->gpio_power);
host->power = devm_gpiod_get_optional(&pdev->dev, "power",
GPIOD_OUT_HIGH);
return PTR_ERR_OR_ZERO(host->power);
}
static const struct of_device_id jz4740_mmc_of_match[] = {
@ -1053,7 +1011,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
mmc->caps |= MMC_CAP_SDIO_IRQ;
if (!(pdata && pdata->data_1bit))
mmc->caps |= MMC_CAP_4_BIT_DATA;
ret = jz4740_mmc_request_gpios(mmc, pdev);
ret = jz4740_mmc_request_gpios(host, mmc, pdev);
if (ret)
goto err_free_host;
}
@ -1104,7 +1062,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
dev_name(&pdev->dev), host);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
goto err_free_gpios;
goto err_free_host;
}
jz4740_mmc_clock_disable(host);
@ -1135,8 +1093,6 @@ err_release_dma:
jz4740_mmc_release_dma_channels(host);
err_free_irq:
free_irq(host->irq, host);
err_free_gpios:
jz4740_mmc_free_gpios(pdev);
err_free_host:
mmc_free_host(mmc);
@ -1155,8 +1111,6 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
free_irq(host->irq, host);
jz4740_mmc_free_gpios(pdev);
if (host->use_dma)
jz4740_mmc_release_dma_channels(host);

View File

@ -21,11 +21,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
@ -66,6 +66,9 @@
#define SD_EMMC_DELAY 0x4
#define SD_EMMC_ADJUST 0x8
#define ADJUST_ADJ_DELAY_MASK GENMASK(21, 16)
#define ADJUST_DS_EN BIT(15)
#define ADJUST_ADJ_EN BIT(13)
#define SD_EMMC_DELAY1 0x4
#define SD_EMMC_DELAY2 0x8
@ -90,9 +93,11 @@
#define CFG_CLK_ALWAYS_ON BIT(18)
#define CFG_CHK_DS BIT(20)
#define CFG_AUTO_CLK BIT(23)
#define CFG_ERR_ABORT BIT(27)
#define SD_EMMC_STATUS 0x48
#define STATUS_BUSY BIT(31)
#define STATUS_DESC_BUSY BIT(30)
#define STATUS_DATI GENMASK(23, 16)
#define SD_EMMC_IRQ_EN 0x4c
@ -141,6 +146,7 @@ struct meson_mmc_data {
unsigned int tx_delay_mask;
unsigned int rx_delay_mask;
unsigned int always_on;
unsigned int adjust;
};
struct sd_emmc_desc {
@ -156,7 +162,6 @@ struct meson_host {
struct mmc_host *mmc;
struct mmc_command *cmd;
spinlock_t lock;
void __iomem *regs;
struct clk *core_clk;
struct clk *mmc_clk;
@ -633,14 +638,8 @@ static int meson_mmc_clk_init(struct meson_host *host)
if (ret)
return ret;
/*
* Set phases : These values are mostly the datasheet recommended ones
* except for the Tx phase. Datasheet recommends 180 but some cards
* fail at initialisation with it. 270 works just fine, it fixes these
* initialisation issues and enable eMMC DDR52 mode.
*/
clk_set_phase(host->mmc_clk, 180);
clk_set_phase(host->tx_clk, 270);
clk_set_phase(host->tx_clk, 0);
clk_set_phase(host->rx_clk, 0);
return clk_prepare_enable(host->mmc_clk);
@ -928,6 +927,7 @@ static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
cmd_cfg |= FIELD_PREP(CMD_CFG_CMD_INDEX_MASK, cmd->opcode);
cmd_cfg |= CMD_CFG_OWNER; /* owned by CPU */
cmd_cfg |= CMD_CFG_ERROR; /* stop in case of error */
meson_mmc_set_response_bits(cmd, &cmd_cfg);
@ -1022,29 +1022,34 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
u32 irq_en, status, raw_status;
irqreturn_t ret = IRQ_NONE;
if (WARN_ON(!host) || WARN_ON(!host->cmd))
return IRQ_NONE;
spin_lock(&host->lock);
cmd = host->cmd;
data = cmd->data;
irq_en = readl(host->regs + SD_EMMC_IRQ_EN);
raw_status = readl(host->regs + SD_EMMC_STATUS);
status = raw_status & irq_en;
if (!status) {
dev_dbg(host->dev,
"Unexpected IRQ! irq_en 0x%08x - status 0x%08x\n",
irq_en, raw_status);
return IRQ_NONE;
}
if (WARN_ON(!host) || WARN_ON(!host->cmd))
return IRQ_NONE;
cmd = host->cmd;
data = cmd->data;
cmd->error = 0;
if (status & IRQ_CRC_ERR) {
dev_dbg(host->dev, "CRC Error - status 0x%08x\n", status);
cmd->error = -EILSEQ;
ret = IRQ_HANDLED;
ret = IRQ_WAKE_THREAD;
goto out;
}
if (status & IRQ_TIMEOUTS) {
dev_dbg(host->dev, "Timeout - status 0x%08x\n", status);
cmd->error = -ETIMEDOUT;
ret = IRQ_HANDLED;
ret = IRQ_WAKE_THREAD;
goto out;
}
@ -1069,17 +1074,48 @@ out:
/* ack all enabled interrupts */
writel(irq_en, host->regs + SD_EMMC_STATUS);
if (cmd->error) {
/* Stop desc in case of errors */
u32 start = readl(host->regs + SD_EMMC_START);
start &= ~START_DESC_BUSY;
writel(start, host->regs + SD_EMMC_START);
}
if (ret == IRQ_HANDLED)
meson_mmc_request_done(host->mmc, cmd->mrq);
else if (ret == IRQ_NONE)
dev_warn(host->dev,
"Unexpected IRQ! status=0x%08x, irq_en=0x%08x\n",
raw_status, irq_en);
spin_unlock(&host->lock);
return ret;
}
static int meson_mmc_wait_desc_stop(struct meson_host *host)
{
int loop;
u32 status;
/*
* It may sometimes take a while for it to actually halt. Here, we
* are giving it 5ms to comply
*
* If we don't confirm the descriptor is stopped, it might raise new
* IRQs after we have called mmc_request_done() which is bad.
*/
for (loop = 50; loop; loop--) {
status = readl(host->regs + SD_EMMC_STATUS);
if (status & (STATUS_BUSY | STATUS_DESC_BUSY))
udelay(100);
else
break;
}
if (status & (STATUS_BUSY | STATUS_DESC_BUSY)) {
dev_err(host->dev, "Timed out waiting for host to stop\n");
return -ETIMEDOUT;
}
return 0;
}
static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
{
struct meson_host *host = dev_id;
@ -1090,6 +1126,13 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
if (WARN_ON(!cmd))
return IRQ_NONE;
if (cmd->error) {
meson_mmc_wait_desc_stop(host);
meson_mmc_request_done(host->mmc, cmd->mrq);
return IRQ_HANDLED;
}
data = cmd->data;
if (meson_mmc_bounce_buf_read(data)) {
xfer_bytes = data->blksz * data->blocks;
@ -1123,14 +1166,21 @@ static int meson_mmc_get_cd(struct mmc_host *mmc)
static void meson_mmc_cfg_init(struct meson_host *host)
{
u32 cfg = 0;
u32 cfg = 0, adj = 0;
cfg |= FIELD_PREP(CFG_RESP_TIMEOUT_MASK,
ilog2(SD_EMMC_CFG_RESP_TIMEOUT));
cfg |= FIELD_PREP(CFG_RC_CC_MASK, ilog2(SD_EMMC_CFG_CMD_GAP));
cfg |= FIELD_PREP(CFG_BLK_LEN_MASK, ilog2(SD_EMMC_CFG_BLK_SIZE));
/* abort chain on R/W errors */
cfg |= CFG_ERR_ABORT;
writel(cfg, host->regs + SD_EMMC_CFG);
/* enable signal resampling w/o delay */
adj = ADJUST_ADJ_EN;
writel(adj, host->regs + host->data->adjust);
}
static int meson_mmc_card_busy(struct mmc_host *mmc)
@ -1191,8 +1241,6 @@ static int meson_mmc_probe(struct platform_device *pdev)
host->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, host);
spin_lock_init(&host->lock);
/* Get regulators and the supported OCR mask */
host->vqmmc_enabled = false;
ret = mmc_regulator_get_supply(mmc);
@ -1356,12 +1404,14 @@ static const struct meson_mmc_data meson_gx_data = {
.tx_delay_mask = CLK_V2_TX_DELAY_MASK,
.rx_delay_mask = CLK_V2_RX_DELAY_MASK,
.always_on = CLK_V2_ALWAYS_ON,
.adjust = SD_EMMC_ADJUST,
};
static const struct meson_mmc_data meson_axg_data = {
.tx_delay_mask = CLK_V3_TX_DELAY_MASK,
.rx_delay_mask = CLK_V3_RX_DELAY_MASK,
.always_on = CLK_V3_ALWAYS_ON,
.adjust = SD_EMMC_V3_ADJUST,
};
static const struct of_device_id meson_mmc_of_match[] = {

View File

@ -596,6 +596,9 @@ static int meson_mx_mmc_register_clks(struct meson_mx_mmc_host *host)
init.name = devm_kasprintf(host->controller_dev, GFP_KERNEL,
"%s#fixed_factor",
dev_name(host->controller_dev));
if (!init.name)
return -ENOMEM;
init.ops = &clk_fixed_factor_ops;
init.flags = 0;
init.parent_names = &clk_fixed_factor_parent;
@ -612,6 +615,9 @@ static int meson_mx_mmc_register_clks(struct meson_mx_mmc_host *host)
clk_div_parent = __clk_get_name(host->fixed_factor_clk);
init.name = devm_kasprintf(host->controller_dev, GFP_KERNEL,
"%s#div", dev_name(host->controller_dev));
if (!init.name)
return -ENOMEM;
init.ops = &clk_divider_ops;
init.flags = CLK_SET_RATE_PARENT;
init.parent_names = &clk_div_parent;

View File

@ -1434,13 +1434,16 @@ static int mmc_spi_probe(struct spi_device *spi)
if (status != 0)
goto fail_add_host;
if (host->pdata && host->pdata->flags & MMC_SPI_USE_CD_GPIO) {
status = mmc_gpio_request_cd(mmc, host->pdata->cd_gpio,
host->pdata->cd_debounce);
if (status != 0)
goto fail_add_host;
/* The platform has a CD GPIO signal that may support
/*
* Index 0 is card detect
* Old boardfiles were specifying 1 ms as debounce
*/
status = mmc_gpiod_request_cd(mmc, NULL, 0, false, 1, NULL);
if (status == -EPROBE_DEFER)
goto fail_add_host;
if (!status) {
/*
* The platform has a CD GPIO signal that may support
* interrupts, so let mmc_gpiod_request_cd_irq() decide
* if polling is needed or not.
*/
@ -1448,12 +1451,12 @@ static int mmc_spi_probe(struct spi_device *spi)
mmc_gpiod_request_cd_irq(mmc);
}
if (host->pdata && host->pdata->flags & MMC_SPI_USE_RO_GPIO) {
/* Index 1 is write protect/read only */
status = mmc_gpiod_request_ro(mmc, NULL, 1, false, 0, NULL);
if (status == -EPROBE_DEFER)
goto fail_add_host;
if (!status)
has_ro = true;
status = mmc_gpio_request_ro(mmc, host->pdata->ro_gpio);
if (status != 0)
goto fail_add_host;
}
dev_info(&spi->dev, "SD/MMC host %s%s%s%s%s\n",
dev_name(&mmc->class_dev),

View File

@ -21,6 +21,7 @@
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/log2.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/pm.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
@ -274,6 +275,7 @@ static struct variant_data variant_stm32_sdmmc = {
.cmdreg_lrsp_crc = MCI_CPSM_STM32_LRSP_CRC,
.cmdreg_srsp_crc = MCI_CPSM_STM32_SRSP_CRC,
.cmdreg_srsp = MCI_CPSM_STM32_SRSP,
.cmdreg_stop = MCI_CPSM_STM32_CMDSTOP,
.data_cmd_enable = MCI_CPSM_STM32_CMDTRANS,
.irq_pio_mask = MCI_IRQ_PIO_STM32_MASK,
.datactrl_first = true,
@ -1100,6 +1102,10 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
mmci_reg_delay(host);
}
if (host->variant->cmdreg_stop &&
cmd->opcode == MMC_STOP_TRANSMISSION)
c |= host->variant->cmdreg_stop;
c |= cmd->opcode | host->variant->cmdreg_cpsm_enable;
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136)
@ -1190,11 +1196,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
/* The error clause is handled above, success! */
data->bytes_xfered = data->blksz * data->blocks;
if (!data->stop || host->mrq->sbc) {
if (!data->stop || (host->mrq->sbc && !data->error))
mmci_request_end(host, data->mrq);
} else {
else
mmci_start_command(host, data->stop, 0);
}
}
}

View File

@ -264,6 +264,7 @@ struct mmci_host;
* @cmdreg_lrsp_crc: enable value for long response with crc
* @cmdreg_srsp_crc: enable value for short response with crc
* @cmdreg_srsp: enable value for short response without crc
* @cmdreg_stop: enable value for stop and abort transmission
* @datalength_bits: number of bits in the MMCIDATALENGTH register
* @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
* is asserted (likewise for RX)
@ -316,6 +317,7 @@ struct variant_data {
unsigned int cmdreg_lrsp_crc;
unsigned int cmdreg_srsp_crc;
unsigned int cmdreg_srsp;
unsigned int cmdreg_stop;
unsigned int datalength_bits;
unsigned int fifosize;
unsigned int fifohalfsize;

View File

@ -1114,6 +1114,7 @@ static void msdc_start_command(struct msdc_host *host,
struct mmc_request *mrq, struct mmc_command *cmd)
{
u32 rawcmd;
unsigned long flags;
WARN_ON(host->cmd);
host->cmd = cmd;
@ -1131,7 +1132,10 @@ static void msdc_start_command(struct msdc_host *host,
cmd->error = 0;
rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd);
spin_lock_irqsave(&host->lock, flags);
sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask);
spin_unlock_irqrestore(&host->lock, flags);
writel(cmd->arg, host->base + SDC_ARG);
writel(rawcmd, host->base + SDC_CMD);
}
@ -1351,6 +1355,31 @@ static void msdc_request_timeout(struct work_struct *work)
}
}
static void __msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
{
unsigned long flags;
struct msdc_host *host = mmc_priv(mmc);
spin_lock_irqsave(&host->lock, flags);
if (enb)
sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
else
sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
spin_unlock_irqrestore(&host->lock, flags);
}
static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
{
struct msdc_host *host = mmc_priv(mmc);
__msdc_enable_sdio_irq(mmc, enb);
if (enb)
pm_runtime_get_noresume(host->dev);
else
pm_runtime_put_noidle(host->dev);
}
static irqreturn_t msdc_irq(int irq, void *dev_id)
{
struct msdc_host *host = (struct msdc_host *) dev_id;
@ -1373,7 +1402,12 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
data = host->data;
spin_unlock_irqrestore(&host->lock, flags);
if (!(events & event_mask))
if ((events & event_mask) & MSDC_INT_SDIOIRQ) {
__msdc_enable_sdio_irq(host->mmc, 0);
sdio_signal_irq(host->mmc);
}
if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ)))
break;
if (!mrq) {
@ -1493,8 +1527,11 @@ static void msdc_init_hw(struct msdc_host *host)
*/
sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO);
/* disable detect SDIO device interrupt function */
sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
/* Config SDIO device detect interrupt function */
if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
else
sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
/* Configure to default data timeout */
sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3);
@ -2013,6 +2050,11 @@ static void msdc_hw_reset(struct mmc_host *mmc)
sdr_clr_bits(host->base + EMMC_IOCON, 1);
}
static void msdc_ack_sdio_irq(struct mmc_host *mmc)
{
__msdc_enable_sdio_irq(mmc, 1);
}
static const struct mmc_host_ops mt_msdc_ops = {
.post_req = msdc_post_req,
.pre_req = msdc_pre_req,
@ -2020,6 +2062,8 @@ static const struct mmc_host_ops mt_msdc_ops = {
.set_ios = msdc_ops_set_ios,
.get_ro = mmc_gpio_get_ro,
.get_cd = mmc_gpio_get_cd,
.enable_sdio_irq = msdc_enable_sdio_irq,
.ack_sdio_irq = msdc_ack_sdio_irq,
.start_signal_voltage_switch = msdc_ops_switch_volt,
.card_busy = msdc_card_busy,
.execute_tuning = msdc_execute_tuning,
@ -2147,6 +2191,9 @@ static int msdc_drv_probe(struct platform_device *pdev)
else
mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 4095);
if (mmc->caps & MMC_CAP_SDIO_IRQ)
mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
/* MMC core transfer sizes tunable parameters */
mmc->max_segs = MAX_BD_NUM;

View File

@ -16,9 +16,7 @@
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/spi/spi.h>
#include <linux/spi/mmc_spi.h>
@ -32,15 +30,7 @@
MODULE_LICENSE("GPL");
enum {
CD_GPIO = 0,
WP_GPIO,
NUM_GPIOS,
};
struct of_mmc_spi {
int gpios[NUM_GPIOS];
bool alow_gpios[NUM_GPIOS];
int detect_irq;
struct mmc_spi_platform_data pdata;
};
@ -102,30 +92,6 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi)
oms->pdata.ocr_mask |= mask;
}
for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) {
enum of_gpio_flags gpio_flags;
oms->gpios[i] = of_get_gpio_flags(np, i, &gpio_flags);
if (!gpio_is_valid(oms->gpios[i]))
continue;
if (gpio_flags & OF_GPIO_ACTIVE_LOW)
oms->alow_gpios[i] = true;
}
if (gpio_is_valid(oms->gpios[CD_GPIO])) {
oms->pdata.cd_gpio = oms->gpios[CD_GPIO];
oms->pdata.flags |= MMC_SPI_USE_CD_GPIO;
if (!oms->alow_gpios[CD_GPIO])
oms->pdata.caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
}
if (gpio_is_valid(oms->gpios[WP_GPIO])) {
oms->pdata.ro_gpio = oms->gpios[WP_GPIO];
oms->pdata.flags |= MMC_SPI_USE_RO_GPIO;
if (!oms->alow_gpios[WP_GPIO])
oms->pdata.caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
}
oms->detect_irq = irq_of_parse_and_map(np, 0);
if (oms->detect_irq != 0) {
oms->pdata.init = of_mmc_spi_init;

View File

@ -1652,7 +1652,7 @@ static struct mmc_host_ops omap_hsmmc_ops = {
#ifdef CONFIG_DEBUG_FS
static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
static int mmc_regs_show(struct seq_file *s, void *data)
{
struct mmc_host *mmc = s->private;
struct omap_hsmmc_host *host = mmc_priv(mmc);
@ -1691,17 +1691,7 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
return 0;
}
static int omap_hsmmc_regs_open(struct inode *inode, struct file *file)
{
return single_open(file, omap_hsmmc_regs_show, inode->i_private);
}
static const struct file_operations mmc_regs_fops = {
.open = omap_hsmmc_regs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(mmc_regs);
static void omap_hsmmc_debugfs(struct mmc_host *mmc)
{

View File

@ -30,10 +30,9 @@
#include <linux/mmc/slot-gpio.h>
#include <linux/io.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/gfp.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <asm/sizes.h>
@ -63,6 +62,8 @@ struct pxamci_host {
unsigned int imask;
unsigned int power_mode;
unsigned long detect_delay_ms;
bool use_ro_gpio;
struct gpio_desc *power;
struct pxamci_platform_data *pdata;
struct mmc_request *mrq;
@ -101,16 +102,13 @@ static inline int pxamci_set_power(struct pxamci_host *host,
{
struct mmc_host *mmc = host->mmc;
struct regulator *supply = mmc->supply.vmmc;
int on;
if (!IS_ERR(supply))
return mmc_regulator_set_ocr(mmc, supply, vdd);
if (host->pdata &&
gpio_is_valid(host->pdata->gpio_power)) {
on = ((1 << vdd) & host->pdata->ocr_mask);
gpio_set_value(host->pdata->gpio_power,
!!on ^ host->pdata->gpio_power_invert);
if (host->power) {
bool on = !!((1 << vdd) & host->pdata->ocr_mask);
gpiod_set_value(host->power, on);
}
if (host->pdata && host->pdata->setpower)
@ -432,7 +430,7 @@ static int pxamci_get_ro(struct mmc_host *mmc)
{
struct pxamci_host *host = mmc_priv(mmc);
if (host->pdata && gpio_is_valid(host->pdata->gpio_card_ro))
if (host->use_ro_gpio)
return mmc_gpio_get_ro(mmc);
if (host->pdata && host->pdata->get_ro)
return !!host->pdata->get_ro(mmc_dev(mmc));
@ -730,52 +728,38 @@ static int pxamci_probe(struct platform_device *pdev)
}
if (host->pdata) {
int gpio_cd = host->pdata->gpio_card_detect;
int gpio_ro = host->pdata->gpio_card_ro;
int gpio_power = host->pdata->gpio_power;
host->detect_delay_ms = host->pdata->detect_delay_ms;
if (gpio_is_valid(gpio_power)) {
ret = devm_gpio_request(dev, gpio_power,
"mmc card power");
if (ret) {
dev_err(dev,
"Failed requesting gpio_power %d\n",
gpio_power);
goto out;
}
gpio_direction_output(gpio_power,
host->pdata->gpio_power_invert);
}
if (gpio_is_valid(gpio_ro)) {
ret = mmc_gpio_request_ro(mmc, gpio_ro);
if (ret) {
dev_err(dev,
"Failed requesting gpio_ro %d\n",
gpio_ro);
goto out;
} else {
mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
0 : MMC_CAP2_RO_ACTIVE_HIGH;
}
}
if (gpio_is_valid(gpio_cd))
ret = mmc_gpio_request_cd(mmc, gpio_cd, 0);
if (ret) {
dev_err(dev, "Failed requesting gpio_cd %d\n",
gpio_cd);
host->power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
if (IS_ERR(host->power)) {
dev_err(dev, "Failed requesting gpio_power\n");
goto out;
}
/* FIXME: should we pass detection delay to debounce? */
ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL);
if (ret && ret != -ENOENT) {
dev_err(dev, "Failed requesting gpio_cd\n");
goto out;
}
ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL);
if (ret && ret != -ENOENT) {
dev_err(dev, "Failed requesting gpio_ro\n");
goto out;
}
if (!ret) {
host->use_ro_gpio = true;
mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
0 : MMC_CAP2_RO_ACTIVE_HIGH;
}
if (host->pdata->init)
host->pdata->init(dev, pxamci_detect_irq, mmc);
if (gpio_is_valid(gpio_power) && host->pdata->setpower)
if (host->power && host->pdata->setpower)
dev_warn(dev, "gpio_power and setpower() both defined\n");
if (gpio_is_valid(gpio_ro) && host->pdata->get_ro)
if (host->use_ro_gpio && host->pdata->get_ro)
dev_warn(dev, "gpio_ro and get_ro() both defined\n");
}

View File

@ -32,6 +32,7 @@
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinctrl-state.h>
#include <linux/regulator/consumer.h>
#include <linux/sys_soc.h>
#include "renesas_sdhi.h"
#include "tmio_mmc.h"
@ -45,6 +46,11 @@
#define SDHI_VER_GEN3_SD 0xcc10
#define SDHI_VER_GEN3_SDMMC 0xcd10
struct renesas_sdhi_quirks {
bool hs400_disabled;
bool hs400_4taps;
};
static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
{
u32 val;
@ -163,15 +169,6 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
if (new_clock == 0)
goto out;
/*
* Both HS400 and HS200/SD104 set 200MHz, but some devices need to
* set 400MHz to distinguish the CPG settings in HS400.
*/
if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 &&
host->pdata->flags & TMIO_MMC_HAVE_4TAP_HS400 &&
new_clock == 200000000)
new_clock = 400000000;
clock = renesas_sdhi_clk_update(host, new_clock) / 512;
for (clk = 0x80000080; new_clock >= (clock << 1); clk >>= 1)
@ -532,6 +529,10 @@ static void renesas_sdhi_hw_reset(struct tmio_mmc_host *host)
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK,
TMIO_MASK_INIT_RCAR2);
}
static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host, u32 bit)
@ -602,11 +603,31 @@ static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
renesas_sdhi_sdbuf_width(host, enable ? width : 16);
}
static const struct renesas_sdhi_quirks sdhi_quirks_h3_m3w_es1 = {
.hs400_disabled = true,
.hs400_4taps = true,
};
static const struct renesas_sdhi_quirks sdhi_quirks_h3_es2 = {
.hs400_disabled = false,
.hs400_4taps = true,
};
static const struct soc_device_attribute sdhi_quirks_match[] = {
{ .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_h3_m3w_es1 },
{ .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_h3_es2 },
{ .soc_id = "r8a7796", .revision = "ES1.0", .data = &sdhi_quirks_h3_m3w_es1 },
{ .soc_id = "r8a7796", .revision = "ES1.1", .data = &sdhi_quirks_h3_m3w_es1 },
{ /* Sentinel. */ },
};
int renesas_sdhi_probe(struct platform_device *pdev,
const struct tmio_mmc_dma_ops *dma_ops)
{
struct tmio_mmc_data *mmd = pdev->dev.platform_data;
const struct renesas_sdhi_quirks *quirks = NULL;
const struct renesas_sdhi_of_data *of_data;
const struct soc_device_attribute *attr;
struct tmio_mmc_data *mmc_data;
struct tmio_mmc_dma *dma_priv;
struct tmio_mmc_host *host;
@ -616,6 +637,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
of_data = of_device_get_match_data(&pdev->dev);
attr = soc_device_match(sdhi_quirks_match);
if (attr)
quirks = attr->data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
@ -681,6 +706,12 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->multi_io_quirk = renesas_sdhi_multi_io_quirk;
host->dma_ops = dma_ops;
if (quirks && quirks->hs400_disabled)
host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES);
if (quirks && quirks->hs400_4taps)
mmc_data->flags |= TMIO_MMC_HAVE_4TAP_HS400;
/* For some SoC, we disable internal WP. GPIO may override this */
if (mmc_can_gpio_ro(host->mmc))
mmc_data->capabilities2 &= ~MMC_CAP2_NO_WRITE_PROTECT;
@ -691,6 +722,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->ops.card_busy = renesas_sdhi_card_busy;
host->ops.start_signal_voltage_switch =
renesas_sdhi_start_signal_voltage_switch;
host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27;
}
/* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */

View File

@ -34,7 +34,7 @@
#define DTRAN_MODE_CH_NUM_CH0 0 /* "downstream" = for write commands */
#define DTRAN_MODE_CH_NUM_CH1 BIT(16) /* "upstream" = for read commands */
#define DTRAN_MODE_BUS_WIDTH (BIT(5) | BIT(4))
#define DTRAN_MODE_ADDR_MODE BIT(0) /* 1 = Increment address */
#define DTRAN_MODE_ADDR_MODE BIT(0) /* 1 = Increment address, 0 = Fixed */
/* DM_CM_DTRAN_CTRL */
#define DTRAN_CTRL_DM_START BIT(0)
@ -73,6 +73,9 @@ static unsigned long global_flags;
#define SDHI_INTERNAL_DMAC_ONE_RX_ONLY 0
#define SDHI_INTERNAL_DMAC_RX_IN_USE 1
/* RZ/A2 does not have the ADRR_MODE bit */
#define SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY 2
/* Definitions for sampling clocks */
static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
{
@ -81,15 +84,14 @@ static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
},
};
static const struct renesas_sdhi_of_data of_rcar_r8a7795_compatible = {
static const struct renesas_sdhi_of_data of_rza2_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2 |
TMIO_MMC_HAVE_4TAP_HS400,
TMIO_MMC_HAVE_CBSY,
.tmio_ocr_mask = MMC_VDD_32_33,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
MMC_CAP_CMD23,
.capabilities2 = MMC_CAP2_NO_WRITE_PROTECT,
.bus_shift = 2,
.scc_offset = 0x1000,
.scc_offset = 0 - 0x1000,
.taps = rcar_gen3_scc_taps,
.taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
/* DMAC can handle 0xffffffff blk count but only 1 segment */
@ -113,9 +115,10 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
};
static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, },
{ .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_r8a7795_compatible, },
{ .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_r8a7795_compatible, },
{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
{},
};
@ -172,7 +175,10 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
struct mmc_data *data)
{
struct scatterlist *sg = host->sg_ptr;
u32 dtran_mode = DTRAN_MODE_BUS_WIDTH | DTRAN_MODE_ADDR_MODE;
u32 dtran_mode = DTRAN_MODE_BUS_WIDTH;
if (!test_bit(SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY, &global_flags))
dtran_mode |= DTRAN_MODE_ADDR_MODE;
if (!dma_map_sg(&host->pdev->dev, sg, host->sg_len,
mmc_get_dma_dir(data)))
@ -292,18 +298,22 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
*/
static const struct soc_device_attribute soc_whitelist[] = {
/* specific ones */
{ .soc_id = "r7s9210",
.data = (void *)BIT(SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY) },
{ .soc_id = "r8a7795", .revision = "ES1.*",
.data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
{ .soc_id = "r8a7796", .revision = "ES1.0",
.data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
/* generic ones */
{ .soc_id = "r8a774a1" },
{ .soc_id = "r8a774c0" },
{ .soc_id = "r8a77470" },
{ .soc_id = "r8a7795" },
{ .soc_id = "r8a7796" },
{ .soc_id = "r8a77965" },
{ .soc_id = "r8a77970" },
{ .soc_id = "r8a77980" },
{ .soc_id = "r8a77990" },
{ .soc_id = "r8a77995" },
{ /* sentinel */ }
};

View File

@ -75,19 +75,6 @@ static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
},
};
static const struct renesas_sdhi_of_data of_rcar_r8a7795_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2 |
TMIO_MMC_HAVE_4TAP_HS400,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
MMC_CAP_CMD23,
.capabilities2 = MMC_CAP2_NO_WRITE_PROTECT,
.bus_shift = 2,
.scc_offset = 0x1000,
.taps = rcar_gen3_scc_taps,
.taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
};
static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
@ -114,8 +101,8 @@ static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = {
{ .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_r8a7795_compatible, },
{ .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_r8a7795_compatible, },
{ .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
{ .compatible = "renesas,rcar-gen1-sdhi", .data = &of_rcar_gen1_compatible, },
{ .compatible = "renesas,rcar-gen2-sdhi", .data = &of_rcar_gen2_compatible, },
{ .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
@ -493,8 +480,7 @@ static const struct soc_device_attribute gen3_soc_whitelist[] = {
static int renesas_sdhi_sys_dmac_probe(struct platform_device *pdev)
{
if ((of_device_get_match_data(&pdev->dev) == &of_rcar_gen3_compatible ||
of_device_get_match_data(&pdev->dev) == &of_rcar_r8a7795_compatible) &&
if (of_device_get_match_data(&pdev->dev) == &of_rcar_gen3_compatible &&
!soc_device_match(gen3_soc_whitelist))
return -ENODEV;

View File

@ -28,6 +28,7 @@
#include <linux/mmc/sd.h>
#include <linux/mmc/card.h>
#include <linux/scatterlist.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/rtsx_usb.h>
@ -1042,9 +1043,9 @@ static int sd_set_power_mode(struct rtsx_usb_sdmmc *host,
if (power_mode == MMC_POWER_OFF) {
err = sd_power_off(host);
pm_runtime_put(sdmmc_dev(host));
pm_runtime_put_noidle(sdmmc_dev(host));
} else {
pm_runtime_get_sync(sdmmc_dev(host));
pm_runtime_get_noresume(sdmmc_dev(host));
err = sd_power_on(host);
}
@ -1297,16 +1298,20 @@ static void rtsx_usb_update_led(struct work_struct *work)
container_of(work, struct rtsx_usb_sdmmc, led_work);
struct rtsx_ucr *ucr = host->ucr;
pm_runtime_get_sync(sdmmc_dev(host));
pm_runtime_get_noresume(sdmmc_dev(host));
mutex_lock(&ucr->dev_mutex);
if (host->power_mode == MMC_POWER_OFF)
goto out;
if (host->led.brightness == LED_OFF)
rtsx_usb_turn_off_led(ucr);
else
rtsx_usb_turn_on_led(ucr);
out:
mutex_unlock(&ucr->dev_mutex);
pm_runtime_put(sdmmc_dev(host));
pm_runtime_put_sync_suspend(sdmmc_dev(host));
}
#endif
@ -1320,7 +1325,7 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host)
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST |
MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
MMC_CAP_NEEDS_POLL | MMC_CAP_ERASE;
MMC_CAP_ERASE | MMC_CAP_SYNC_RUNTIME_PM;
mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE |
MMC_CAP2_NO_SDIO;
@ -1363,8 +1368,6 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
mutex_init(&host->host_mutex);
rtsx_usb_init_host(host);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
pm_runtime_enable(&pdev->dev);
#ifdef RTSX_USB_USE_LEDS_CLASS
@ -1419,7 +1422,6 @@ static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
mmc_free_host(mmc);
pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
platform_set_drvdata(pdev, NULL);
dev_dbg(&(pdev->dev),
@ -1428,6 +1430,31 @@ static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int rtsx_usb_sdmmc_runtime_suspend(struct device *dev)
{
struct rtsx_usb_sdmmc *host = dev_get_drvdata(dev);
host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
return 0;
}
static int rtsx_usb_sdmmc_runtime_resume(struct device *dev)
{
struct rtsx_usb_sdmmc *host = dev_get_drvdata(dev);
host->mmc->caps |= MMC_CAP_NEEDS_POLL;
if (sdmmc_get_cd(host->mmc) == 1)
mmc_detect_change(host->mmc, 0);
return 0;
}
#endif
static const struct dev_pm_ops rtsx_usb_sdmmc_dev_pm_ops = {
SET_RUNTIME_PM_OPS(rtsx_usb_sdmmc_runtime_suspend,
rtsx_usb_sdmmc_runtime_resume, NULL)
};
static const struct platform_device_id rtsx_usb_sdmmc_ids[] = {
{
.name = "rtsx_usb_sdmmc",
@ -1443,6 +1470,7 @@ static struct platform_driver rtsx_usb_sdmmc_driver = {
.id_table = rtsx_usb_sdmmc_ids,
.driver = {
.name = "rtsx_usb_sdmmc",
.pm = &rtsx_usb_sdmmc_dev_pm_ops,
},
};
module_platform_driver(rtsx_usb_sdmmc_driver);

View File

@ -26,7 +26,6 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/mmc/slot-gpio.h>
#include <plat/gpio-cfg.h>
@ -1406,18 +1405,7 @@ static int s3cmci_state_show(struct seq_file *seq, void *v)
return 0;
}
static int s3cmci_state_open(struct inode *inode, struct file *file)
{
return single_open(file, s3cmci_state_show, inode->i_private);
}
static const struct file_operations s3cmci_fops_state = {
.owner = THIS_MODULE,
.open = s3cmci_state_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(s3cmci_state);
#define DBG_REG(_r) { .addr = S3C2410_SDI##_r, .name = #_r }
@ -1459,18 +1447,7 @@ static int s3cmci_regs_show(struct seq_file *seq, void *v)
return 0;
}
static int s3cmci_regs_open(struct inode *inode, struct file *file)
{
return single_open(file, s3cmci_regs_show, inode->i_private);
}
static const struct file_operations s3cmci_fops_regs = {
.owner = THIS_MODULE,
.open = s3cmci_regs_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(s3cmci_regs);
static void s3cmci_debugfs_attach(struct s3cmci_host *host)
{
@ -1484,14 +1461,14 @@ static void s3cmci_debugfs_attach(struct s3cmci_host *host)
host->debug_state = debugfs_create_file("state", 0444,
host->debug_root, host,
&s3cmci_fops_state);
&s3cmci_state_fops);
if (IS_ERR(host->debug_state))
dev_err(dev, "failed to create debug state file\n");
host->debug_regs = debugfs_create_file("regs", 0444,
host->debug_root, host,
&s3cmci_fops_regs);
&s3cmci_regs_fops);
if (IS_ERR(host->debug_regs))
dev_err(dev, "failed to create debug regs file\n");
@ -1545,25 +1522,19 @@ static int s3cmci_probe_pdata(struct s3cmci_host *host)
if (pdata->wprotect_invert)
mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
if (pdata->detect_invert)
mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
if (gpio_is_valid(pdata->gpio_detect)) {
ret = mmc_gpio_request_cd(mmc, pdata->gpio_detect, 0);
if (ret) {
dev_err(&pdev->dev, "error requesting GPIO for CD %d\n",
ret);
return ret;
}
/* If we get -ENOENT we have no card detect GPIO line */
ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL);
if (ret != -ENOENT) {
dev_err(&pdev->dev, "error requesting GPIO for CD %d\n",
ret);
return ret;
}
if (gpio_is_valid(pdata->gpio_wprotect)) {
ret = mmc_gpio_request_ro(mmc, pdata->gpio_wprotect);
if (ret) {
dev_err(&pdev->dev, "error requesting GPIO for WP %d\n",
ret);
return ret;
}
ret = mmc_gpiod_request_ro(host->mmc, "wp", 0, false, 0, NULL);
if (ret != -ENOENT) {
dev_err(&pdev->dev, "error requesting GPIO for WP %d\n",
ret);
return ret;
}
return 0;

View File

@ -437,7 +437,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
MMC_CAP_CMD_DURING_TFR | MMC_CAP_WAIT_WHILE_BUSY,
.flags = SDHCI_ACPI_RUNTIME_PM,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
SDHCI_QUIRK_NO_LED,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_STOP_WITH_TC |
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
@ -448,6 +449,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_NO_LED |
SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
.caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD |
@ -462,7 +464,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
.flags = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL |
SDHCI_ACPI_RUNTIME_PM,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
SDHCI_QUIRK_NO_LED,
.quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
SDHCI_QUIRK2_STOP_WITH_TC,
.caps = MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_AGGRESSIVE_PM,

View File

@ -14,7 +14,7 @@
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/mmc/host.h>

View File

@ -12,7 +12,6 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mmc/host.h>
@ -21,7 +20,6 @@
#include <linux/mmc/slot-gpio.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_data/mmc-esdhc-imx.h>
#include <linux/pm_runtime.h>
@ -429,7 +427,7 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
val = readl(host->ioaddr + ESDHC_MIX_CTRL);
else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING)
/* the std tuning bits is in ACMD12_ERR for imx6sl */
val = readl(host->ioaddr + SDHCI_ACMD12_ERR);
val = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
}
if (val & ESDHC_MIX_CTRL_EXE_TUNE)
@ -494,7 +492,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
}
writel(new_val , host->ioaddr + ESDHC_MIX_CTRL);
} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
u32 v = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
if (val & SDHCI_CTRL_TUNED_CLK) {
v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
@ -512,7 +510,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
}
writel(v, host->ioaddr + SDHCI_ACMD12_ERR);
writel(v, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
writel(m, host->ioaddr + ESDHC_MIX_CTRL);
}
return;
@ -957,9 +955,9 @@ static void esdhc_reset_tuning(struct sdhci_host *host)
writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
} else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
ctrl = readl(host->ioaddr + SDHCI_ACMD12_ERR);
ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
writel(ctrl, host->ioaddr + SDHCI_ACMD12_ERR);
writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
}
}
}
@ -1139,8 +1137,12 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
if (of_get_property(np, "fsl,wp-controller", NULL))
boarddata->wp_type = ESDHC_WP_CONTROLLER;
boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
if (gpio_is_valid(boarddata->wp_gpio))
/*
* If we have this property, then activate WP check.
* Retrieveing and requesting the actual WP GPIO will happen
* in the call to mmc_of_parse().
*/
if (of_property_read_bool(np, "wp-gpios"))
boarddata->wp_type = ESDHC_WP_GPIO;
of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step);
@ -1198,7 +1200,7 @@ static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev,
host->mmc->parent->platform_data);
/* write_protect */
if (boarddata->wp_type == ESDHC_WP_GPIO) {
err = mmc_gpio_request_ro(host->mmc, boarddata->wp_gpio);
err = mmc_gpiod_request_ro(host->mmc, "wp", 0, false, 0, NULL);
if (err) {
dev_err(mmc_dev(host->mmc),
"failed to request write-protect gpio!\n");
@ -1210,7 +1212,7 @@ static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev,
/* card_detect */
switch (boarddata->cd_type) {
case ESDHC_CD_GPIO:
err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio, 0);
err = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0, NULL);
if (err) {
dev_err(mmc_dev(host->mmc),
"failed to request card-detect gpio!\n");
@ -1317,7 +1319,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
/* clear tuning bits in case ROM has set it already */
writel(0x0, host->ioaddr + ESDHC_MIX_CTRL);
writel(0x0, host->ioaddr + SDHCI_ACMD12_ERR);
writel(0x0, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
}

View File

@ -59,9 +59,33 @@
/* Tuning Block Control Register */
#define ESDHC_TBCTL 0x120
#define ESDHC_HS400_WNDW_ADJUST 0x00000040
#define ESDHC_HS400_MODE 0x00000010
#define ESDHC_TB_EN 0x00000004
#define ESDHC_TBPTR 0x128
/* SD Clock Control Register */
#define ESDHC_SDCLKCTL 0x144
#define ESDHC_LPBK_CLK_SEL 0x80000000
#define ESDHC_CMD_CLK_CTL 0x00008000
/* SD Timing Control Register */
#define ESDHC_SDTIMNGCTL 0x148
#define ESDHC_FLW_CTL_BG 0x00008000
/* DLL Config 0 Register */
#define ESDHC_DLLCFG0 0x160
#define ESDHC_DLL_ENABLE 0x80000000
#define ESDHC_DLL_FREQ_SEL 0x08000000
/* DLL Config 1 Register */
#define ESDHC_DLLCFG1 0x164
#define ESDHC_DLL_PD_PULSE_STRETCH_SEL 0x80000000
/* DLL Status 0 Register */
#define ESDHC_DLLSTAT0 0x170
#define ESDHC_DLL_STS_SLV_LOCK 0x08000000
/* Control Register for DMA transfer */
#define ESDHC_DMA_SYSCTL 0x40c
#define ESDHC_PERIPHERAL_CLK_SEL 0x00080000

View File

@ -232,6 +232,7 @@ struct sdhci_msm_variant_ops {
*/
struct sdhci_msm_variant_info {
bool mci_removed;
bool restore_dll_config;
const struct sdhci_msm_variant_ops *var_ops;
const struct sdhci_msm_offset *offset;
};
@ -256,8 +257,11 @@ struct sdhci_msm_host {
bool pwr_irq_flag;
u32 caps_0;
bool mci_removed;
bool restore_dll_config;
const struct sdhci_msm_variant_ops *var_ops;
const struct sdhci_msm_offset *offset;
bool use_cdr;
u32 transfer_mode;
};
static const struct sdhci_msm_offset *sdhci_priv_msm_offset(struct sdhci_host *host)
@ -1025,6 +1029,69 @@ out:
return ret;
}
static bool sdhci_msm_is_tuning_needed(struct sdhci_host *host)
{
struct mmc_ios *ios = &host->mmc->ios;
/*
* Tuning is required for SDR104, HS200 and HS400 cards and
* if clock frequency is greater than 100MHz in these modes.
*/
if (host->clock <= CORE_FREQ_100MHZ ||
!(ios->timing == MMC_TIMING_MMC_HS400 ||
ios->timing == MMC_TIMING_MMC_HS200 ||
ios->timing == MMC_TIMING_UHS_SDR104) ||
ios->enhanced_strobe)
return false;
return true;
}
static int sdhci_msm_restore_sdr_dll_config(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
int ret;
/*
* SDR DLL comes into picture only for timing modes which needs
* tuning.
*/
if (!sdhci_msm_is_tuning_needed(host))
return 0;
/* Reset the tuning block */
ret = msm_init_cm_dll(host);
if (ret)
return ret;
/* Restore the tuning block */
ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
return ret;
}
static void sdhci_msm_set_cdr(struct sdhci_host *host, bool enable)
{
const struct sdhci_msm_offset *msm_offset = sdhci_priv_msm_offset(host);
u32 config, oldconfig = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config);
config = oldconfig;
if (enable) {
config |= CORE_CDR_EN;
config &= ~CORE_CDR_EXT_EN;
} else {
config &= ~CORE_CDR_EN;
config |= CORE_CDR_EXT_EN;
}
if (config != oldconfig) {
writel_relaxed(config, host->ioaddr +
msm_offset->core_dll_config);
}
}
static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct sdhci_host *host = mmc_priv(mmc);
@ -1035,15 +1102,14 @@ static int sdhci_msm_execute_tuning(struct mmc_host *mmc, u32 opcode)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
/*
* Tuning is required for SDR104, HS200 and HS400 cards and
* if clock frequency is greater than 100MHz in these modes.
*/
if (host->clock <= CORE_FREQ_100MHZ ||
!(ios.timing == MMC_TIMING_MMC_HS400 ||
ios.timing == MMC_TIMING_MMC_HS200 ||
ios.timing == MMC_TIMING_UHS_SDR104))
if (!sdhci_msm_is_tuning_needed(host)) {
msm_host->use_cdr = false;
sdhci_msm_set_cdr(host, false);
return 0;
}
/* Clock-Data-Recovery used to dynamically adjust RX sampling point */
msm_host->use_cdr = true;
/*
* For HS400 tuning in HS200 timing requires:
@ -1069,7 +1135,6 @@ retry:
if (rc)
return rc;
msm_host->saved_tuning_phase = phase;
rc = mmc_send_tuning(mmc, opcode, NULL);
if (!rc) {
/* Tuning is successful at this tuning point */
@ -1094,6 +1159,7 @@ retry:
rc = msm_config_cm_dll_phase(host, phase);
if (rc)
return rc;
msm_host->saved_tuning_phase = phase;
dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
mmc_hostname(mmc), phase);
} else {
@ -1525,6 +1591,19 @@ static int __sdhci_msm_check_write(struct sdhci_host *host, u16 val, int reg)
case SDHCI_POWER_CONTROL:
req_type = !val ? REQ_BUS_OFF : REQ_BUS_ON;
break;
case SDHCI_TRANSFER_MODE:
msm_host->transfer_mode = val;
break;
case SDHCI_COMMAND:
if (!msm_host->use_cdr)
break;
if ((msm_host->transfer_mode & SDHCI_TRNS_READ) &&
SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK_HS200 &&
SDHCI_GET_CMD(val) != MMC_SEND_TUNING_BLOCK)
sdhci_msm_set_cdr(host, true);
else
sdhci_msm_set_cdr(host, false);
break;
}
if (req_type) {
@ -1616,7 +1695,6 @@ static const struct sdhci_msm_variant_ops v5_var_ops = {
};
static const struct sdhci_msm_variant_info sdhci_msm_mci_var = {
.mci_removed = false,
.var_ops = &mci_var_ops,
.offset = &sdhci_msm_mci_offset,
};
@ -1627,9 +1705,17 @@ static const struct sdhci_msm_variant_info sdhci_msm_v5_var = {
.offset = &sdhci_msm_v5_offset,
};
static const struct sdhci_msm_variant_info sdm845_sdhci_var = {
.mci_removed = true,
.restore_dll_config = true,
.var_ops = &v5_var_ops,
.offset = &sdhci_msm_v5_offset,
};
static const struct of_device_id sdhci_msm_dt_match[] = {
{.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var},
{.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var},
{.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var},
{},
};
@ -1689,6 +1775,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
var_info = of_device_get_match_data(&pdev->dev);
msm_host->mci_removed = var_info->mci_removed;
msm_host->restore_dll_config = var_info->restore_dll_config;
msm_host->var_ops = var_info->var_ops;
msm_host->offset = var_info->offset;
@ -1910,8 +1997,7 @@ static int sdhci_msm_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
static int sdhci_msm_runtime_suspend(struct device *dev)
static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@ -1923,16 +2009,26 @@ static int sdhci_msm_runtime_suspend(struct device *dev)
return 0;
}
static int sdhci_msm_runtime_resume(struct device *dev)
static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
int ret;
return clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
msm_host->bulk_clks);
if (ret)
return ret;
/*
* Whenever core-clock is gated dynamically, it's needed to
* restore the SDR DLL settings when the clock is ungated.
*/
if (msm_host->restore_dll_config && msm_host->clk_rate)
return sdhci_msm_restore_sdr_dll_config(host);
return 0;
}
#endif
static const struct dev_pm_ops sdhci_msm_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,

View File

@ -231,25 +231,6 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
}
}
static void sdhci_arasan_am654_set_clock(struct sdhci_host *host,
unsigned int clock)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
if (sdhci_arasan->is_phy_on) {
phy_power_off(sdhci_arasan->phy);
sdhci_arasan->is_phy_on = false;
}
sdhci_set_clock(host, clock);
if (clock > PHY_CLK_TOO_SLOW_HZ) {
phy_power_on(sdhci_arasan->phy);
sdhci_arasan->is_phy_on = true;
}
}
static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
struct mmc_ios *ios)
{
@ -335,29 +316,6 @@ static struct sdhci_arasan_of_data sdhci_arasan_data = {
.pdata = &sdhci_arasan_pdata,
};
static const struct sdhci_ops sdhci_arasan_am654_ops = {
.set_clock = sdhci_arasan_am654_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_arasan_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
static const struct sdhci_pltfm_data sdhci_arasan_am654_pdata = {
.ops = &sdhci_arasan_am654_ops,
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN |
SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
};
static const struct sdhci_arasan_of_data sdhci_arasan_am654_data = {
.pdata = &sdhci_arasan_am654_pdata,
};
static u32 sdhci_arasan_cqhci_irq(struct sdhci_host *host, u32 intmask)
{
int cmd_error = 0;
@ -520,10 +478,6 @@ static const struct of_device_id sdhci_arasan_of_match[] = {
.compatible = "rockchip,rk3399-sdhci-5.1",
.data = &sdhci_arasan_rk3399_data,
},
{
.compatible = "ti,am654-sdhci-5.1",
.data = &sdhci_arasan_am654_data,
},
/* Generic compatible below here */
{
.compatible = "arasan,sdhci-8.9a",

View File

@ -78,6 +78,8 @@ struct sdhci_esdhc {
u8 vendor_ver;
u8 spec_ver;
bool quirk_incorrect_hostver;
bool quirk_limited_clk_division;
bool quirk_unreliable_pulse_detection;
bool quirk_fixup_tuning;
unsigned int peripheral_clock;
const struct esdhc_clk_fixup *clk_fixup;
@ -528,8 +530,12 @@ static void esdhc_clock_enable(struct sdhci_host *host, bool enable)
/* Wait max 20 ms */
timeout = ktime_add_ms(ktime_get(), 20);
val = ESDHC_CLOCK_STABLE;
while (!(sdhci_readl(host, ESDHC_PRSSTAT) & val)) {
if (ktime_after(ktime_get(), timeout)) {
while (1) {
bool timedout = ktime_after(ktime_get(), timeout);
if (sdhci_readl(host, ESDHC_PRSSTAT) & val)
break;
if (timedout) {
pr_err("%s: Internal clock never stabilised.\n",
mmc_hostname(host->mmc));
break;
@ -544,6 +550,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
int pre_div = 1;
int div = 1;
int division;
ktime_t timeout;
long fixup = 0;
u32 temp;
@ -579,6 +586,26 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
while (host->max_clk / pre_div / div > clock && div < 16)
div++;
if (esdhc->quirk_limited_clk_division &&
clock == MMC_HS200_MAX_DTR &&
(host->mmc->ios.timing == MMC_TIMING_MMC_HS400 ||
host->flags & SDHCI_HS400_TUNING)) {
division = pre_div * div;
if (division <= 4) {
pre_div = 4;
div = 1;
} else if (division <= 8) {
pre_div = 4;
div = 2;
} else if (division <= 12) {
pre_div = 4;
div = 3;
} else {
pr_warn("%s: using unsupported clock division.\n",
mmc_hostname(host->mmc));
}
}
dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
clock, host->max_clk / pre_div / div);
host->mmc->actual_clock = host->max_clk / pre_div / div;
@ -592,10 +619,36 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
| (pre_div << ESDHC_PREDIV_SHIFT));
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 &&
clock == MMC_HS200_MAX_DTR) {
temp = sdhci_readl(host, ESDHC_TBCTL);
sdhci_writel(host, temp | ESDHC_HS400_MODE, ESDHC_TBCTL);
temp = sdhci_readl(host, ESDHC_SDCLKCTL);
sdhci_writel(host, temp | ESDHC_CMD_CLK_CTL, ESDHC_SDCLKCTL);
esdhc_clock_enable(host, true);
temp = sdhci_readl(host, ESDHC_DLLCFG0);
temp |= ESDHC_DLL_ENABLE;
if (host->mmc->actual_clock == MMC_HS200_MAX_DTR)
temp |= ESDHC_DLL_FREQ_SEL;
sdhci_writel(host, temp, ESDHC_DLLCFG0);
temp = sdhci_readl(host, ESDHC_TBCTL);
sdhci_writel(host, temp | ESDHC_HS400_WNDW_ADJUST, ESDHC_TBCTL);
esdhc_clock_enable(host, false);
temp = sdhci_readl(host, ESDHC_DMA_SYSCTL);
temp |= ESDHC_FLUSH_ASYNC_FIFO;
sdhci_writel(host, temp, ESDHC_DMA_SYSCTL);
}
/* Wait max 20 ms */
timeout = ktime_add_ms(ktime_get(), 20);
while (!(sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)) {
if (ktime_after(ktime_get(), timeout)) {
while (1) {
bool timedout = ktime_after(ktime_get(), timeout);
if (sdhci_readl(host, ESDHC_PRSSTAT) & ESDHC_CLOCK_STABLE)
break;
if (timedout) {
pr_err("%s: Internal clock never stabilised.\n",
mmc_hostname(host->mmc));
return;
@ -603,6 +656,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
udelay(10);
}
temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
temp |= ESDHC_CLOCK_SDCLKEN;
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
}
@ -631,6 +685,8 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
static void esdhc_reset(struct sdhci_host *host, u8 mask)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
u32 val;
sdhci_reset(host, mask);
@ -642,6 +698,12 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
val = sdhci_readl(host, ESDHC_TBCTL);
val &= ~ESDHC_TB_EN;
sdhci_writel(host, val, ESDHC_TBCTL);
if (esdhc->quirk_unreliable_pulse_detection) {
val = sdhci_readl(host, ESDHC_DLLCFG1);
val &= ~ESDHC_DLL_PD_PULSE_STRETCH_SEL;
sdhci_writel(host, val, ESDHC_DLLCFG1);
}
}
}
@ -728,25 +790,50 @@ static struct soc_device_attribute soc_fixup_tuning[] = {
{ },
};
static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
static void esdhc_tuning_block_enable(struct sdhci_host *host, bool enable)
{
struct sdhci_host *host = mmc_priv(mmc);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
u32 val;
/* Use tuning block for tuning procedure */
esdhc_clock_enable(host, false);
val = sdhci_readl(host, ESDHC_DMA_SYSCTL);
val |= ESDHC_FLUSH_ASYNC_FIFO;
sdhci_writel(host, val, ESDHC_DMA_SYSCTL);
val = sdhci_readl(host, ESDHC_TBCTL);
val |= ESDHC_TB_EN;
if (enable)
val |= ESDHC_TB_EN;
else
val &= ~ESDHC_TB_EN;
sdhci_writel(host, val, ESDHC_TBCTL);
esdhc_clock_enable(host, true);
sdhci_execute_tuning(mmc, opcode);
esdhc_clock_enable(host, true);
}
static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct sdhci_host *host = mmc_priv(mmc);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
bool hs400_tuning;
u32 val;
int ret;
if (esdhc->quirk_limited_clk_division &&
host->flags & SDHCI_HS400_TUNING)
esdhc_of_set_clock(host, host->clock);
esdhc_tuning_block_enable(host, true);
hs400_tuning = host->flags & SDHCI_HS400_TUNING;
ret = sdhci_execute_tuning(mmc, opcode);
if (hs400_tuning) {
val = sdhci_readl(host, ESDHC_SDTIMNGCTL);
val |= ESDHC_FLW_CTL_BG;
sdhci_writel(host, val, ESDHC_SDTIMNGCTL);
}
if (host->tuning_err == -EAGAIN && esdhc->quirk_fixup_tuning) {
/* program TBPTR[TB_WNDW_END_PTR] = 3*DIV_RATIO and
@ -765,7 +852,16 @@ static int esdhc_execute_tuning(struct mmc_host *mmc, u32 opcode)
sdhci_writel(host, val, ESDHC_TBCTL);
sdhci_execute_tuning(mmc, opcode);
}
return 0;
return ret;
}
static void esdhc_set_uhs_signaling(struct sdhci_host *host,
unsigned int timing)
{
if (timing == MMC_TIMING_MMC_HS400)
esdhc_tuning_block_enable(host, true);
else
sdhci_set_uhs_signaling(host, timing);
}
#ifdef CONFIG_PM_SLEEP
@ -814,7 +910,7 @@ static const struct sdhci_ops sdhci_esdhc_be_ops = {
.adma_workaround = esdhc_of_adma_workaround,
.set_bus_width = esdhc_pltfm_set_bus_width,
.reset = esdhc_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.set_uhs_signaling = esdhc_set_uhs_signaling,
};
static const struct sdhci_ops sdhci_esdhc_le_ops = {
@ -831,7 +927,7 @@ static const struct sdhci_ops sdhci_esdhc_le_ops = {
.adma_workaround = esdhc_of_adma_workaround,
.set_bus_width = esdhc_pltfm_set_bus_width,
.reset = esdhc_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.set_uhs_signaling = esdhc_set_uhs_signaling,
};
static const struct sdhci_pltfm_data sdhci_esdhc_be_pdata = {
@ -857,6 +953,16 @@ static struct soc_device_attribute soc_incorrect_hostver[] = {
{ },
};
static struct soc_device_attribute soc_fixup_sdhc_clkdivs[] = {
{ .family = "QorIQ LX2160A", .revision = "1.0", },
{ },
};
static struct soc_device_attribute soc_unreliable_pulse_detection[] = {
{ .family = "QorIQ LX2160A", .revision = "1.0", },
{ },
};
static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
{
const struct of_device_id *match;
@ -879,6 +985,16 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
else
esdhc->quirk_incorrect_hostver = false;
if (soc_device_match(soc_fixup_sdhc_clkdivs))
esdhc->quirk_limited_clk_division = true;
else
esdhc->quirk_limited_clk_division = false;
if (soc_device_match(soc_unreliable_pulse_detection))
esdhc->quirk_unreliable_pulse_detection = true;
else
esdhc->quirk_unreliable_pulse_detection = false;
match = of_match_node(sdhci_esdhc_of_match, pdev->dev.of_node);
if (match)
esdhc->clk_fixup = match->data;
@ -909,6 +1025,12 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
}
}
static int esdhc_hs400_prepare_ddr(struct mmc_host *mmc)
{
esdhc_tuning_block_enable(mmc_priv(mmc), false);
return 0;
}
static int sdhci_esdhc_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
@ -932,6 +1054,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
host->mmc_host_ops.start_signal_voltage_switch =
esdhc_signal_voltage_switch;
host->mmc_host_ops.execute_tuning = esdhc_execute_tuning;
host->mmc_host_ops.hs400_prepare_ddr = esdhc_hs400_prepare_ddr;
host->tuning_delay = 1;
esdhc_init(pdev, host);

View File

@ -27,6 +27,7 @@
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/sys_soc.h>
#include <linux/thermal.h>
#include "sdhci-pltfm.h"
@ -115,6 +116,7 @@ struct sdhci_omap_host {
struct pinctrl *pinctrl;
struct pinctrl_state **pinctrl_state;
bool is_tuning;
};
static void sdhci_omap_start_clock(struct sdhci_omap_host *omap_host);
@ -220,8 +222,12 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host,
/* wait 1ms */
timeout = ktime_add_ms(ktime_get(), SDHCI_OMAP_TIMEOUT);
while (!(sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL) & HCTL_SDBP)) {
if (WARN_ON(ktime_after(ktime_get(), timeout)))
while (1) {
bool timedout = ktime_after(ktime_get(), timeout);
if (sdhci_omap_readl(omap_host, SDHCI_OMAP_HCTL) & HCTL_SDBP)
break;
if (WARN_ON(timedout))
return;
usleep_range(5, 10);
}
@ -285,19 +291,19 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
struct sdhci_host *host = mmc_priv(mmc);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
struct thermal_zone_device *thermal_dev;
struct device *dev = omap_host->dev;
struct mmc_ios *ios = &mmc->ios;
u32 start_window = 0, max_window = 0;
bool single_point_failure = false;
bool dcrc_was_enabled = false;
u8 cur_match, prev_match = 0;
u32 length = 0, max_len = 0;
u32 phase_delay = 0;
int temperature;
int ret = 0;
u32 reg;
pltfm_host = sdhci_priv(host);
omap_host = sdhci_pltfm_priv(pltfm_host);
dev = omap_host->dev;
int i;
/* clock tuning is not needed for upto 52MHz */
if (ios->clock <= 52000000)
@ -307,6 +313,16 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
if (ios->timing == MMC_TIMING_UHS_SDR50 && !(reg & CAPA2_TSDR50))
return 0;
thermal_dev = thermal_zone_get_zone_by_name("cpu_thermal");
if (IS_ERR(thermal_dev)) {
dev_err(dev, "Unable to get thermal zone for tuning\n");
return PTR_ERR(thermal_dev);
}
ret = thermal_zone_get_temp(thermal_dev, &temperature);
if (ret)
return ret;
reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL);
reg |= DLL_SWT;
sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg);
@ -322,6 +338,13 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
dcrc_was_enabled = true;
}
omap_host->is_tuning = true;
/*
* Stage 1: Search for a maximum pass window ignoring any
* any single point failures. If the tuning value ends up
* near it, move away from it in stage 2 below
*/
while (phase_delay <= MAX_PHASE_DELAY) {
sdhci_omap_set_dll(omap_host, phase_delay);
@ -329,10 +352,15 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
if (cur_match) {
if (prev_match) {
length++;
} else if (single_point_failure) {
/* ignore single point failure */
length++;
} else {
start_window = phase_delay;
length = 1;
}
} else {
single_point_failure = prev_match;
}
if (length > max_len) {
@ -350,18 +378,84 @@ static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode)
goto tuning_error;
}
/*
* Assign tuning value as a ratio of maximum pass window based
* on temperature
*/
if (temperature < -20000)
phase_delay = min(max_window + 4 * max_len - 24,
max_window +
DIV_ROUND_UP(13 * max_len, 16) * 4);
else if (temperature < 20000)
phase_delay = max_window + DIV_ROUND_UP(9 * max_len, 16) * 4;
else if (temperature < 40000)
phase_delay = max_window + DIV_ROUND_UP(8 * max_len, 16) * 4;
else if (temperature < 70000)
phase_delay = max_window + DIV_ROUND_UP(7 * max_len, 16) * 4;
else if (temperature < 90000)
phase_delay = max_window + DIV_ROUND_UP(5 * max_len, 16) * 4;
else if (temperature < 120000)
phase_delay = max_window + DIV_ROUND_UP(4 * max_len, 16) * 4;
else
phase_delay = max_window + DIV_ROUND_UP(3 * max_len, 16) * 4;
/*
* Stage 2: Search for a single point failure near the chosen tuning
* value in two steps. First in the +3 to +10 range and then in the
* +2 to -10 range. If found, move away from it in the appropriate
* direction by the appropriate amount depending on the temperature.
*/
for (i = 3; i <= 10; i++) {
sdhci_omap_set_dll(omap_host, phase_delay + i);
if (mmc_send_tuning(mmc, opcode, NULL)) {
if (temperature < 10000)
phase_delay += i + 6;
else if (temperature < 20000)
phase_delay += i - 12;
else if (temperature < 70000)
phase_delay += i - 8;
else
phase_delay += i - 6;
goto single_failure_found;
}
}
for (i = 2; i >= -10; i--) {
sdhci_omap_set_dll(omap_host, phase_delay + i);
if (mmc_send_tuning(mmc, opcode, NULL)) {
if (temperature < 10000)
phase_delay += i + 12;
else if (temperature < 20000)
phase_delay += i + 8;
else if (temperature < 70000)
phase_delay += i + 8;
else if (temperature < 90000)
phase_delay += i + 10;
else
phase_delay += i + 12;
goto single_failure_found;
}
}
single_failure_found:
reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12);
if (!(reg & AC12_SCLK_SEL)) {
ret = -EIO;
goto tuning_error;
}
phase_delay = max_window + 4 * (max_len >> 1);
sdhci_omap_set_dll(omap_host, phase_delay);
omap_host->is_tuning = false;
goto ret;
tuning_error:
omap_host->is_tuning = false;
dev_err(dev, "Tuning failed\n");
sdhci_omap_disable_tuning(omap_host);
@ -653,8 +747,12 @@ static void sdhci_omap_init_74_clocks(struct sdhci_host *host, u8 power_mode)
/* wait 1ms */
timeout = ktime_add_ms(ktime_get(), SDHCI_OMAP_TIMEOUT);
while (!(sdhci_omap_readl(omap_host, SDHCI_OMAP_STAT) & INT_CC_EN)) {
if (WARN_ON(ktime_after(ktime_get(), timeout)))
while (1) {
bool timedout = ktime_after(ktime_get(), timeout);
if (sdhci_omap_readl(omap_host, SDHCI_OMAP_STAT) & INT_CC_EN)
break;
if (WARN_ON(timedout))
return;
usleep_range(5, 10);
}
@ -687,6 +785,18 @@ static void sdhci_omap_set_uhs_signaling(struct sdhci_host *host,
sdhci_omap_start_clock(omap_host);
}
void sdhci_omap_reset(struct sdhci_host *host, u8 mask)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host);
/* Don't reset data lines during tuning operation */
if (omap_host->is_tuning)
mask &= ~SDHCI_RESET_DATA;
sdhci_reset(host, mask);
}
static struct sdhci_ops sdhci_omap_ops = {
.set_clock = sdhci_omap_set_clock,
.set_power = sdhci_omap_set_power,
@ -695,7 +805,7 @@ static struct sdhci_ops sdhci_omap_ops = {
.get_min_clock = sdhci_omap_get_min_clock,
.set_bus_width = sdhci_omap_set_bus_width,
.platform_send_init_74_clocks = sdhci_omap_init_74_clocks,
.reset = sdhci_reset,
.reset = sdhci_omap_reset,
.set_uhs_signaling = sdhci_omap_set_uhs_signaling,
};

Some files were not shown because too many files have changed in this diff Show More