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 | ||||
|  | ||||
							
								
								
									
										36
									
								
								Documentation/devicetree/bindings/mmc/sdhci-am654.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								Documentation/devicetree/bindings/mmc/sdhci-am654.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| Device Tree Bindings for the SDHCI Controllers present on TI's AM654 SOCs | ||||
| 
 | ||||
| The bindings follow the mmc[1], clock[2] and interrupt[3] bindings. | ||||
| Only deviations are documented here. | ||||
| 
 | ||||
|   [1] Documentation/devicetree/bindings/mmc/mmc.txt | ||||
|   [2] Documentation/devicetree/bindings/clock/clock-bindings.txt | ||||
|   [3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt | ||||
| 
 | ||||
| Required Properties: | ||||
| 	- compatible: should be "ti,am654-sdhci-5.1" | ||||
| 	- reg: Must be two entries. | ||||
| 		- The first should be the sdhci register space | ||||
| 		- The second should the subsystem/phy register space | ||||
| 	- clocks: Handles to the clock inputs. | ||||
| 	- clock-names: Tuple including "clk_xin" and "clk_ahb" | ||||
| 	- interrupts: Interrupt specifiers | ||||
| 	- ti,otap-del-sel: Output Tap Delay select | ||||
| 	- ti,trm-icp: DLL trim select | ||||
| 	- ti,driver-strength-ohm: driver strength in ohms. | ||||
| 				  Valid values are 33, 40, 50, 66 and 100 ohms. | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| 	sdhci0: sdhci@4f80000 { | ||||
| 		compatible = "ti,am654-sdhci-5.1"; | ||||
| 		reg = <0x0 0x4f80000 0x0 0x260>, <0x0 0x4f90000 0x0 0x134>; | ||||
| 		power-domains = <&k3_pds 47>; | ||||
| 		clocks = <&k3_clks 47 0>, <&k3_clks 47 1>; | ||||
| 		clock-names = "clk_ahb", "clk_xin"; | ||||
| 		interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>; | ||||
| 		sdhci-caps-mask = <0x80000007 0x0>; | ||||
| 		mmc-ddr-1_8v; | ||||
| 		ti,otap-del-sel = <0x2>; | ||||
| 		ti,trm-icp = <0x8>; | ||||
| 	}; | ||||
| @ -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 | ||||
|  | ||||
							
								
								
									
										371
									
								
								drivers/misc/cardreader/alcor_pci.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										371
									
								
								drivers/misc/cardreader/alcor_pci.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,371 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0+
 | ||||
| /*
 | ||||
|  * Copyright (C) 2018 Oleksij Rempel <linux@rempel-privat.de> | ||||
|  * | ||||
|  * Driver for Alcor Micro AU6601 and AU6621 controllers | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/delay.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/irq.h> | ||||
| #include <linux/mfd/core.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/pci.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/pm.h> | ||||
| 
 | ||||
| #include <linux/alcor_pci.h> | ||||
| 
 | ||||
| #define DRV_NAME_ALCOR_PCI			"alcor_pci" | ||||
| 
 | ||||
| static DEFINE_IDA(alcor_pci_idr); | ||||
| 
 | ||||
| static struct mfd_cell alcor_pci_cells[] = { | ||||
| 	[ALCOR_SD_CARD] = { | ||||
| 		.name = DRV_NAME_ALCOR_PCI_SDMMC, | ||||
| 	}, | ||||
| 	[ALCOR_MS_CARD] = { | ||||
| 		.name = DRV_NAME_ALCOR_PCI_MS, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct alcor_dev_cfg alcor_cfg = { | ||||
| 	.dma = 0, | ||||
| }; | ||||
| 
 | ||||
| static const struct alcor_dev_cfg au6621_cfg = { | ||||
| 	.dma = 1, | ||||
| }; | ||||
| 
 | ||||
| static const struct pci_device_id pci_ids[] = { | ||||
| 	{ PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6601), | ||||
| 		.driver_data = (kernel_ulong_t)&alcor_cfg }, | ||||
| 	{ PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6621), | ||||
| 		.driver_data = (kernel_ulong_t)&au6621_cfg }, | ||||
| 	{ }, | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(pci, pci_ids); | ||||
| 
 | ||||
| void alcor_write8(struct alcor_pci_priv *priv, u8 val, unsigned int addr) | ||||
| { | ||||
| 	writeb(val, priv->iobase + addr); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(alcor_write8); | ||||
| 
 | ||||
| void alcor_write16(struct alcor_pci_priv *priv, u16 val, unsigned int addr) | ||||
| { | ||||
| 	writew(val, priv->iobase + addr); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(alcor_write16); | ||||
| 
 | ||||
| void alcor_write32(struct alcor_pci_priv *priv, u32 val, unsigned int addr) | ||||
| { | ||||
| 	writel(val, priv->iobase + addr); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(alcor_write32); | ||||
| 
 | ||||
| void alcor_write32be(struct alcor_pci_priv *priv, u32 val, unsigned int addr) | ||||
| { | ||||
| 	iowrite32be(val, priv->iobase + addr); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(alcor_write32be); | ||||
| 
 | ||||
| u8 alcor_read8(struct alcor_pci_priv *priv, unsigned int addr) | ||||
| { | ||||
| 	return readb(priv->iobase + addr); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(alcor_read8); | ||||
| 
 | ||||
| u32 alcor_read32(struct alcor_pci_priv *priv, unsigned int addr) | ||||
| { | ||||
| 	return readl(priv->iobase + addr); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(alcor_read32); | ||||
| 
 | ||||
| u32 alcor_read32be(struct alcor_pci_priv *priv, unsigned int addr) | ||||
| { | ||||
| 	return ioread32be(priv->iobase + addr); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(alcor_read32be); | ||||
| 
 | ||||
| static int alcor_pci_find_cap_offset(struct alcor_pci_priv *priv, | ||||
| 				     struct pci_dev *pci) | ||||
| { | ||||
| 	int where; | ||||
| 	u8 val8; | ||||
| 	u32 val32; | ||||
| 
 | ||||
| 	where = ALCOR_CAP_START_OFFSET; | ||||
| 	pci_read_config_byte(pci, where, &val8); | ||||
| 	if (!val8) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	where = (int)val8; | ||||
| 	while (1) { | ||||
| 		pci_read_config_dword(pci, where, &val32); | ||||
| 		if (val32 == 0xffffffff) { | ||||
| 			dev_dbg(priv->dev, "find_cap_offset invalid value %x.\n", | ||||
| 				val32); | ||||
| 			return 0; | ||||
| 		} | ||||
| 
 | ||||
| 		if ((val32 & 0xff) == 0x10) { | ||||
| 			dev_dbg(priv->dev, "pcie cap offset: %x\n", where); | ||||
| 			return where; | ||||
| 		} | ||||
| 
 | ||||
| 		if ((val32 & 0xff00) == 0x00) { | ||||
| 			dev_dbg(priv->dev, "pci_find_cap_offset invalid value %x.\n", | ||||
| 				val32); | ||||
| 			break; | ||||
| 		} | ||||
| 		where = (int)((val32 >> 8) & 0xff); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void alcor_pci_init_check_aspm(struct alcor_pci_priv *priv) | ||||
| { | ||||
| 	struct pci_dev *pci; | ||||
| 	int where; | ||||
| 	u32 val32; | ||||
| 
 | ||||
| 	priv->pdev_cap_off    = alcor_pci_find_cap_offset(priv, priv->pdev); | ||||
| 	priv->parent_cap_off = alcor_pci_find_cap_offset(priv, | ||||
| 							 priv->parent_pdev); | ||||
| 
 | ||||
| 	if ((priv->pdev_cap_off == 0) || (priv->parent_cap_off == 0)) { | ||||
| 		dev_dbg(priv->dev, "pci_cap_off: %x, parent_cap_off: %x\n", | ||||
| 			priv->pdev_cap_off, priv->parent_cap_off); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/* link capability */ | ||||
| 	pci   = priv->pdev; | ||||
| 	where = priv->pdev_cap_off + ALCOR_PCIE_LINK_CAP_OFFSET; | ||||
| 	pci_read_config_dword(pci, where, &val32); | ||||
| 	priv->pdev_aspm_cap = (u8)(val32 >> 10) & 0x03; | ||||
| 
 | ||||
| 	pci   = priv->parent_pdev; | ||||
| 	where = priv->parent_cap_off + ALCOR_PCIE_LINK_CAP_OFFSET; | ||||
| 	pci_read_config_dword(pci, where, &val32); | ||||
| 	priv->parent_aspm_cap = (u8)(val32 >> 10) & 0x03; | ||||
| 
 | ||||
| 	if (priv->pdev_aspm_cap != priv->parent_aspm_cap) { | ||||
| 		u8 aspm_cap; | ||||
| 
 | ||||
| 		dev_dbg(priv->dev, "pdev_aspm_cap: %x, parent_aspm_cap: %x\n", | ||||
| 			priv->pdev_aspm_cap, priv->parent_aspm_cap); | ||||
| 		aspm_cap = priv->pdev_aspm_cap & priv->parent_aspm_cap; | ||||
| 		priv->pdev_aspm_cap    = aspm_cap; | ||||
| 		priv->parent_aspm_cap = aspm_cap; | ||||
| 	} | ||||
| 
 | ||||
| 	dev_dbg(priv->dev, "ext_config_dev_aspm: %x, pdev_aspm_cap: %x\n", | ||||
| 		priv->ext_config_dev_aspm, priv->pdev_aspm_cap); | ||||
| 	priv->ext_config_dev_aspm &= priv->pdev_aspm_cap; | ||||
| } | ||||
| 
 | ||||
| static void alcor_pci_aspm_ctrl(struct alcor_pci_priv *priv, u8 aspm_enable) | ||||
| { | ||||
| 	struct pci_dev *pci; | ||||
| 	u8 aspm_ctrl, i; | ||||
| 	int where; | ||||
| 	u32 val32; | ||||
| 
 | ||||
| 	if ((!priv->pdev_cap_off) || (!priv->parent_cap_off)) { | ||||
| 		dev_dbg(priv->dev, "pci_cap_off: %x, parent_cap_off: %x\n", | ||||
| 			priv->pdev_cap_off, priv->parent_cap_off); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!priv->pdev_aspm_cap) | ||||
| 		return; | ||||
| 
 | ||||
| 	aspm_ctrl = 0; | ||||
| 	if (aspm_enable) { | ||||
| 		aspm_ctrl = priv->ext_config_dev_aspm; | ||||
| 
 | ||||
| 		if (!aspm_ctrl) { | ||||
| 			dev_dbg(priv->dev, "aspm_ctrl == 0\n"); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < 2; i++) { | ||||
| 
 | ||||
| 		if (i) { | ||||
| 			pci   = priv->parent_pdev; | ||||
| 			where = priv->parent_cap_off | ||||
| 				+ ALCOR_PCIE_LINK_CTRL_OFFSET; | ||||
| 		} else { | ||||
| 			pci   = priv->pdev; | ||||
| 			where = priv->pdev_cap_off | ||||
| 				+ ALCOR_PCIE_LINK_CTRL_OFFSET; | ||||
| 		} | ||||
| 
 | ||||
| 		pci_read_config_dword(pci, where, &val32); | ||||
| 		val32 &= (~0x03); | ||||
| 		val32 |= (aspm_ctrl & priv->pdev_aspm_cap); | ||||
| 		pci_write_config_byte(pci, where, (u8)val32); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static inline void alcor_mask_sd_irqs(struct alcor_pci_priv *priv) | ||||
| { | ||||
| 	alcor_write32(priv, 0, AU6601_REG_INT_ENABLE); | ||||
| } | ||||
| 
 | ||||
| static inline void alcor_unmask_sd_irqs(struct alcor_pci_priv *priv) | ||||
| { | ||||
| 	alcor_write32(priv, AU6601_INT_CMD_MASK | AU6601_INT_DATA_MASK | | ||||
| 		  AU6601_INT_CARD_INSERT | AU6601_INT_CARD_REMOVE | | ||||
| 		  AU6601_INT_OVER_CURRENT_ERR, | ||||
| 		  AU6601_REG_INT_ENABLE); | ||||
| } | ||||
| 
 | ||||
| static inline void alcor_mask_ms_irqs(struct alcor_pci_priv *priv) | ||||
| { | ||||
| 	alcor_write32(priv, 0, AU6601_MS_INT_ENABLE); | ||||
| } | ||||
| 
 | ||||
| static inline void alcor_unmask_ms_irqs(struct alcor_pci_priv *priv) | ||||
| { | ||||
| 	alcor_write32(priv, 0x3d00fa, AU6601_MS_INT_ENABLE); | ||||
| } | ||||
| 
 | ||||
| static int alcor_pci_probe(struct pci_dev *pdev, | ||||
| 			   const struct pci_device_id *ent) | ||||
| { | ||||
| 	struct alcor_dev_cfg *cfg; | ||||
| 	struct alcor_pci_priv *priv; | ||||
| 	int ret, i, bar = 0; | ||||
| 
 | ||||
| 	cfg = (void *)ent->driver_data; | ||||
| 
 | ||||
| 	ret = pcim_enable_device(pdev); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||||
| 	if (!priv) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	ret = ida_simple_get(&alcor_pci_idr, 0, 0, GFP_KERNEL); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 	priv->id = ret; | ||||
| 
 | ||||
| 	priv->pdev = pdev; | ||||
| 	priv->parent_pdev = pdev->bus->self; | ||||
| 	priv->dev = &pdev->dev; | ||||
| 	priv->cfg = cfg; | ||||
| 	priv->irq = pdev->irq; | ||||
| 
 | ||||
| 	ret = pci_request_regions(pdev, DRV_NAME_ALCOR_PCI); | ||||
| 	if (ret) { | ||||
| 		dev_err(&pdev->dev, "Cannot request region\n"); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { | ||||
| 		dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar); | ||||
| 		ret = -ENODEV; | ||||
| 		goto error_release_regions; | ||||
| 	} | ||||
| 
 | ||||
| 	priv->iobase = pcim_iomap(pdev, bar, 0); | ||||
| 	if (!priv->iobase) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto error_release_regions; | ||||
| 	} | ||||
| 
 | ||||
| 	/* make sure irqs are disabled */ | ||||
| 	alcor_write32(priv, 0, AU6601_REG_INT_ENABLE); | ||||
| 	alcor_write32(priv, 0, AU6601_MS_INT_ENABLE); | ||||
| 
 | ||||
| 	ret = dma_set_mask_and_coherent(priv->dev, AU6601_SDMA_MASK); | ||||
| 	if (ret) { | ||||
| 		dev_err(priv->dev, "Failed to set DMA mask\n"); | ||||
| 		goto error_release_regions; | ||||
| 	} | ||||
| 
 | ||||
| 	pci_set_master(pdev); | ||||
| 	pci_set_drvdata(pdev, priv); | ||||
| 	alcor_pci_init_check_aspm(priv); | ||||
| 
 | ||||
| 	for (i = 0; i < ARRAY_SIZE(alcor_pci_cells); i++) { | ||||
| 		alcor_pci_cells[i].platform_data = priv; | ||||
| 		alcor_pci_cells[i].pdata_size = sizeof(*priv); | ||||
| 	} | ||||
| 	ret = mfd_add_devices(&pdev->dev, priv->id, alcor_pci_cells, | ||||
| 			ARRAY_SIZE(alcor_pci_cells), NULL, 0, NULL); | ||||
| 	if (ret < 0) | ||||
| 		goto error_release_regions; | ||||
| 
 | ||||
| 	alcor_pci_aspm_ctrl(priv, 0); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| error_release_regions: | ||||
| 	pci_release_regions(pdev); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void alcor_pci_remove(struct pci_dev *pdev) | ||||
| { | ||||
| 	struct alcor_pci_priv *priv; | ||||
| 
 | ||||
| 	priv = pci_get_drvdata(pdev); | ||||
| 
 | ||||
| 	alcor_pci_aspm_ctrl(priv, 1); | ||||
| 
 | ||||
| 	mfd_remove_devices(&pdev->dev); | ||||
| 
 | ||||
| 	ida_simple_remove(&alcor_pci_idr, priv->id); | ||||
| 
 | ||||
| 	pci_release_regions(pdev); | ||||
| 	pci_set_drvdata(pdev, NULL); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_PM_SLEEP | ||||
| static int alcor_suspend(struct device *dev) | ||||
| { | ||||
| 	struct pci_dev *pdev = to_pci_dev(dev); | ||||
| 	struct alcor_pci_priv *priv = pci_get_drvdata(pdev); | ||||
| 
 | ||||
| 	alcor_pci_aspm_ctrl(priv, 1); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int alcor_resume(struct device *dev) | ||||
| { | ||||
| 
 | ||||
| 	struct pci_dev *pdev = to_pci_dev(dev); | ||||
| 	struct alcor_pci_priv *priv = pci_get_drvdata(pdev); | ||||
| 
 | ||||
| 	alcor_pci_aspm_ctrl(priv, 0); | ||||
| 	return 0; | ||||
| } | ||||
| #endif /* CONFIG_PM_SLEEP */ | ||||
| 
 | ||||
| static SIMPLE_DEV_PM_OPS(alcor_pci_pm_ops, alcor_suspend, alcor_resume); | ||||
| 
 | ||||
| static struct pci_driver alcor_driver = { | ||||
| 	.name	=	DRV_NAME_ALCOR_PCI, | ||||
| 	.id_table =	pci_ids, | ||||
| 	.probe	=	alcor_pci_probe, | ||||
| 	.remove =	alcor_pci_remove, | ||||
| 	.driver	=	{ | ||||
| 		.pm	= &alcor_pci_pm_ops | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| module_pci_driver(alcor_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>"); | ||||
| MODULE_DESCRIPTION("PCI driver for Alcor Micro AU6601 Secure Digital Host Controller Interface"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| @ -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 | ||||
|  | ||||
							
								
								
									
										1162
									
								
								drivers/mmc/host/alcor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1162
									
								
								drivers/mmc/host/alcor.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												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
	
	Block a user