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:
commit
00d59fde85
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>;
|
||||
};
|
|
@ -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>;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(¢ro685_mci_gpio_table);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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[] = {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */ }
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue