mirror of
https://github.com/torvalds/linux.git
synced 2026-06-07 22:14:04 +02:00
Merge ce51c2b7ce ("Merge tag 'mmc-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc") into android-mainline
Steps on the way to 5.11-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I2bac328ace91118b026621b8544019c3ca472d88
This commit is contained in:
commit
8b882de4c1
|
|
@ -5,8 +5,12 @@ Required properties:
|
|||
"aeroflexgaisler,i2cmst"
|
||||
"sifive,fu540-c000-i2c", "sifive,i2c0"
|
||||
For Opencore based I2C IP block reimplemented in
|
||||
FU540-C000 SoC. Please refer to sifive-blocks-ip-versioning.txt
|
||||
for additional details.
|
||||
FU540-C000 SoC.
|
||||
"sifive,fu740-c000-i2c", "sifive,i2c0"
|
||||
For Opencore based I2C IP block reimplemented in
|
||||
FU740-C000 SoC.
|
||||
Please refer to sifive-blocks-ip-versioning.txt for
|
||||
additional details.
|
||||
- reg : bus address start and address range size of device
|
||||
- clocks : handle to the controller clock; see the note below.
|
||||
Mutually exclusive with opencores,ip-clock-frequency
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ Required properties :
|
|||
"ti,omap4-i2c" for OMAP4+ SoCs
|
||||
"ti,am654-i2c", "ti,omap4-i2c" for AM654 SoCs
|
||||
"ti,j721e-i2c", "ti,omap4-i2c" for J721E SoCs
|
||||
"ti,am64-i2c", "ti,omap4-i2c" for AM64 SoCs
|
||||
- ti,hwmods : Must be "i2c<n>", n being the instance number (1-based)
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
Actions Semiconductor Owl I2C controller
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : Should be one of the following:
|
||||
- "actions,s700-i2c" for S700 SoC
|
||||
- "actions,s900-i2c" for S900 SoC
|
||||
- reg : Offset and length of the register set for the device.
|
||||
- #address-cells : Should be 1.
|
||||
- #size-cells : Should be 0.
|
||||
- interrupts : A single interrupt specifier.
|
||||
- clocks : Phandle of the clock feeding the I2C controller.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- clock-frequency : Desired I2C bus clock frequency in Hz. As only Normal and
|
||||
Fast modes are supported, possible values are 100000 and
|
||||
400000.
|
||||
Examples:
|
||||
|
||||
i2c0: i2c@e0170000 {
|
||||
compatible = "actions,s900-i2c";
|
||||
reg = <0 0xe0170000 0 0x1000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clock CLK_I2C0>;
|
||||
clock-frequency = <100000>;
|
||||
};
|
||||
62
Documentation/devicetree/bindings/i2c/i2c-owl.yaml
Normal file
62
Documentation/devicetree/bindings/i2c/i2c-owl.yaml
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/i2c-owl.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Actions Semi Owl I2C Controller
|
||||
|
||||
maintainers:
|
||||
- Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
|
||||
|
||||
description: |
|
||||
This I2C controller is found in the Actions Semi Owl SoCs:
|
||||
S500, S700 and S900.
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- actions,s500-i2c # Actions Semi S500 compatible SoCs
|
||||
- actions,s700-i2c # Actions Semi S700 compatible SoCs
|
||||
- actions,s900-i2c # Actions Semi S900 compatible SoCs
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
description: Phandle of the clock feeding the I2C controller.
|
||||
minItems: 1
|
||||
|
||||
clock-frequency:
|
||||
description: |
|
||||
Desired I2C bus clock frequency in Hz. As only Standard and Fast
|
||||
modes are supported, possible values are 100000 and 400000.
|
||||
enum: [100000, 400000]
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/actions,s900-cmu.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
i2c@e0170000 {
|
||||
compatible = "actions,s900-i2c";
|
||||
reg = <0xe0170000 0x1000>;
|
||||
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cmu CLK_I2C0>;
|
||||
clock-frequency = <100000>;
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
Device tree configuration for the Mellanox I2C SMBus on BlueField SoCs
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible : should be "mellanox,i2c-mlxbf1" or "mellanox,i2c-mlxbf2".
|
||||
|
||||
- reg : address offset and length of the device registers. The
|
||||
registers consist of the following set of resources:
|
||||
1) Smbus block registers.
|
||||
2) Cause master registers.
|
||||
3) Cause slave registers.
|
||||
4) Cause coalesce registers (if compatible isn't set
|
||||
to "mellanox,i2c-mlxbf1").
|
||||
|
||||
- interrupts : interrupt number.
|
||||
|
||||
Optional Properties:
|
||||
|
||||
- clock-frequency : bus frequency used to configure timing registers;
|
||||
allowed values are 100000, 400000 and 1000000;
|
||||
those are expressed in Hz. Default is 100000.
|
||||
|
||||
Example:
|
||||
|
||||
i2c@2804000 {
|
||||
compatible = "mellanox,i2c-mlxbf1";
|
||||
reg = <0x02804000 0x800>,
|
||||
<0x02801200 0x020>,
|
||||
<0x02801260 0x020>;
|
||||
interrupts = <57>;
|
||||
clock-frequency = <100000>;
|
||||
};
|
||||
|
||||
i2c@2808800 {
|
||||
compatible = "mellanox,i2c-mlxbf2";
|
||||
reg = <0x02808800 0x600>,
|
||||
<0x02808e00 0x020>,
|
||||
<0x02808e20 0x020>,
|
||||
<0x02808e40 0x010>;
|
||||
interrupts = <57>;
|
||||
clock-frequency = <400000>;
|
||||
};
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/i2c/mellanox,i2c-mlxbf.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Mellanox I2C SMBus on BlueField SoCs
|
||||
|
||||
maintainers:
|
||||
- Khalil Blaiech <kblaiech@nvidia.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/i2c/i2c-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mellanox,i2c-mlxbf1
|
||||
- mellanox,i2c-mlxbf2
|
||||
|
||||
reg:
|
||||
minItems: 3
|
||||
maxItems: 4
|
||||
items:
|
||||
- description: Smbus block registers
|
||||
- description: Cause master registers
|
||||
- description: Cause slave registers
|
||||
- description: Cause coalesce registers
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clock-frequency:
|
||||
enum: [ 100000, 400000, 1000000 ]
|
||||
description:
|
||||
bus frequency used to configure timing registers;
|
||||
The frequency is expressed in Hz. Default is 100000.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- mellanox,i2c-mlxbf1
|
||||
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
maxItems: 3
|
||||
|
||||
examples:
|
||||
- |
|
||||
i2c@2804000 {
|
||||
compatible = "mellanox,i2c-mlxbf1";
|
||||
reg = <0x02804000 0x800>,
|
||||
<0x02801200 0x020>,
|
||||
<0x02801260 0x020>;
|
||||
interrupts = <57>;
|
||||
clock-frequency = <100000>;
|
||||
};
|
||||
|
||||
- |
|
||||
i2c@2808800 {
|
||||
compatible = "mellanox,i2c-mlxbf2";
|
||||
reg = <0x02808800 0x600>,
|
||||
<0x02808e00 0x020>,
|
||||
<0x02808e20 0x020>,
|
||||
<0x02808e40 0x010>;
|
||||
interrupts = <57>;
|
||||
clock-frequency = <400000>;
|
||||
};
|
||||
|
|
@ -147,7 +147,7 @@ properties:
|
|||
|
||||
xlnx,mio-bank:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 2]
|
||||
enum: [0, 1, 2]
|
||||
default: 0
|
||||
description:
|
||||
The MIO bank number in which the command and data lines are configured.
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ properties:
|
|||
- fsl,imx8mn-usdhc
|
||||
- fsl,imx8mp-usdhc
|
||||
- fsl,imx8mq-usdhc
|
||||
- fsl,imx8qm-usdhc
|
||||
- fsl,imx8qxp-usdhc
|
||||
- const: fsl,imx7d-usdhc
|
||||
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
* MTK MMC controller
|
||||
|
||||
The MTK MSDC can act as a MMC controller
|
||||
to support MMC, SD, and SDIO types of memory cards.
|
||||
|
||||
This file documents differences between the core properties in mmc.txt
|
||||
and the properties used by the msdc driver.
|
||||
|
||||
Required properties:
|
||||
- compatible: value should be either of the following.
|
||||
"mediatek,mt8135-mmc": for mmc host ip compatible with mt8135
|
||||
"mediatek,mt8173-mmc": for mmc host ip compatible with mt8173
|
||||
"mediatek,mt8183-mmc": for mmc host ip compatible with mt8183
|
||||
"mediatek,mt8516-mmc": for mmc host ip compatible with mt8516
|
||||
"mediatek,mt6779-mmc": for mmc host ip compatible with mt6779
|
||||
"mediatek,mt2701-mmc": for mmc host ip compatible with mt2701
|
||||
"mediatek,mt2712-mmc": for mmc host ip compatible with mt2712
|
||||
"mediatek,mt7622-mmc": for MT7622 SoC
|
||||
"mediatek,mt7623-mmc", "mediatek,mt2701-mmc": for MT7623 SoC
|
||||
"mediatek,mt7620-mmc", for MT7621 SoC (and others)
|
||||
|
||||
- reg: physical base address of the controller and length
|
||||
- interrupts: Should contain MSDC interrupt number
|
||||
- clocks: Should contain phandle for the clock feeding the MMC controller
|
||||
- clock-names: Should contain the following:
|
||||
"source" - source clock (required)
|
||||
"hclk" - HCLK which used for host (required)
|
||||
"source_cg" - independent source clock gate (required for MT2712)
|
||||
"bus_clk" - bus clock used for internal register access (required for MT2712 MSDC0/3)
|
||||
- pinctrl-names: should be "default", "state_uhs"
|
||||
- pinctrl-0: should contain default/high speed pin ctrl
|
||||
- pinctrl-1: should contain uhs mode pin ctrl
|
||||
- vmmc-supply: power to the Core
|
||||
- vqmmc-supply: power to the IO
|
||||
|
||||
Optional properties:
|
||||
- assigned-clocks: PLL of the source clock
|
||||
- assigned-clock-parents: parent of source clock, used for HS400 mode to get 400Mhz source clock
|
||||
- hs400-ds-delay: HS400 DS delay setting
|
||||
- mediatek,hs200-cmd-int-delay: HS200 command internal delay setting.
|
||||
This field has total 32 stages.
|
||||
The value is an integer from 0 to 31.
|
||||
- mediatek,hs400-cmd-int-delay: HS400 command internal delay setting
|
||||
This field has total 32 stages.
|
||||
The value is an integer from 0 to 31.
|
||||
- mediatek,hs400-cmd-resp-sel-rising: HS400 command response sample selection
|
||||
If present,HS400 command responses are sampled on rising edges.
|
||||
If not present,HS400 command responses are sampled on falling edges.
|
||||
- mediatek,latch-ck: Some SoCs do not support enhance_rx, need set correct latch-ck to avoid data crc
|
||||
error caused by stop clock(fifo full)
|
||||
Valid range = [0:0x7]. if not present, default value is 0.
|
||||
applied to compatible "mediatek,mt2701-mmc".
|
||||
- resets: Phandle and reset specifier pair to softreset line of MSDC IP.
|
||||
- reset-names: Should be "hrst".
|
||||
|
||||
Examples:
|
||||
mmc0: mmc@11230000 {
|
||||
compatible = "mediatek,mt8173-mmc", "mediatek,mt8135-mmc";
|
||||
reg = <0 0x11230000 0 0x108>;
|
||||
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_LOW>;
|
||||
vmmc-supply = <&mt6397_vemc_3v3_reg>;
|
||||
vqmmc-supply = <&mt6397_vio18_reg>;
|
||||
clocks = <&pericfg CLK_PERI_MSDC30_0>,
|
||||
<&topckgen CLK_TOP_MSDC50_0_H_SEL>;
|
||||
clock-names = "source", "hclk";
|
||||
pinctrl-names = "default", "state_uhs";
|
||||
pinctrl-0 = <&mmc0_pins_default>;
|
||||
pinctrl-1 = <&mmc0_pins_uhs>;
|
||||
assigned-clocks = <&topckgen CLK_TOP_MSDC50_0_SEL>;
|
||||
assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_D2>;
|
||||
hs400-ds-delay = <0x14015>;
|
||||
mediatek,hs200-cmd-int-delay = <26>;
|
||||
mediatek,hs400-cmd-int-delay = <14>;
|
||||
mediatek,hs400-cmd-resp-sel-rising;
|
||||
};
|
||||
176
Documentation/devicetree/bindings/mmc/mtk-sd.yaml
Normal file
176
Documentation/devicetree/bindings/mmc/mtk-sd.yaml
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mmc/mtk-sd.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MTK MSDC Storage Host Controller Binding
|
||||
|
||||
maintainers:
|
||||
- Chaotian Jing <chaotian.jing@mediatek.com>
|
||||
- Wenbin Mei <wenbin.mei@mediatek.com>
|
||||
|
||||
allOf:
|
||||
- $ref: mmc-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- mediatek,mt2701-mmc
|
||||
- mediatek,mt2712-mmc
|
||||
- mediatek,mt6779-mmc
|
||||
- mediatek,mt7620-mmc
|
||||
- mediatek,mt7622-mmc
|
||||
- mediatek,mt8135-mmc
|
||||
- mediatek,mt8173-mmc
|
||||
- mediatek,mt8183-mmc
|
||||
- mediatek,mt8516-mmc
|
||||
- items:
|
||||
- const: mediatek,mt7623-mmc
|
||||
- const: mediatek,mt2701-mmc
|
||||
- items:
|
||||
- const: mediatek,mt8192-mmc
|
||||
- const: mediatek,mt8183-mmc
|
||||
|
||||
clocks:
|
||||
description:
|
||||
Should contain phandle for the clock feeding the MMC controller.
|
||||
minItems: 2
|
||||
maxItems: 8
|
||||
items:
|
||||
- description: source clock (required).
|
||||
- description: HCLK which used for host (required).
|
||||
- description: independent source clock gate (required for MT2712).
|
||||
- description: bus clock used for internal register access (required for MT2712 MSDC0/3).
|
||||
- description: msdc subsys clock gate (required for MT8192).
|
||||
- description: peripheral bus clock gate (required for MT8192).
|
||||
- description: AXI bus clock gate (required for MT8192).
|
||||
- description: AHB bus clock gate (required for MT8192).
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 8
|
||||
items:
|
||||
- const: source
|
||||
- const: hclk
|
||||
- const: source_cg
|
||||
- const: bus_clk
|
||||
- const: sys_cg
|
||||
- const: pclk_cg
|
||||
- const: axi_cg
|
||||
- const: ahb_cg
|
||||
|
||||
pinctrl-names:
|
||||
items:
|
||||
- const: default
|
||||
- const: state_uhs
|
||||
|
||||
pinctrl-0:
|
||||
description:
|
||||
should contain default/high speed pin ctrl.
|
||||
maxItems: 1
|
||||
|
||||
pinctrl-1:
|
||||
description:
|
||||
should contain uhs mode pin ctrl.
|
||||
maxItems: 1
|
||||
|
||||
assigned-clocks:
|
||||
description:
|
||||
PLL of the source clock.
|
||||
maxItems: 1
|
||||
|
||||
assigned-clock-parents:
|
||||
description:
|
||||
parent of source clock, used for HS400 mode to get 400Mhz source clock.
|
||||
maxItems: 1
|
||||
|
||||
hs400-ds-delay:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
HS400 DS delay setting.
|
||||
minimum: 0
|
||||
maximum: 0xffffffff
|
||||
|
||||
mediatek,hs200-cmd-int-delay:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
HS200 command internal delay setting.
|
||||
This field has total 32 stages.
|
||||
The value is an integer from 0 to 31.
|
||||
minimum: 0
|
||||
maximum: 31
|
||||
|
||||
mediatek,hs400-cmd-int-delay:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
HS400 command internal delay setting.
|
||||
This field has total 32 stages.
|
||||
The value is an integer from 0 to 31.
|
||||
minimum: 0
|
||||
maximum: 31
|
||||
|
||||
mediatek,hs400-cmd-resp-sel-rising:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
HS400 command response sample selection.
|
||||
If present, HS400 command responses are sampled on rising edges.
|
||||
If not present, HS400 command responses are sampled on falling edges.
|
||||
|
||||
mediatek,latch-ck:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
description:
|
||||
Some SoCs do not support enhance_rx, need set correct latch-ck to avoid
|
||||
data crc error caused by stop clock(fifo full) Valid range = [0:0x7].
|
||||
if not present, default value is 0.
|
||||
applied to compatible "mediatek,mt2701-mmc".
|
||||
minimum: 0
|
||||
maximum: 7
|
||||
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
const: hrst
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- pinctrl-names
|
||||
- pinctrl-0
|
||||
- pinctrl-1
|
||||
- vmmc-supply
|
||||
- vqmmc-supply
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/clock/mt8173-clk.h>
|
||||
mmc0: mmc@11230000 {
|
||||
compatible = "mediatek,mt8173-mmc";
|
||||
reg = <0x11230000 0x1000>;
|
||||
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_LOW>;
|
||||
vmmc-supply = <&mt6397_vemc_3v3_reg>;
|
||||
vqmmc-supply = <&mt6397_vio18_reg>;
|
||||
clocks = <&pericfg CLK_PERI_MSDC30_0>,
|
||||
<&topckgen CLK_TOP_MSDC50_0_H_SEL>;
|
||||
clock-names = "source", "hclk";
|
||||
pinctrl-names = "default", "state_uhs";
|
||||
pinctrl-0 = <&mmc0_pins_default>;
|
||||
pinctrl-1 = <&mmc0_pins_uhs>;
|
||||
assigned-clocks = <&topckgen CLK_TOP_MSDC50_0_SEL>;
|
||||
assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_D2>;
|
||||
hs400-ds-delay = <0x14015>;
|
||||
mediatek,hs200-cmd-int-delay = <26>;
|
||||
mediatek,hs400-cmd-int-delay = <14>;
|
||||
mediatek,hs400-cmd-resp-sel-rising;
|
||||
};
|
||||
|
||||
...
|
||||
|
|
@ -17,7 +17,9 @@ properties:
|
|||
oneOf:
|
||||
- const: actions,owl-mmc
|
||||
- items:
|
||||
- const: actions,s700-mmc
|
||||
- enum:
|
||||
- actions,s500-mmc
|
||||
- actions,s700-mmc
|
||||
- const: actions,owl-mmc
|
||||
|
||||
reg:
|
||||
|
|
|
|||
|
|
@ -1502,7 +1502,7 @@ S: Maintained
|
|||
F: Documentation/devicetree/bindings/arm/actions.yaml
|
||||
F: Documentation/devicetree/bindings/clock/actions,owl-cmu.txt
|
||||
F: Documentation/devicetree/bindings/dma/owl-dma.yaml
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-owl.txt
|
||||
F: Documentation/devicetree/bindings/i2c/i2c-owl.yaml
|
||||
F: Documentation/devicetree/bindings/interrupt-controller/actions,owl-sirq.yaml
|
||||
F: Documentation/devicetree/bindings/mmc/owl-mmc.yaml
|
||||
F: Documentation/devicetree/bindings/pinctrl/actions,*
|
||||
|
|
@ -11261,6 +11261,7 @@ MELLANOX BLUEFIELD I2C DRIVER
|
|||
M: Khalil Blaiech <kblaiech@nvidia.com>
|
||||
L: linux-i2c@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/i2c/mellanox,i2c-mlxbf.yaml
|
||||
F: drivers/i2c/busses/i2c-mlxbf.c
|
||||
|
||||
MELLANOX ETHERNET DRIVER (mlx4_en)
|
||||
|
|
|
|||
|
|
@ -675,6 +675,7 @@ config I2C_IMG
|
|||
config I2C_IMX
|
||||
tristate "IMX I2C interface"
|
||||
depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE
|
||||
select I2C_SLAVE
|
||||
help
|
||||
Say Y here if you want to use the IIC bus controller on
|
||||
the Freescale i.MX/MXC, Layerscape or ColdFire processors.
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/dma-atmel.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "i2c-at91.h"
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_data/dma-atmel.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define AT91_I2C_TIMEOUT msecs_to_jiffies(100) /* transfer timeout */
|
||||
|
|
@ -123,7 +122,6 @@ struct at91_twi_pdata {
|
|||
bool has_adv_dig_filtr;
|
||||
bool has_ana_filtr;
|
||||
bool has_clear_cmd;
|
||||
struct at_dma_slave dma_slave;
|
||||
};
|
||||
|
||||
struct at91_twi_dma {
|
||||
|
|
|
|||
|
|
@ -25,25 +25,25 @@
|
|||
I2C_FUNC_SMBUS_BLOCK_DATA | \
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK)
|
||||
|
||||
#define DW_IC_CON_MASTER 0x1
|
||||
#define DW_IC_CON_SPEED_STD 0x2
|
||||
#define DW_IC_CON_SPEED_FAST 0x4
|
||||
#define DW_IC_CON_SPEED_HIGH 0x6
|
||||
#define DW_IC_CON_SPEED_MASK 0x6
|
||||
#define DW_IC_CON_10BITADDR_SLAVE 0x8
|
||||
#define DW_IC_CON_10BITADDR_MASTER 0x10
|
||||
#define DW_IC_CON_RESTART_EN 0x20
|
||||
#define DW_IC_CON_SLAVE_DISABLE 0x40
|
||||
#define DW_IC_CON_STOP_DET_IFADDRESSED 0x80
|
||||
#define DW_IC_CON_TX_EMPTY_CTRL 0x100
|
||||
#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL 0x200
|
||||
#define DW_IC_CON_MASTER BIT(0)
|
||||
#define DW_IC_CON_SPEED_STD (1 << 1)
|
||||
#define DW_IC_CON_SPEED_FAST (2 << 1)
|
||||
#define DW_IC_CON_SPEED_HIGH (3 << 1)
|
||||
#define DW_IC_CON_SPEED_MASK GENMASK(2, 1)
|
||||
#define DW_IC_CON_10BITADDR_SLAVE BIT(3)
|
||||
#define DW_IC_CON_10BITADDR_MASTER BIT(4)
|
||||
#define DW_IC_CON_RESTART_EN BIT(5)
|
||||
#define DW_IC_CON_SLAVE_DISABLE BIT(6)
|
||||
#define DW_IC_CON_STOP_DET_IFADDRESSED BIT(7)
|
||||
#define DW_IC_CON_TX_EMPTY_CTRL BIT(8)
|
||||
#define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL BIT(9)
|
||||
|
||||
/*
|
||||
* Registers offset
|
||||
*/
|
||||
#define DW_IC_CON 0x0
|
||||
#define DW_IC_TAR 0x4
|
||||
#define DW_IC_SAR 0x8
|
||||
#define DW_IC_CON 0x00
|
||||
#define DW_IC_TAR 0x04
|
||||
#define DW_IC_SAR 0x08
|
||||
#define DW_IC_DATA_CMD 0x10
|
||||
#define DW_IC_SS_SCL_HCNT 0x14
|
||||
#define DW_IC_SS_SCL_LCNT 0x18
|
||||
|
|
@ -81,19 +81,19 @@
|
|||
#define DW_IC_COMP_TYPE 0xfc
|
||||
#define DW_IC_COMP_TYPE_VALUE 0x44570140
|
||||
|
||||
#define DW_IC_INTR_RX_UNDER 0x001
|
||||
#define DW_IC_INTR_RX_OVER 0x002
|
||||
#define DW_IC_INTR_RX_FULL 0x004
|
||||
#define DW_IC_INTR_TX_OVER 0x008
|
||||
#define DW_IC_INTR_TX_EMPTY 0x010
|
||||
#define DW_IC_INTR_RD_REQ 0x020
|
||||
#define DW_IC_INTR_TX_ABRT 0x040
|
||||
#define DW_IC_INTR_RX_DONE 0x080
|
||||
#define DW_IC_INTR_ACTIVITY 0x100
|
||||
#define DW_IC_INTR_STOP_DET 0x200
|
||||
#define DW_IC_INTR_START_DET 0x400
|
||||
#define DW_IC_INTR_GEN_CALL 0x800
|
||||
#define DW_IC_INTR_RESTART_DET 0x1000
|
||||
#define DW_IC_INTR_RX_UNDER BIT(0)
|
||||
#define DW_IC_INTR_RX_OVER BIT(1)
|
||||
#define DW_IC_INTR_RX_FULL BIT(2)
|
||||
#define DW_IC_INTR_TX_OVER BIT(3)
|
||||
#define DW_IC_INTR_TX_EMPTY BIT(4)
|
||||
#define DW_IC_INTR_RD_REQ BIT(5)
|
||||
#define DW_IC_INTR_TX_ABRT BIT(6)
|
||||
#define DW_IC_INTR_RX_DONE BIT(7)
|
||||
#define DW_IC_INTR_ACTIVITY BIT(8)
|
||||
#define DW_IC_INTR_STOP_DET BIT(9)
|
||||
#define DW_IC_INTR_START_DET BIT(10)
|
||||
#define DW_IC_INTR_GEN_CALL BIT(11)
|
||||
#define DW_IC_INTR_RESTART_DET BIT(12)
|
||||
|
||||
#define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \
|
||||
DW_IC_INTR_TX_ABRT | \
|
||||
|
|
@ -105,13 +105,13 @@
|
|||
DW_IC_INTR_RX_UNDER | \
|
||||
DW_IC_INTR_RD_REQ)
|
||||
|
||||
#define DW_IC_STATUS_ACTIVITY 0x1
|
||||
#define DW_IC_STATUS_ACTIVITY BIT(0)
|
||||
#define DW_IC_STATUS_TFE BIT(2)
|
||||
#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5)
|
||||
#define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6)
|
||||
|
||||
#define DW_IC_SDA_HOLD_RX_SHIFT 16
|
||||
#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, DW_IC_SDA_HOLD_RX_SHIFT)
|
||||
#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, 16)
|
||||
|
||||
#define DW_IC_ERR_TX_ABRT 0x1
|
||||
|
||||
|
|
@ -154,20 +154,20 @@
|
|||
#define ABRT_SLAVE_ARBLOST 14
|
||||
#define ABRT_SLAVE_RD_INTX 15
|
||||
|
||||
#define DW_IC_TX_ABRT_7B_ADDR_NOACK (1UL << ABRT_7B_ADDR_NOACK)
|
||||
#define DW_IC_TX_ABRT_10ADDR1_NOACK (1UL << ABRT_10ADDR1_NOACK)
|
||||
#define DW_IC_TX_ABRT_10ADDR2_NOACK (1UL << ABRT_10ADDR2_NOACK)
|
||||
#define DW_IC_TX_ABRT_TXDATA_NOACK (1UL << ABRT_TXDATA_NOACK)
|
||||
#define DW_IC_TX_ABRT_GCALL_NOACK (1UL << ABRT_GCALL_NOACK)
|
||||
#define DW_IC_TX_ABRT_GCALL_READ (1UL << ABRT_GCALL_READ)
|
||||
#define DW_IC_TX_ABRT_SBYTE_ACKDET (1UL << ABRT_SBYTE_ACKDET)
|
||||
#define DW_IC_TX_ABRT_SBYTE_NORSTRT (1UL << ABRT_SBYTE_NORSTRT)
|
||||
#define DW_IC_TX_ABRT_10B_RD_NORSTRT (1UL << ABRT_10B_RD_NORSTRT)
|
||||
#define DW_IC_TX_ABRT_MASTER_DIS (1UL << ABRT_MASTER_DIS)
|
||||
#define DW_IC_TX_ARB_LOST (1UL << ARB_LOST)
|
||||
#define DW_IC_RX_ABRT_SLAVE_RD_INTX (1UL << ABRT_SLAVE_RD_INTX)
|
||||
#define DW_IC_RX_ABRT_SLAVE_ARBLOST (1UL << ABRT_SLAVE_ARBLOST)
|
||||
#define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO (1UL << ABRT_SLAVE_FLUSH_TXFIFO)
|
||||
#define DW_IC_TX_ABRT_7B_ADDR_NOACK BIT(ABRT_7B_ADDR_NOACK)
|
||||
#define DW_IC_TX_ABRT_10ADDR1_NOACK BIT(ABRT_10ADDR1_NOACK)
|
||||
#define DW_IC_TX_ABRT_10ADDR2_NOACK BIT(ABRT_10ADDR2_NOACK)
|
||||
#define DW_IC_TX_ABRT_TXDATA_NOACK BIT(ABRT_TXDATA_NOACK)
|
||||
#define DW_IC_TX_ABRT_GCALL_NOACK BIT(ABRT_GCALL_NOACK)
|
||||
#define DW_IC_TX_ABRT_GCALL_READ BIT(ABRT_GCALL_READ)
|
||||
#define DW_IC_TX_ABRT_SBYTE_ACKDET BIT(ABRT_SBYTE_ACKDET)
|
||||
#define DW_IC_TX_ABRT_SBYTE_NORSTRT BIT(ABRT_SBYTE_NORSTRT)
|
||||
#define DW_IC_TX_ABRT_10B_RD_NORSTRT BIT(ABRT_10B_RD_NORSTRT)
|
||||
#define DW_IC_TX_ABRT_MASTER_DIS BIT(ABRT_MASTER_DIS)
|
||||
#define DW_IC_TX_ARB_LOST BIT(ARB_LOST)
|
||||
#define DW_IC_RX_ABRT_SLAVE_RD_INTX BIT(ABRT_SLAVE_RD_INTX)
|
||||
#define DW_IC_RX_ABRT_SLAVE_ARBLOST BIT(ABRT_SLAVE_ARBLOST)
|
||||
#define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO BIT(ABRT_SLAVE_FLUSH_TXFIFO)
|
||||
|
||||
#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \
|
||||
DW_IC_TX_ABRT_10ADDR1_NOACK | \
|
||||
|
|
@ -288,12 +288,12 @@ struct dw_i2c_dev {
|
|||
bool suspended;
|
||||
};
|
||||
|
||||
#define ACCESS_INTR_MASK 0x00000001
|
||||
#define ACCESS_NO_IRQ_SUSPEND 0x00000002
|
||||
#define ACCESS_INTR_MASK BIT(0)
|
||||
#define ACCESS_NO_IRQ_SUSPEND BIT(1)
|
||||
|
||||
#define MODEL_MSCC_OCELOT 0x00000100
|
||||
#define MODEL_BAIKAL_BT1 0x00000200
|
||||
#define MODEL_MASK 0x00000f00
|
||||
#define MODEL_MSCC_OCELOT BIT(8)
|
||||
#define MODEL_BAIKAL_BT1 BIT(9)
|
||||
#define MODEL_MASK GENMASK(11, 8)
|
||||
|
||||
int i2c_dw_init_regmap(struct dw_i2c_dev *dev);
|
||||
u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset);
|
||||
|
|
|
|||
|
|
@ -778,11 +778,8 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
|
|||
init_completion(&i2c->msg_complete);
|
||||
|
||||
i2c->irq = ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
dev_err(&pdev->dev, "cannot find HS-I2C IRQ\n");
|
||||
ret = -EINVAL;
|
||||
if (ret < 0)
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, i2c->irq, exynos5_i2c_irq,
|
||||
IRQF_NO_SUSPEND, dev_name(&pdev->dev), i2c);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
* Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt>
|
||||
*
|
||||
* Copyright 2013 Freescale Semiconductor, Inc.
|
||||
* Copyright 2020 NXP
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -73,6 +74,11 @@
|
|||
#define IMX_I2C_I2SR 0x03 /* i2c status */
|
||||
#define IMX_I2C_I2DR 0x04 /* i2c transfer data */
|
||||
|
||||
/*
|
||||
* All of the layerscape series SoCs support IBIC register.
|
||||
*/
|
||||
#define IMX_I2C_IBIC 0x05 /* i2c bus interrupt config */
|
||||
|
||||
#define IMX_I2C_REGSHIFT 2
|
||||
#define VF610_I2C_REGSHIFT 0
|
||||
|
||||
|
|
@ -91,6 +97,7 @@
|
|||
#define I2CR_MSTA 0x20
|
||||
#define I2CR_IIEN 0x40
|
||||
#define I2CR_IEN 0x80
|
||||
#define IBIC_BIIE 0x80 /* Bus idle interrupt enable */
|
||||
|
||||
/* register bits different operating codes definition:
|
||||
* 1) I2SR: Interrupt flags clear operation differ between SoCs:
|
||||
|
|
@ -201,6 +208,7 @@ struct imx_i2c_struct {
|
|||
struct pinctrl_state *pinctrl_pins_gpio;
|
||||
|
||||
struct imx_i2c_dma *dma;
|
||||
struct i2c_client *slave;
|
||||
};
|
||||
|
||||
static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
|
||||
|
|
@ -233,19 +241,6 @@ static struct imx_i2c_hwdata vf610_i2c_hwdata = {
|
|||
|
||||
};
|
||||
|
||||
static const struct platform_device_id imx_i2c_devtype[] = {
|
||||
{
|
||||
.name = "imx1-i2c",
|
||||
.driver_data = (kernel_ulong_t)&imx1_i2c_hwdata,
|
||||
}, {
|
||||
.name = "imx21-i2c",
|
||||
.driver_data = (kernel_ulong_t)&imx21_i2c_hwdata,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, imx_i2c_devtype);
|
||||
|
||||
static const struct of_device_id i2c_imx_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
|
||||
{ .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
|
||||
|
|
@ -265,6 +260,11 @@ static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx)
|
|||
return i2c_imx->hwdata->devtype == IMX1_I2C;
|
||||
}
|
||||
|
||||
static inline int is_vf610_i2c(struct imx_i2c_struct *i2c_imx)
|
||||
{
|
||||
return i2c_imx->hwdata->devtype == VF610_I2C;
|
||||
}
|
||||
|
||||
static inline void imx_i2c_write_reg(unsigned int val,
|
||||
struct imx_i2c_struct *i2c_imx, unsigned int reg)
|
||||
{
|
||||
|
|
@ -277,6 +277,27 @@ static inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx,
|
|||
return readb(i2c_imx->base + (reg << i2c_imx->hwdata->regshift));
|
||||
}
|
||||
|
||||
static void i2c_imx_clear_irq(struct imx_i2c_struct *i2c_imx, unsigned int bits)
|
||||
{
|
||||
unsigned int temp;
|
||||
|
||||
/*
|
||||
* i2sr_clr_opcode is the value to clear all interrupts. Here we want to
|
||||
* clear only <bits>, so we write ~i2sr_clr_opcode with just <bits>
|
||||
* toggled. This is required because i.MX needs W0C and Vybrid uses W1C.
|
||||
*/
|
||||
temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ bits;
|
||||
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
|
||||
}
|
||||
|
||||
/* Set up i2c controller register and i2c status register to default value. */
|
||||
static void i2c_imx_reset_regs(struct imx_i2c_struct *i2c_imx)
|
||||
{
|
||||
imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
|
||||
i2c_imx, IMX_I2C_I2CR);
|
||||
i2c_imx_clear_irq(i2c_imx, I2SR_IIF | I2SR_IAL);
|
||||
}
|
||||
|
||||
/* Functions for DMA support */
|
||||
static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
|
||||
dma_addr_t phy_addr)
|
||||
|
|
@ -412,19 +433,6 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
|
|||
dma->chan_using = NULL;
|
||||
}
|
||||
|
||||
static void i2c_imx_clear_irq(struct imx_i2c_struct *i2c_imx, unsigned int bits)
|
||||
{
|
||||
unsigned int temp;
|
||||
|
||||
/*
|
||||
* i2sr_clr_opcode is the value to clear all interrupts. Here we want to
|
||||
* clear only <bits>, so we write ~i2sr_clr_opcode with just <bits>
|
||||
* toggled. This is required because i.MX needs W0C and Vybrid uses W1C.
|
||||
*/
|
||||
temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ bits;
|
||||
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
|
||||
}
|
||||
|
||||
static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool atomic)
|
||||
{
|
||||
unsigned long orig_jiffies = jiffies;
|
||||
|
|
@ -638,18 +646,165 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx, bool atomic)
|
|||
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable bus idle interrupts
|
||||
* Note: IBIC register will be cleared after disabled i2c module.
|
||||
* All of layerscape series SoCs support IBIC register.
|
||||
*/
|
||||
static void i2c_imx_enable_bus_idle(struct imx_i2c_struct *i2c_imx)
|
||||
{
|
||||
if (is_vf610_i2c(i2c_imx)) {
|
||||
unsigned int temp;
|
||||
|
||||
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_IBIC);
|
||||
temp |= IBIC_BIIE;
|
||||
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_IBIC);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx,
|
||||
unsigned int status, unsigned int ctl)
|
||||
{
|
||||
u8 value;
|
||||
|
||||
if (status & I2SR_IAL) { /* Arbitration lost */
|
||||
i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
|
||||
if (!(status & I2SR_IAAS))
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (status & I2SR_IAAS) { /* Addressed as a slave */
|
||||
if (status & I2SR_SRW) { /* Master wants to read from us*/
|
||||
dev_dbg(&i2c_imx->adapter.dev, "read requested");
|
||||
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_REQUESTED, &value);
|
||||
|
||||
/* Slave transmit */
|
||||
ctl |= I2CR_MTX;
|
||||
imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
|
||||
|
||||
/* Send data */
|
||||
imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
|
||||
} else { /* Master wants to write to us */
|
||||
dev_dbg(&i2c_imx->adapter.dev, "write requested");
|
||||
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
|
||||
|
||||
/* Slave receive */
|
||||
ctl &= ~I2CR_MTX;
|
||||
imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
|
||||
/* Dummy read */
|
||||
imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
|
||||
}
|
||||
} else if (!(ctl & I2CR_MTX)) { /* Receive mode */
|
||||
if (status & I2SR_IBB) { /* No STOP signal detected */
|
||||
value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
|
||||
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
|
||||
} else { /* STOP signal is detected */
|
||||
dev_dbg(&i2c_imx->adapter.dev,
|
||||
"STOP signal detected");
|
||||
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, &value);
|
||||
}
|
||||
} else if (!(status & I2SR_RXAK)) { /* Transmit mode received ACK */
|
||||
ctl |= I2CR_MTX;
|
||||
imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
|
||||
|
||||
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_PROCESSED, &value);
|
||||
|
||||
imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
|
||||
} else { /* Transmit mode received NAK */
|
||||
ctl &= ~I2CR_MTX;
|
||||
imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
|
||||
imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void i2c_imx_slave_init(struct imx_i2c_struct *i2c_imx)
|
||||
{
|
||||
int temp;
|
||||
|
||||
/* Set slave addr. */
|
||||
imx_i2c_write_reg((i2c_imx->slave->addr << 1), i2c_imx, IMX_I2C_IADR);
|
||||
|
||||
i2c_imx_reset_regs(i2c_imx);
|
||||
|
||||
/* Enable module */
|
||||
temp = i2c_imx->hwdata->i2cr_ien_opcode;
|
||||
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
|
||||
|
||||
/* Enable interrupt from i2c module */
|
||||
temp |= I2CR_IIEN;
|
||||
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
|
||||
|
||||
i2c_imx_enable_bus_idle(i2c_imx);
|
||||
}
|
||||
|
||||
static int i2c_imx_reg_slave(struct i2c_client *client)
|
||||
{
|
||||
struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter);
|
||||
int ret;
|
||||
|
||||
if (i2c_imx->slave)
|
||||
return -EBUSY;
|
||||
|
||||
i2c_imx->slave = client;
|
||||
|
||||
/* Resume */
|
||||
ret = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
|
||||
if (ret < 0) {
|
||||
dev_err(&i2c_imx->adapter.dev, "failed to resume i2c controller");
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_imx_slave_init(i2c_imx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_imx_unreg_slave(struct i2c_client *client)
|
||||
{
|
||||
struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter);
|
||||
int ret;
|
||||
|
||||
if (!i2c_imx->slave)
|
||||
return -EINVAL;
|
||||
|
||||
/* Reset slave address. */
|
||||
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
|
||||
|
||||
i2c_imx_reset_regs(i2c_imx);
|
||||
|
||||
i2c_imx->slave = NULL;
|
||||
|
||||
/* Suspend */
|
||||
ret = pm_runtime_put_sync(i2c_imx->adapter.dev.parent);
|
||||
if (ret < 0)
|
||||
dev_err(&i2c_imx->adapter.dev, "failed to suspend i2c controller");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned int status)
|
||||
{
|
||||
/* save status register */
|
||||
i2c_imx->i2csr = status;
|
||||
wake_up(&i2c_imx->queue);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct imx_i2c_struct *i2c_imx = dev_id;
|
||||
unsigned int temp;
|
||||
unsigned int ctl, status;
|
||||
|
||||
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
|
||||
if (temp & I2SR_IIF) {
|
||||
/* save status register */
|
||||
i2c_imx->i2csr = temp;
|
||||
status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
|
||||
ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
|
||||
if (status & I2SR_IIF) {
|
||||
i2c_imx_clear_irq(i2c_imx, I2SR_IIF);
|
||||
wake_up(&i2c_imx->queue);
|
||||
return IRQ_HANDLED;
|
||||
if (i2c_imx->slave && !(ctl & I2CR_MSTA))
|
||||
return i2c_imx_slave_isr(i2c_imx, status, ctl);
|
||||
return i2c_imx_master_isr(i2c_imx, status);
|
||||
}
|
||||
|
||||
return IRQ_NONE;
|
||||
|
|
@ -1027,6 +1182,10 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
|
|||
dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
|
||||
(result < 0) ? "error" : "success msg",
|
||||
(result < 0) ? result : num);
|
||||
/* After data is transferred, switch to slave mode(as a receiver) */
|
||||
if (i2c_imx->slave)
|
||||
i2c_imx_slave_init(i2c_imx);
|
||||
|
||||
return (result < 0) ? result : num;
|
||||
}
|
||||
|
||||
|
|
@ -1140,6 +1299,8 @@ static const struct i2c_algorithm i2c_imx_algo = {
|
|||
.master_xfer = i2c_imx_xfer,
|
||||
.master_xfer_atomic = i2c_imx_xfer_atomic,
|
||||
.functionality = i2c_imx_func,
|
||||
.reg_slave = i2c_imx_reg_slave,
|
||||
.unreg_slave = i2c_imx_unreg_slave,
|
||||
};
|
||||
|
||||
static int i2c_imx_probe(struct platform_device *pdev)
|
||||
|
|
@ -1169,11 +1330,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
match = device_get_match_data(&pdev->dev);
|
||||
if (match)
|
||||
i2c_imx->hwdata = match;
|
||||
else
|
||||
i2c_imx->hwdata = (struct imx_i2c_hwdata *)
|
||||
platform_get_device_id(pdev)->driver_data;
|
||||
i2c_imx->hwdata = match;
|
||||
|
||||
/* Setup i2c_imx driver structure */
|
||||
strlcpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name));
|
||||
|
|
@ -1233,10 +1390,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
|
|||
clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb);
|
||||
i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
|
||||
|
||||
/* Set up chip registers to defaults */
|
||||
imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
|
||||
i2c_imx, IMX_I2C_I2CR);
|
||||
imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
|
||||
i2c_imx_reset_regs(i2c_imx);
|
||||
|
||||
/* Init optional bus recovery function */
|
||||
ret = i2c_imx_init_recovery_info(i2c_imx, pdev);
|
||||
|
|
@ -1344,7 +1498,6 @@ static struct platform_driver i2c_imx_driver = {
|
|||
.of_match_table = i2c_imx_dt_ids,
|
||||
.acpi_match_table = i2c_imx_acpi_ids,
|
||||
},
|
||||
.id_table = imx_i2c_devtype,
|
||||
};
|
||||
|
||||
static int __init i2c_adap_imx_init(void)
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@
|
|||
* Features supported by this driver:
|
||||
* Hardware PEC yes
|
||||
* Block buffer yes
|
||||
* Block process call transaction no
|
||||
* Block process call transaction yes
|
||||
* Slave mode no
|
||||
*/
|
||||
|
||||
|
|
@ -332,7 +332,8 @@ static int ismt_process_desc(const struct ismt_desc *desc,
|
|||
|
||||
if (desc->status & ISMT_DESC_SCS) {
|
||||
if (read_write == I2C_SMBUS_WRITE &&
|
||||
size != I2C_SMBUS_PROC_CALL)
|
||||
size != I2C_SMBUS_PROC_CALL &&
|
||||
size != I2C_SMBUS_BLOCK_PROC_CALL)
|
||||
return 0;
|
||||
|
||||
switch (size) {
|
||||
|
|
@ -345,6 +346,7 @@ static int ismt_process_desc(const struct ismt_desc *desc,
|
|||
data->word = dma_buffer[0] | (dma_buffer[1] << 8);
|
||||
break;
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
case I2C_SMBUS_BLOCK_PROC_CALL:
|
||||
if (desc->rxbytes != dma_buffer[0] + 1)
|
||||
return -EMSGSIZE;
|
||||
|
||||
|
|
@ -518,6 +520,18 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
|
|||
}
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_PROC_CALL:
|
||||
dev_dbg(dev, "I2C_SMBUS_BLOCK_PROC_CALL\n");
|
||||
dma_size = I2C_SMBUS_BLOCK_MAX;
|
||||
desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 1);
|
||||
desc->wr_len_cmd = data->block[0] + 1;
|
||||
desc->rd_len = dma_size;
|
||||
desc->control |= ISMT_DESC_BLK;
|
||||
dma_direction = DMA_BIDIRECTIONAL;
|
||||
dma_buffer[0] = command;
|
||||
memcpy(&dma_buffer[1], &data->block[1], data->block[0]);
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
/* Make sure the length is valid */
|
||||
if (data->block[0] < 1)
|
||||
|
|
@ -624,6 +638,7 @@ static u32 ismt_func(struct i2c_adapter *adap)
|
|||
I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_PROC_CALL |
|
||||
I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK |
|
||||
I2C_FUNC_SMBUS_PEC;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/mv643xx_i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
|
|
@ -147,6 +148,7 @@ struct mv64xxx_i2c_data {
|
|||
bool irq_clear_inverted;
|
||||
/* Clk div is 2 to the power n, not 2 to the power n + 1 */
|
||||
bool clk_n_base_0;
|
||||
struct i2c_bus_recovery_info rinfo;
|
||||
};
|
||||
|
||||
static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
|
||||
|
|
@ -325,7 +327,8 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
|
|||
drv_data->msg->flags);
|
||||
drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
|
||||
mv64xxx_i2c_hw_init(drv_data);
|
||||
drv_data->rc = -EIO;
|
||||
i2c_recover_bus(&drv_data->adapter);
|
||||
drv_data->rc = -EAGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -561,6 +564,7 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data)
|
|||
"time_left: %d\n", drv_data->block,
|
||||
(int)time_left);
|
||||
mv64xxx_i2c_hw_init(drv_data);
|
||||
i2c_recover_bus(&drv_data->adapter);
|
||||
}
|
||||
} else
|
||||
spin_unlock_irqrestore(&drv_data->lock, flags);
|
||||
|
|
@ -870,6 +874,25 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
|
|||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static int mv64xxx_i2c_init_recovery_info(struct mv64xxx_i2c_data *drv_data,
|
||||
struct device *dev)
|
||||
{
|
||||
struct i2c_bus_recovery_info *rinfo = &drv_data->rinfo;
|
||||
|
||||
rinfo->pinctrl = devm_pinctrl_get(dev);
|
||||
if (IS_ERR(rinfo->pinctrl)) {
|
||||
if (PTR_ERR(rinfo->pinctrl) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
dev_info(dev, "can't get pinctrl, bus recovery not supported\n");
|
||||
return PTR_ERR(rinfo->pinctrl);
|
||||
} else if (!rinfo->pinctrl) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
drv_data->adapter.bus_recovery_info = rinfo;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mv64xxx_i2c_probe(struct platform_device *pd)
|
||||
{
|
||||
|
|
@ -926,6 +949,10 @@ mv64xxx_i2c_probe(struct platform_device *pd)
|
|||
goto exit_reset;
|
||||
}
|
||||
|
||||
rc = mv64xxx_i2c_init_recovery_info(drv_data, &pd->dev);
|
||||
if (rc == -EPROBE_DEFER)
|
||||
goto exit_reset;
|
||||
|
||||
drv_data->adapter.dev.parent = &pd->dev;
|
||||
drv_data->adapter.algo = &mv64xxx_i2c_algo;
|
||||
drv_data->adapter.owner = THIS_MODULE;
|
||||
|
|
|
|||
|
|
@ -781,28 +781,15 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id mxs_i2c_devtype[] = {
|
||||
{
|
||||
.name = "imx23-i2c",
|
||||
.driver_data = MXS_I2C_V1,
|
||||
}, {
|
||||
.name = "imx28-i2c",
|
||||
.driver_data = MXS_I2C_V2,
|
||||
}, { /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, mxs_i2c_devtype);
|
||||
|
||||
static const struct of_device_id mxs_i2c_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx23-i2c", .data = &mxs_i2c_devtype[0], },
|
||||
{ .compatible = "fsl,imx28-i2c", .data = &mxs_i2c_devtype[1], },
|
||||
{ .compatible = "fsl,imx23-i2c", .data = (void *)MXS_I2C_V1, },
|
||||
{ .compatible = "fsl,imx28-i2c", .data = (void *)MXS_I2C_V2, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mxs_i2c_dt_ids);
|
||||
|
||||
static int mxs_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(mxs_i2c_dt_ids, &pdev->dev);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mxs_i2c_dev *i2c;
|
||||
struct i2c_adapter *adap;
|
||||
|
|
@ -812,10 +799,7 @@ static int mxs_i2c_probe(struct platform_device *pdev)
|
|||
if (!i2c)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_id) {
|
||||
const struct platform_device_id *device_id = of_id->data;
|
||||
i2c->dev_type = device_id->driver_data;
|
||||
}
|
||||
i2c->dev_type = (enum mxs_i2c_devtype)of_device_get_match_data(&pdev->dev);
|
||||
|
||||
i2c->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(i2c->regs))
|
||||
|
|
|
|||
|
|
@ -353,15 +353,7 @@ static void gpu_i2c_remove(struct pci_dev *pdev)
|
|||
pci_free_irq_vectors(pdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* We need gpu_i2c_suspend() even if it is stub, for runtime pm to work
|
||||
* correctly. Without it, lspci shows runtime pm status as "D0" for the card.
|
||||
* Documentation/power/pci.rst also insists for driver to provide this.
|
||||
*/
|
||||
static __maybe_unused int gpu_i2c_suspend(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#define gpu_i2c_suspend NULL
|
||||
|
||||
static __maybe_unused int gpu_i2c_resume(struct device *dev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -83,7 +83,6 @@ struct ocores_i2c {
|
|||
|
||||
#define TYPE_OCORES 0
|
||||
#define TYPE_GRLIB 1
|
||||
#define TYPE_SIFIVE_REV0 2
|
||||
|
||||
#define OCORES_FLAG_BROKEN_IRQ BIT(1) /* Broken IRQ for FU540-C000 SoC */
|
||||
|
||||
|
|
@ -476,11 +475,9 @@ static const struct of_device_id ocores_i2c_match[] = {
|
|||
},
|
||||
{
|
||||
.compatible = "sifive,fu540-c000-i2c",
|
||||
.data = (void *)TYPE_SIFIVE_REV0,
|
||||
},
|
||||
{
|
||||
.compatible = "sifive,i2c0",
|
||||
.data = (void *)TYPE_SIFIVE_REV0,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
|
@ -606,7 +603,6 @@ static int ocores_i2c_probe(struct platform_device *pdev)
|
|||
{
|
||||
struct ocores_i2c *i2c;
|
||||
struct ocores_i2c_platform_data *pdata;
|
||||
const struct of_device_id *match;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int ret;
|
||||
|
|
@ -686,17 +682,20 @@ static int ocores_i2c_probe(struct platform_device *pdev)
|
|||
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
irq = platform_get_irq_optional(pdev, 0);
|
||||
/*
|
||||
* Since the SoC does have an interrupt, its DT has an interrupt
|
||||
* property - But this should be bypassed as the IRQ logic in this
|
||||
* SoC is broken.
|
||||
*/
|
||||
if (of_device_is_compatible(pdev->dev.of_node,
|
||||
"sifive,fu540-c000-i2c")) {
|
||||
i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
|
||||
irq = -ENXIO;
|
||||
}
|
||||
|
||||
if (irq == -ENXIO) {
|
||||
ocores_algorithm.master_xfer = ocores_xfer_polling;
|
||||
|
||||
/*
|
||||
* Set in OCORES_FLAG_BROKEN_IRQ to enable workaround for
|
||||
* FU540-C000 SoC in polling mode.
|
||||
*/
|
||||
match = of_match_node(ocores_i2c_match, pdev->dev.of_node);
|
||||
if (match && (long)match->data == TYPE_SIFIVE_REV0)
|
||||
i2c->flags |= OCORES_FLAG_BROKEN_IRQ;
|
||||
} else {
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
|
|
@ -76,6 +77,7 @@
|
|||
#define OWL_I2C_FIFOCTL_TFR BIT(2)
|
||||
|
||||
/* I2Cc_FIFOSTAT Bit Mask */
|
||||
#define OWL_I2C_FIFOSTAT_CECB BIT(0)
|
||||
#define OWL_I2C_FIFOSTAT_RNB BIT(1)
|
||||
#define OWL_I2C_FIFOSTAT_RFE BIT(2)
|
||||
#define OWL_I2C_FIFOSTAT_TFF BIT(5)
|
||||
|
|
@ -83,7 +85,8 @@
|
|||
#define OWL_I2C_FIFOSTAT_RFD GENMASK(15, 8)
|
||||
|
||||
/* I2C bus timeout */
|
||||
#define OWL_I2C_TIMEOUT msecs_to_jiffies(4 * 1000)
|
||||
#define OWL_I2C_TIMEOUT_MS (4 * 1000)
|
||||
#define OWL_I2C_TIMEOUT msecs_to_jiffies(OWL_I2C_TIMEOUT_MS)
|
||||
|
||||
#define OWL_I2C_MAX_RETRIES 50
|
||||
|
||||
|
|
@ -161,14 +164,11 @@ static void owl_i2c_set_freq(struct owl_i2c_dev *i2c_dev)
|
|||
writel(OWL_I2C_DIV_FACTOR(val), i2c_dev->base + OWL_I2C_REG_CLKDIV);
|
||||
}
|
||||
|
||||
static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
|
||||
static void owl_i2c_xfer_data(struct owl_i2c_dev *i2c_dev)
|
||||
{
|
||||
struct owl_i2c_dev *i2c_dev = _dev;
|
||||
struct i2c_msg *msg = i2c_dev->msg;
|
||||
unsigned int stat, fifostat;
|
||||
|
||||
spin_lock(&i2c_dev->lock);
|
||||
|
||||
i2c_dev->err = 0;
|
||||
|
||||
/* Handle NACK from slave */
|
||||
|
|
@ -178,7 +178,7 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
|
|||
/* Clear NACK error bit by writing "1" */
|
||||
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
|
||||
OWL_I2C_FIFOSTAT_RNB, true);
|
||||
goto stop;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle bus error */
|
||||
|
|
@ -188,7 +188,7 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
|
|||
/* Clear BUS error bit by writing "1" */
|
||||
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
|
||||
OWL_I2C_STAT_BEB, true);
|
||||
goto stop;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle FIFO read */
|
||||
|
|
@ -206,8 +206,16 @@ static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
|
|||
i2c_dev->base + OWL_I2C_REG_TXDAT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t owl_i2c_interrupt(int irq, void *_dev)
|
||||
{
|
||||
struct owl_i2c_dev *i2c_dev = _dev;
|
||||
|
||||
spin_lock(&i2c_dev->lock);
|
||||
|
||||
owl_i2c_xfer_data(i2c_dev);
|
||||
|
||||
stop:
|
||||
/* Clear pending interrupts */
|
||||
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_STAT,
|
||||
OWL_I2C_STAT_IRQP, true);
|
||||
|
|
@ -240,8 +248,8 @@ static int owl_i2c_check_bus_busy(struct i2c_adapter *adap)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num)
|
||||
static int owl_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num, bool atomic)
|
||||
{
|
||||
struct owl_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
|
||||
struct i2c_msg *msg;
|
||||
|
|
@ -285,11 +293,12 @@ static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||
goto err_exit;
|
||||
}
|
||||
|
||||
reinit_completion(&i2c_dev->msg_complete);
|
||||
if (!atomic)
|
||||
reinit_completion(&i2c_dev->msg_complete);
|
||||
|
||||
/* Enable I2C controller interrupt */
|
||||
/* Enable/disable I2C controller interrupt */
|
||||
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
|
||||
OWL_I2C_CTL_IRQE, true);
|
||||
OWL_I2C_CTL_IRQE, !atomic);
|
||||
|
||||
/*
|
||||
* Select: FIFO enable, Master mode, Stop enable, Data count enable,
|
||||
|
|
@ -357,20 +366,33 @@ static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||
|
||||
spin_unlock_irqrestore(&i2c_dev->lock, flags);
|
||||
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
|
||||
adap->timeout);
|
||||
if (atomic) {
|
||||
/* Wait for Command Execute Completed or NACK Error bits */
|
||||
ret = readl_poll_timeout_atomic(i2c_dev->base + OWL_I2C_REG_FIFOSTAT,
|
||||
val, val & (OWL_I2C_FIFOSTAT_CECB |
|
||||
OWL_I2C_FIFOSTAT_RNB),
|
||||
10, OWL_I2C_TIMEOUT_MS * 1000);
|
||||
} else {
|
||||
time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
|
||||
adap->timeout);
|
||||
if (!time_left)
|
||||
ret = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&i2c_dev->lock, flags);
|
||||
if (time_left == 0) {
|
||||
|
||||
if (ret) {
|
||||
dev_err(&adap->dev, "Transaction timed out\n");
|
||||
/* Send stop condition and release the bus */
|
||||
owl_i2c_update_reg(i2c_dev->base + OWL_I2C_REG_CTL,
|
||||
OWL_I2C_CTL_GBCC_STOP | OWL_I2C_CTL_RB,
|
||||
true);
|
||||
ret = -ETIMEDOUT;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
if (atomic)
|
||||
owl_i2c_xfer_data(i2c_dev);
|
||||
|
||||
ret = i2c_dev->err < 0 ? i2c_dev->err : num;
|
||||
|
||||
err_exit:
|
||||
|
|
@ -384,9 +406,22 @@ static int owl_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int owl_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
||||
int num)
|
||||
{
|
||||
return owl_i2c_xfer_common(adap, msgs, num, false);
|
||||
}
|
||||
|
||||
static int owl_i2c_xfer_atomic(struct i2c_adapter *adap,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
return owl_i2c_xfer_common(adap, msgs, num, true);
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm owl_i2c_algorithm = {
|
||||
.master_xfer = owl_i2c_master_xfer,
|
||||
.functionality = owl_i2c_func,
|
||||
.master_xfer = owl_i2c_xfer,
|
||||
.master_xfer_atomic = owl_i2c_xfer_atomic,
|
||||
.functionality = owl_i2c_func,
|
||||
};
|
||||
|
||||
static const struct i2c_adapter_quirks owl_i2c_quirks = {
|
||||
|
|
@ -473,6 +508,7 @@ static int owl_i2c_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
static const struct of_device_id owl_i2c_of_match[] = {
|
||||
{ .compatible = "actions,s500-i2c" },
|
||||
{ .compatible = "actions,s700-i2c" },
|
||||
{ .compatible = "actions,s900-i2c" },
|
||||
{ /* sentinel */ }
|
||||
|
|
@ -484,6 +520,7 @@ static struct platform_driver owl_i2c_driver = {
|
|||
.driver = {
|
||||
.name = "owl-i2c",
|
||||
.of_match_table = of_match_ptr(owl_i2c_of_match),
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
},
|
||||
};
|
||||
module_platform_driver(owl_i2c_driver);
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@ struct i2c_pca_pf_data {
|
|||
wait_queue_head_t wait;
|
||||
struct i2c_adapter adap;
|
||||
struct i2c_algo_pca_data algo_data;
|
||||
unsigned long io_base;
|
||||
unsigned long io_size;
|
||||
};
|
||||
|
||||
/* Read/Write functions for different register alignments */
|
||||
|
|
@ -156,8 +154,6 @@ static int i2c_pca_pf_probe(struct platform_device *pdev)
|
|||
|
||||
init_waitqueue_head(&i2c->wait);
|
||||
|
||||
i2c->io_base = res->start;
|
||||
i2c->io_size = resource_size(res);
|
||||
i2c->irq = irq;
|
||||
|
||||
i2c->adap.nr = pdev->id;
|
||||
|
|
|
|||
|
|
@ -264,9 +264,6 @@ struct pxa_i2c {
|
|||
u32 hs_mask;
|
||||
|
||||
struct i2c_bus_recovery_info recovery;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pinctrl_default;
|
||||
struct pinctrl_state *pinctrl_recovery;
|
||||
};
|
||||
|
||||
#define _IBMR(i2c) ((i2c)->reg_ibmr)
|
||||
|
|
@ -1305,13 +1302,12 @@ static void i2c_pxa_prepare_recovery(struct i2c_adapter *adap)
|
|||
*/
|
||||
gpiod_set_value(i2c->recovery.scl_gpiod, ibmr & IBMR_SCLS);
|
||||
gpiod_set_value(i2c->recovery.sda_gpiod, ibmr & IBMR_SDAS);
|
||||
|
||||
WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery));
|
||||
}
|
||||
|
||||
static void i2c_pxa_unprepare_recovery(struct i2c_adapter *adap)
|
||||
{
|
||||
struct pxa_i2c *i2c = adap->algo_data;
|
||||
struct i2c_bus_recovery_info *bri = adap->bus_recovery_info;
|
||||
u32 isr;
|
||||
|
||||
/*
|
||||
|
|
@ -1325,7 +1321,7 @@ static void i2c_pxa_unprepare_recovery(struct i2c_adapter *adap)
|
|||
i2c_pxa_do_reset(i2c);
|
||||
}
|
||||
|
||||
WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default));
|
||||
WARN_ON(pinctrl_select_state(bri->pinctrl, bri->pins_default));
|
||||
|
||||
dev_dbg(&i2c->adap.dev, "recovery: IBMR 0x%08x ISR 0x%08x\n",
|
||||
readl(_IBMR(i2c)), readl(_ISR(i2c)));
|
||||
|
|
@ -1347,76 +1343,20 @@ static int i2c_pxa_init_recovery(struct pxa_i2c *i2c)
|
|||
if (IS_ENABLED(CONFIG_I2C_PXA_SLAVE))
|
||||
return 0;
|
||||
|
||||
i2c->pinctrl = devm_pinctrl_get(dev);
|
||||
if (PTR_ERR(i2c->pinctrl) == -ENODEV)
|
||||
i2c->pinctrl = NULL;
|
||||
if (IS_ERR(i2c->pinctrl))
|
||||
return PTR_ERR(i2c->pinctrl);
|
||||
|
||||
if (!i2c->pinctrl)
|
||||
return 0;
|
||||
|
||||
i2c->pinctrl_default = pinctrl_lookup_state(i2c->pinctrl,
|
||||
PINCTRL_STATE_DEFAULT);
|
||||
i2c->pinctrl_recovery = pinctrl_lookup_state(i2c->pinctrl, "recovery");
|
||||
|
||||
if (IS_ERR(i2c->pinctrl_default) || IS_ERR(i2c->pinctrl_recovery)) {
|
||||
dev_info(dev, "missing pinmux recovery information: %ld %ld\n",
|
||||
PTR_ERR(i2c->pinctrl_default),
|
||||
PTR_ERR(i2c->pinctrl_recovery));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Claiming GPIOs can influence the pinmux state, and may glitch the
|
||||
* I2C bus. Do this carefully.
|
||||
*/
|
||||
bri->scl_gpiod = devm_gpiod_get(dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN);
|
||||
if (bri->scl_gpiod == ERR_PTR(-EPROBE_DEFER))
|
||||
return -EPROBE_DEFER;
|
||||
if (IS_ERR(bri->scl_gpiod)) {
|
||||
dev_info(dev, "missing scl gpio recovery information: %pe\n",
|
||||
bri->scl_gpiod);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We have SCL. Pull SCL low and wait a bit so that SDA glitches
|
||||
* have no effect.
|
||||
*/
|
||||
gpiod_direction_output(bri->scl_gpiod, 0);
|
||||
udelay(10);
|
||||
bri->sda_gpiod = devm_gpiod_get(dev, "sda", GPIOD_OUT_HIGH_OPEN_DRAIN);
|
||||
|
||||
/* Wait a bit in case of a SDA glitch, and then release SCL. */
|
||||
udelay(10);
|
||||
gpiod_direction_output(bri->scl_gpiod, 1);
|
||||
|
||||
if (bri->sda_gpiod == ERR_PTR(-EPROBE_DEFER))
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
if (IS_ERR(bri->sda_gpiod)) {
|
||||
dev_info(dev, "missing sda gpio recovery information: %pe\n",
|
||||
bri->sda_gpiod);
|
||||
bri->pinctrl = devm_pinctrl_get(dev);
|
||||
if (PTR_ERR(bri->pinctrl) == -ENODEV) {
|
||||
bri->pinctrl = NULL;
|
||||
return 0;
|
||||
}
|
||||
if (IS_ERR(bri->pinctrl))
|
||||
return PTR_ERR(bri->pinctrl);
|
||||
|
||||
bri->prepare_recovery = i2c_pxa_prepare_recovery;
|
||||
bri->unprepare_recovery = i2c_pxa_unprepare_recovery;
|
||||
bri->recover_bus = i2c_generic_scl_recovery;
|
||||
|
||||
i2c->adap.bus_recovery_info = bri;
|
||||
|
||||
/*
|
||||
* Claiming GPIOs can change the pinmux state, which confuses the
|
||||
* pinctrl since pinctrl's idea of the current setting is unaffected
|
||||
* by the pinmux change caused by claiming the GPIO. Work around that
|
||||
* by switching pinctrl to the GPIO state here. We do it this way to
|
||||
* avoid glitching the I2C bus.
|
||||
*/
|
||||
pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery);
|
||||
|
||||
return pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i2c_pxa_probe(struct platform_device *dev)
|
||||
|
|
|
|||
|
|
@ -353,19 +353,18 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
|||
{
|
||||
dma_addr_t rx_dma;
|
||||
unsigned long time_left;
|
||||
void *dma_buf = NULL;
|
||||
void *dma_buf;
|
||||
struct geni_se *se = &gi2c->se;
|
||||
size_t len = msg->len;
|
||||
|
||||
if (!of_machine_is_compatible("lenovo,yoga-c630"))
|
||||
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
||||
|
||||
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
||||
if (dma_buf)
|
||||
geni_se_select_mode(se, GENI_SE_DMA);
|
||||
else
|
||||
geni_se_select_mode(se, GENI_SE_FIFO);
|
||||
|
||||
writel_relaxed(len, se->base + SE_I2C_RX_TRANS_LEN);
|
||||
geni_se_setup_m_cmd(se, I2C_READ, m_param);
|
||||
|
||||
if (dma_buf && geni_se_rx_dma_prep(se, dma_buf, len, &rx_dma)) {
|
||||
geni_se_select_mode(se, GENI_SE_FIFO);
|
||||
|
|
@ -373,8 +372,6 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
|||
dma_buf = NULL;
|
||||
}
|
||||
|
||||
geni_se_setup_m_cmd(se, I2C_READ, m_param);
|
||||
|
||||
time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
|
||||
if (!time_left)
|
||||
geni_i2c_abort_xfer(gi2c);
|
||||
|
|
@ -395,19 +392,18 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
|||
{
|
||||
dma_addr_t tx_dma;
|
||||
unsigned long time_left;
|
||||
void *dma_buf = NULL;
|
||||
void *dma_buf;
|
||||
struct geni_se *se = &gi2c->se;
|
||||
size_t len = msg->len;
|
||||
|
||||
if (!of_machine_is_compatible("lenovo,yoga-c630"))
|
||||
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
||||
|
||||
dma_buf = i2c_get_dma_safe_msg_buf(msg, 32);
|
||||
if (dma_buf)
|
||||
geni_se_select_mode(se, GENI_SE_DMA);
|
||||
else
|
||||
geni_se_select_mode(se, GENI_SE_FIFO);
|
||||
|
||||
writel_relaxed(len, se->base + SE_I2C_TX_TRANS_LEN);
|
||||
geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
|
||||
|
||||
if (dma_buf && geni_se_tx_dma_prep(se, dma_buf, len, &tx_dma)) {
|
||||
geni_se_select_mode(se, GENI_SE_FIFO);
|
||||
|
|
@ -415,8 +411,6 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
|
|||
dma_buf = NULL;
|
||||
}
|
||||
|
||||
geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
|
||||
|
||||
if (!dma_buf) /* Get FIFO IRQ */
|
||||
writel_relaxed(1, se->base + SE_GENI_TX_WATERMARK_REG);
|
||||
|
||||
|
|
|
|||
|
|
@ -956,10 +956,38 @@ static int sh_mobile_i2c_remove(struct platform_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sh_mobile_i2c_suspend(struct device *dev)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd = dev_get_drvdata(dev);
|
||||
|
||||
i2c_mark_adapter_suspended(&pd->adap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sh_mobile_i2c_resume(struct device *dev)
|
||||
{
|
||||
struct sh_mobile_i2c_data *pd = dev_get_drvdata(dev);
|
||||
|
||||
i2c_mark_adapter_resumed(&pd->adap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops sh_mobile_i2c_pm_ops = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sh_mobile_i2c_suspend,
|
||||
sh_mobile_i2c_resume)
|
||||
};
|
||||
|
||||
#define DEV_PM_OPS (&sh_mobile_i2c_pm_ops)
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static struct platform_driver sh_mobile_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "i2c-sh_mobile",
|
||||
.of_match_table = sh_mobile_i2c_dt_ids,
|
||||
.pm = DEV_PM_OPS,
|
||||
},
|
||||
.probe = sh_mobile_i2c_probe,
|
||||
.remove = sh_mobile_i2c_remove,
|
||||
|
|
|
|||
|
|
@ -549,17 +549,18 @@ static int i2c_device_probe(struct device *dev)
|
|||
|
||||
static int i2c_device_remove(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = i2c_verify_client(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_driver *driver;
|
||||
int status = 0;
|
||||
|
||||
if (!client || !dev->driver)
|
||||
return 0;
|
||||
|
||||
driver = to_i2c_driver(dev->driver);
|
||||
if (driver->remove) {
|
||||
int status;
|
||||
|
||||
dev_dbg(dev, "remove\n");
|
||||
|
||||
status = driver->remove(client);
|
||||
if (status)
|
||||
dev_warn(dev, "remove failed (%pe), will be ignored\n", ERR_PTR(status));
|
||||
}
|
||||
|
||||
dev_pm_domain_detach(&client->dev, true);
|
||||
|
|
@ -571,7 +572,8 @@ static int i2c_device_remove(struct device *dev)
|
|||
if (client->flags & I2C_CLIENT_HOST_NOTIFY)
|
||||
pm_runtime_put(&client->adapter->dev);
|
||||
|
||||
return status;
|
||||
/* return always 0 because there is WIP to make remove-functions void */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void i2c_device_shutdown(struct device *dev)
|
||||
|
|
|
|||
|
|
@ -468,7 +468,6 @@ static void memstick_check(struct work_struct *work)
|
|||
host->card = card;
|
||||
if (device_register(&card->dev)) {
|
||||
put_device(&card->dev);
|
||||
kfree(host->card);
|
||||
host->card = NULL;
|
||||
}
|
||||
} else
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ static const char *mspro_block_attr_name(unsigned char tag)
|
|||
return "attr_devinfo";
|
||||
default:
|
||||
return NULL;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
typedef ssize_t (*sysfs_show_t)(struct device *dev,
|
||||
|
|
|
|||
|
|
@ -748,7 +748,7 @@ static int jmb38x_ms_set_param(struct memstick_host *msh,
|
|||
clock_delay);
|
||||
host->ifmode = value;
|
||||
break;
|
||||
};
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -759,8 +759,10 @@ static int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
goto error3;
|
||||
|
||||
dev->mmio = pci_ioremap_bar(pdev, 0);
|
||||
if (!dev->mmio)
|
||||
if (!dev->mmio) {
|
||||
error = -ENOMEM;
|
||||
goto error4;
|
||||
}
|
||||
|
||||
dev->irq = pdev->irq;
|
||||
spin_lock_init(&dev->irq_lock);
|
||||
|
|
@ -786,12 +788,14 @@ static int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
&dev->dummy_dma_page_physical_address, GFP_KERNEL);
|
||||
r592_stop_dma(dev , 0);
|
||||
|
||||
if (request_irq(dev->irq, &r592_irq, IRQF_SHARED,
|
||||
DRV_NAME, dev))
|
||||
error = request_irq(dev->irq, &r592_irq, IRQF_SHARED,
|
||||
DRV_NAME, dev);
|
||||
if (error)
|
||||
goto error6;
|
||||
|
||||
r592_update_card_detect(dev);
|
||||
if (memstick_add_host(host))
|
||||
error = memstick_add_host(host);
|
||||
if (error)
|
||||
goto error7;
|
||||
|
||||
message("driver successfully loaded");
|
||||
|
|
|
|||
|
|
@ -528,7 +528,7 @@ static int tifm_ms_set_param(struct memstick_host *msh,
|
|||
} else
|
||||
return -EINVAL;
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,16 +26,16 @@ static u8 rts5261_get_ic_version(struct rtsx_pcr *pcr)
|
|||
static void rts5261_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
|
||||
{
|
||||
u8 driving_3v3[4][3] = {
|
||||
{0x13, 0x13, 0x13},
|
||||
{0x96, 0x96, 0x96},
|
||||
{0x96, 0x96, 0x96},
|
||||
{0x7F, 0x7F, 0x7F},
|
||||
{0x96, 0x96, 0x96},
|
||||
{0x13, 0x13, 0x13},
|
||||
};
|
||||
u8 driving_1v8[4][3] = {
|
||||
{0x99, 0x99, 0x99},
|
||||
{0xB3, 0xB3, 0xB3},
|
||||
{0x3A, 0x3A, 0x3A},
|
||||
{0xE6, 0xE6, 0xE6},
|
||||
{0xB3, 0xB3, 0xB3},
|
||||
{0x99, 0x99, 0x99},
|
||||
};
|
||||
u8 (*driving)[3], drive_sel;
|
||||
|
||||
|
|
@ -67,12 +67,17 @@ static void rtsx5261_fetch_vendor_settings(struct rtsx_pcr *pcr)
|
|||
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
|
||||
|
||||
if (!rts5261_vendor_setting_valid(reg)) {
|
||||
/* Not support MMC default */
|
||||
pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
|
||||
pcr_dbg(pcr, "skip fetch vendor setting\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pcr->card_drive_sel &= 0x3F;
|
||||
pcr->card_drive_sel |= rts5261_reg_to_card_drive_sel(reg);
|
||||
if (!rts5261_reg_check_mmc_support(reg))
|
||||
pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
|
||||
|
||||
/* TO do: need to add rtd3 function */
|
||||
pcr->rtd3_en = rts5261_reg_to_rtd3(reg);
|
||||
|
||||
if (rts5261_reg_check_reverse_socket(reg))
|
||||
pcr->flags |= PCR_REVERSE_SOCKET;
|
||||
|
|
@ -171,6 +176,8 @@ static int rts5261_card_power_on(struct rtsx_pcr *pcr, int card)
|
|||
if (option->ocp_en)
|
||||
rtsx_pci_enable_ocp(pcr);
|
||||
|
||||
rtsx_pci_write_register(pcr, REG_CRC_DUMMY_0,
|
||||
CFG_SD_POW_AUTO_PD, CFG_SD_POW_AUTO_PD);
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5261_LDO1_CFG1,
|
||||
RTS5261_LDO1_TUNE_MASK, RTS5261_LDO1_33);
|
||||
|
|
@ -272,6 +279,9 @@ static void rts5261_enable_ocp(struct rtsx_pcr *pcr)
|
|||
u8 val = 0;
|
||||
|
||||
val = SD_OCP_INT_EN | SD_DETECT_EN;
|
||||
rtsx_pci_write_register(pcr, RTS5261_LDO1_CFG0,
|
||||
RTS5261_LDO1_OCP_EN | RTS5261_LDO1_OCP_LMT_EN,
|
||||
RTS5261_LDO1_OCP_EN | RTS5261_LDO1_OCP_LMT_EN);
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, 0xFF, val);
|
||||
|
||||
}
|
||||
|
|
@ -295,6 +305,8 @@ static int rts5261_card_power_off(struct rtsx_pcr *pcr, int card)
|
|||
err = rtsx_pci_write_register(pcr, RTS5261_LDO1233318_POW_CTL,
|
||||
RTS5261_LDO_POWERON_MASK, 0);
|
||||
|
||||
rtsx_pci_write_register(pcr, REG_CRC_DUMMY_0,
|
||||
CFG_SD_POW_AUTO_PD, 0);
|
||||
if (pcr->option.ocp_en)
|
||||
rtsx_pci_disable_ocp(pcr);
|
||||
|
||||
|
|
@ -340,7 +352,7 @@ static void rts5261_clear_ocpstat(struct rtsx_pcr *pcr)
|
|||
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, val);
|
||||
|
||||
udelay(10);
|
||||
udelay(1000);
|
||||
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
|
||||
|
||||
}
|
||||
|
|
@ -353,9 +365,9 @@ static void rts5261_process_ocp(struct rtsx_pcr *pcr)
|
|||
rtsx_pci_get_ocpstat(pcr, &pcr->ocp_stat);
|
||||
|
||||
if (pcr->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) {
|
||||
rts5261_clear_ocpstat(pcr);
|
||||
rts5261_card_power_off(pcr, RTSX_SD_CARD);
|
||||
rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, 0);
|
||||
rts5261_clear_ocpstat(pcr);
|
||||
pcr->ocp_stat = 0;
|
||||
}
|
||||
|
||||
|
|
@ -467,6 +479,7 @@ static void rts5261_init_from_cfg(struct rtsx_pcr *pcr)
|
|||
static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
|
||||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
u32 val;
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG1,
|
||||
CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
|
||||
|
|
@ -481,6 +494,10 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
|
|||
AUX_CLK_ACTIVE_SEL_MASK, MAC_CKSW_DONE);
|
||||
rtsx_pci_write_register(pcr, L1SUB_CONFIG3, 0xFF, 0);
|
||||
|
||||
if (is_version_higher_than(pcr, PID_5261, IC_VER_B)) {
|
||||
val = rtsx_pci_readl(pcr, RTSX_DUM_REG);
|
||||
rtsx_pci_writel(pcr, RTSX_DUM_REG, val | 0x1);
|
||||
}
|
||||
rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG4,
|
||||
RTS5261_AUX_CLK_16M_EN, 0);
|
||||
|
||||
|
|
@ -502,6 +519,11 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
|
|||
/* Configure driving */
|
||||
rts5261_fill_driving(pcr, OUTPUT_3V3);
|
||||
|
||||
if (pcr->flags & PCR_REVERSE_SOCKET)
|
||||
rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x30);
|
||||
else
|
||||
rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00);
|
||||
|
||||
/*
|
||||
* If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
|
||||
* to drive low, and we forcibly request clock.
|
||||
|
|
@ -513,6 +535,7 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
|
|||
rtsx_pci_write_register(pcr, PETXCFG,
|
||||
FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
|
||||
|
||||
rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB);
|
||||
rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x00);
|
||||
rtsx_pci_write_register(pcr, RTS5261_REG_PME_FORCE_CTL,
|
||||
FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
|
||||
|
|
@ -526,22 +549,30 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
|
|||
|
||||
static void rts5261_enable_aspm(struct rtsx_pcr *pcr, bool enable)
|
||||
{
|
||||
u8 val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
|
||||
u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
|
||||
|
||||
if (pcr->aspm_enabled == enable)
|
||||
return;
|
||||
|
||||
val |= (pcr->aspm_en & 0x02);
|
||||
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
|
||||
pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPMC, pcr->aspm_en);
|
||||
pcr->aspm_enabled = enable;
|
||||
|
||||
}
|
||||
|
||||
static void rts5261_disable_aspm(struct rtsx_pcr *pcr, bool enable)
|
||||
{
|
||||
u8 val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
|
||||
u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
|
||||
|
||||
if (pcr->aspm_enabled == enable)
|
||||
return;
|
||||
|
||||
pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
|
||||
PCI_EXP_LNKCTL_ASPMC, 0);
|
||||
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
|
||||
rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
|
||||
udelay(10);
|
||||
pcr->aspm_enabled = enable;
|
||||
|
|
@ -618,7 +649,7 @@ int rts5261_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
|||
|
||||
if (initial_mode) {
|
||||
/* We use 250k(around) here, in initial stage */
|
||||
if (is_version(pcr, PID_5261, IC_VER_D)) {
|
||||
if (is_version_higher_than(pcr, PID_5261, IC_VER_C)) {
|
||||
clk_divider = SD_CLK_DIVIDE_256;
|
||||
card_clock = 60000000;
|
||||
} else {
|
||||
|
|
@ -669,7 +700,7 @@ int rts5261_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
|
|||
div++;
|
||||
}
|
||||
|
||||
n = (n / 2);
|
||||
n = (n / 2) - 1;
|
||||
pcr_dbg(pcr, "n = %d, div = %d\n", n, div);
|
||||
|
||||
ssc_depth = depth[ssc_depth];
|
||||
|
|
@ -738,15 +769,19 @@ void rts5261_init_params(struct rtsx_pcr *pcr)
|
|||
{
|
||||
struct rtsx_cr_option *option = &pcr->option;
|
||||
struct rtsx_hw_param *hw_param = &pcr->hw_param;
|
||||
u8 val;
|
||||
|
||||
pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
|
||||
rtsx_pci_read_register(pcr, RTS5261_FW_STATUS, &val);
|
||||
if (!(val & RTS5261_EXPRESS_LINK_FAIL_MASK))
|
||||
pcr->extra_caps |= EXTRA_CAPS_SD_EXPRESS;
|
||||
pcr->num_slots = 1;
|
||||
pcr->ops = &rts5261_pcr_ops;
|
||||
|
||||
pcr->flags = 0;
|
||||
pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
|
||||
pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
|
||||
pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
|
||||
pcr->sd30_drive_sel_1v8 = 0x00;
|
||||
pcr->sd30_drive_sel_3v3 = 0x00;
|
||||
pcr->aspm_en = ASPM_L1_EN;
|
||||
pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 11);
|
||||
pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
|
||||
|
|
|
|||
|
|
@ -12,12 +12,13 @@
|
|||
|
||||
/*New add*/
|
||||
#define rts5261_vendor_setting_valid(reg) ((reg) & 0x010000)
|
||||
#define rts5261_reg_to_aspm(reg) (((reg) >> 28) ^ 0x03)
|
||||
#define rts5261_reg_to_aspm(reg) \
|
||||
(((~(reg) >> 28) & 0x02) | (((reg) >> 28) & 0x01))
|
||||
#define rts5261_reg_check_reverse_socket(reg) ((reg) & 0x04)
|
||||
#define rts5261_reg_to_card_drive_sel(reg) ((((reg) >> 6) & 0x01) << 6)
|
||||
#define rts5261_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 22) ^ 0x03)
|
||||
#define rts5261_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 16) ^ 0x03)
|
||||
|
||||
#define rts5261_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 22) & 0x03)
|
||||
#define rts5261_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 16) & 0x03)
|
||||
#define rts5261_reg_to_rtd3(reg) ((reg) & 0x08)
|
||||
#define rts5261_reg_check_mmc_support(reg) ((reg) & 0x10)
|
||||
|
||||
#define RTS5261_AUTOLOAD_CFG0 0xFF7B
|
||||
#define RTS5261_AUTOLOAD_CFG1 0xFF7C
|
||||
|
|
@ -60,28 +61,6 @@
|
|||
/* DMACTL 0xFE2C */
|
||||
#define RTS5261_DMA_PACK_SIZE_MASK 0xF0
|
||||
|
||||
/* FW config info register */
|
||||
#define RTS5261_FW_CFG_INFO0 0xFF50
|
||||
#define RTS5261_FW_EXPRESS_TEST_MASK (0x01<<0)
|
||||
#define RTS5261_FW_EA_MODE_MASK (0x01<<5)
|
||||
|
||||
/* FW config register */
|
||||
#define RTS5261_FW_CFG0 0xFF54
|
||||
#define RTS5261_FW_ENTER_EXPRESS (0x01<<0)
|
||||
|
||||
#define RTS5261_FW_CFG1 0xFF55
|
||||
#define RTS5261_SYS_CLK_SEL_MCU_CLK (0x01<<7)
|
||||
#define RTS5261_CRC_CLK_SEL_MCU_CLK (0x01<<6)
|
||||
#define RTS5261_FAKE_MCU_CLOCK_GATING (0x01<<5)
|
||||
/*MCU_bus_mode_sel: 0=real 8051 1=fake mcu*/
|
||||
#define RTS5261_MCU_BUS_SEL_MASK (0x01<<4)
|
||||
/*MCU_clock_sel:VerA 00=aux16M 01=aux400K 1x=REFCLK100M*/
|
||||
/*MCU_clock_sel:VerB 00=aux400K 01=aux16M 10=REFCLK100M*/
|
||||
#define RTS5261_MCU_CLOCK_SEL_MASK (0x03<<2)
|
||||
#define RTS5261_MCU_CLOCK_SEL_16M (0x01<<2)
|
||||
#define RTS5261_MCU_CLOCK_GATING (0x01<<1)
|
||||
#define RTS5261_DRIVER_ENABLE_FW (0x01<<0)
|
||||
|
||||
/* FW status register */
|
||||
#define RTS5261_FW_STATUS 0xFF56
|
||||
#define RTS5261_EXPRESS_LINK_FAIL_MASK (0x01<<7)
|
||||
|
|
@ -121,12 +100,6 @@
|
|||
#define RTS5261_DV3318_19 (0x04<<4)
|
||||
#define RTS5261_DV3318_33 (0x07<<4)
|
||||
|
||||
#define RTS5261_LDO1_CFG0 0xFF72
|
||||
#define RTS5261_LDO1_OCP_THD_MASK (0x07<<5)
|
||||
#define RTS5261_LDO1_OCP_EN (0x01<<4)
|
||||
#define RTS5261_LDO1_OCP_LMT_THD_MASK (0x03<<2)
|
||||
#define RTS5261_LDO1_OCP_LMT_EN (0x01<<1)
|
||||
|
||||
/* CRD6603-433 190319 request changed */
|
||||
#define RTS5261_LDO1_OCP_THD_740 (0x00<<5)
|
||||
#define RTS5261_LDO1_OCP_THD_800 (0x01<<5)
|
||||
|
|
|
|||
|
|
@ -1004,6 +1004,11 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
|
|||
} else {
|
||||
pcr->card_removed |= SD_EXIST;
|
||||
pcr->card_inserted &= ~SD_EXIST;
|
||||
if (PCI_PID(pcr) == PID_5261) {
|
||||
rtsx_pci_write_register(pcr, RTS5261_FW_STATUS,
|
||||
RTS5261_EXPRESS_LINK_FAIL_MASK, 0);
|
||||
pcr->extra_caps |= EXTRA_CAPS_SD_EXPRESS;
|
||||
}
|
||||
}
|
||||
pcr->dma_error_count = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2147,8 +2147,12 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
|
|||
|
||||
mmc_go_idle(host);
|
||||
|
||||
if (!(host->caps2 & MMC_CAP2_NO_SD))
|
||||
mmc_send_if_cond(host, host->ocr_avail);
|
||||
if (!(host->caps2 & MMC_CAP2_NO_SD)) {
|
||||
if (mmc_send_if_cond_pcie(host, host->ocr_avail))
|
||||
goto out;
|
||||
if (mmc_card_sd_express(host))
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Order's important: probe SDIO, then SD, then MMC */
|
||||
if (!(host->caps2 & MMC_CAP2_NO_SDIO))
|
||||
|
|
@ -2163,6 +2167,7 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
|
|||
if (!mmc_attach_mmc(host))
|
||||
return 0;
|
||||
|
||||
out:
|
||||
mmc_power_off(host);
|
||||
return -EIO;
|
||||
}
|
||||
|
|
@ -2290,6 +2295,12 @@ void mmc_rescan(struct work_struct *work)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* If an SD express card is present, then leave it as is. */
|
||||
if (mmc_card_sd_express(host)) {
|
||||
mmc_release_host(host);
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
|
||||
unsigned int freq = freqs[i];
|
||||
if (freq > host->f_max) {
|
||||
|
|
|
|||
|
|
@ -77,5 +77,11 @@ static inline bool mmc_card_hs400es(struct mmc_card *card)
|
|||
return card->host->ios.enhanced_strobe;
|
||||
}
|
||||
|
||||
static inline bool mmc_card_sd_express(struct mmc_host *host)
|
||||
{
|
||||
return host->ios.timing == MMC_TIMING_SD_EXP ||
|
||||
host->ios.timing == MMC_TIMING_SD_EXP_1_2V;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -158,7 +158,8 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
|
|||
return err;
|
||||
}
|
||||
|
||||
int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
|
||||
static int __mmc_send_if_cond(struct mmc_host *host, u32 ocr, u8 pcie_bits,
|
||||
u32 *resp)
|
||||
{
|
||||
struct mmc_command cmd = {};
|
||||
int err;
|
||||
|
|
@ -171,7 +172,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
|
|||
* SD 1.0 cards.
|
||||
*/
|
||||
cmd.opcode = SD_SEND_IF_COND;
|
||||
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
|
||||
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | pcie_bits << 8 | test_pattern;
|
||||
cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
|
||||
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
|
|
@ -186,6 +187,50 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
|
|||
if (result_pattern != test_pattern)
|
||||
return -EIO;
|
||||
|
||||
if (resp)
|
||||
*resp = cmd.resp[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
|
||||
{
|
||||
return __mmc_send_if_cond(host, ocr, 0, NULL);
|
||||
}
|
||||
|
||||
int mmc_send_if_cond_pcie(struct mmc_host *host, u32 ocr)
|
||||
{
|
||||
u32 resp = 0;
|
||||
u8 pcie_bits = 0;
|
||||
int ret;
|
||||
|
||||
if (host->caps2 & MMC_CAP2_SD_EXP) {
|
||||
/* Probe card for SD express support via PCIe. */
|
||||
pcie_bits = 0x10;
|
||||
if (host->caps2 & MMC_CAP2_SD_EXP_1_2V)
|
||||
/* Probe also for 1.2V support. */
|
||||
pcie_bits = 0x30;
|
||||
}
|
||||
|
||||
ret = __mmc_send_if_cond(host, ocr, pcie_bits, &resp);
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
/* Continue with the SD express init, if the card supports it. */
|
||||
resp &= 0x3000;
|
||||
if (pcie_bits && resp) {
|
||||
if (resp == 0x3000)
|
||||
host->ios.timing = MMC_TIMING_SD_EXP_1_2V;
|
||||
else
|
||||
host->ios.timing = MMC_TIMING_SD_EXP;
|
||||
|
||||
/*
|
||||
* According to the spec the clock shall also be gated, but
|
||||
* let's leave this to the host driver for more flexibility.
|
||||
*/
|
||||
return host->ops->init_sd_express(host, &host->ios);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ struct mmc_host;
|
|||
int mmc_app_set_bus_width(struct mmc_card *card, int width);
|
||||
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
|
||||
int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
|
||||
int mmc_send_if_cond_pcie(struct mmc_host *host, u32 ocr);
|
||||
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
|
||||
int mmc_app_send_scr(struct mmc_card *card);
|
||||
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
|
||||
|
|
|
|||
|
|
@ -631,8 +631,8 @@ config MMC_SPI
|
|||
|
||||
config MMC_S3C
|
||||
tristate "Samsung S3C SD/MMC Card Interface support"
|
||||
depends on ARCH_S3C24XX
|
||||
depends on S3C24XX_DMAC
|
||||
depends on ARCH_S3C24XX || COMPILE_TEST
|
||||
depends on S3C24XX_DMAC || COMPILE_TEST
|
||||
help
|
||||
This selects a driver for the MCI interface found in
|
||||
Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
|
||||
|
|
@ -664,7 +664,7 @@ config MMC_S3C_PIO
|
|||
config MMC_S3C_DMA
|
||||
bool "Use DMA transfers only"
|
||||
help
|
||||
Use DMA to transfer data between memory and the hardare.
|
||||
Use DMA to transfer data between memory and the hardware.
|
||||
|
||||
Currently, the DMA support in this driver seems to not be
|
||||
working properly and needs to be debugged before this
|
||||
|
|
@ -1023,6 +1023,7 @@ config MMC_BCM2835
|
|||
config MMC_MTK
|
||||
tristate "MediaTek SD/MMC Card Interface support"
|
||||
depends on HAS_DMA
|
||||
depends on COMMON_CLK
|
||||
select REGULATOR
|
||||
select MMC_CQHCI
|
||||
help
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host,
|
|||
default:
|
||||
s = ", (R? response)";
|
||||
break;
|
||||
}; s; }));
|
||||
} s; }));
|
||||
host->cmd = cmd;
|
||||
|
||||
switch (mmc_resp_type(cmd)) {
|
||||
|
|
|
|||
|
|
@ -2617,7 +2617,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
|
|||
struct dw_mci *host = dev_id;
|
||||
u32 pending;
|
||||
struct dw_mci_slot *slot = host->slot;
|
||||
unsigned long irqflags;
|
||||
|
||||
pending = mci_readl(host, MINTSTS); /* read-only mask reg */
|
||||
|
||||
|
|
@ -2632,15 +2631,15 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
|
|||
* Hold the lock; we know cmd11_timer can't be kicked
|
||||
* off after the lock is released, so safe to delete.
|
||||
*/
|
||||
spin_lock_irqsave(&host->irq_lock, irqflags);
|
||||
spin_lock(&host->irq_lock);
|
||||
dw_mci_cmd_interrupt(host, pending);
|
||||
spin_unlock_irqrestore(&host->irq_lock, irqflags);
|
||||
spin_unlock(&host->irq_lock);
|
||||
|
||||
del_timer(&host->cmd11_timer);
|
||||
}
|
||||
|
||||
if (pending & DW_MCI_CMD_ERROR_FLAGS) {
|
||||
spin_lock_irqsave(&host->irq_lock, irqflags);
|
||||
spin_lock(&host->irq_lock);
|
||||
|
||||
del_timer(&host->cto_timer);
|
||||
mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
|
||||
|
|
@ -2648,7 +2647,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
|
|||
smp_wmb(); /* drain writebuffer */
|
||||
set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
|
||||
|
||||
spin_unlock_irqrestore(&host->irq_lock, irqflags);
|
||||
spin_unlock(&host->irq_lock);
|
||||
}
|
||||
|
||||
if (pending & DW_MCI_DATA_ERROR_FLAGS) {
|
||||
|
|
@ -2661,7 +2660,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
if (pending & SDMMC_INT_DATA_OVER) {
|
||||
spin_lock_irqsave(&host->irq_lock, irqflags);
|
||||
spin_lock(&host->irq_lock);
|
||||
|
||||
del_timer(&host->dto_timer);
|
||||
|
||||
|
|
@ -2676,7 +2675,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
|
|||
set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
|
||||
tasklet_schedule(&host->tasklet);
|
||||
|
||||
spin_unlock_irqrestore(&host->irq_lock, irqflags);
|
||||
spin_unlock(&host->irq_lock);
|
||||
}
|
||||
|
||||
if (pending & SDMMC_INT_RXDR) {
|
||||
|
|
@ -2692,12 +2691,12 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
if (pending & SDMMC_INT_CMD_DONE) {
|
||||
spin_lock_irqsave(&host->irq_lock, irqflags);
|
||||
spin_lock(&host->irq_lock);
|
||||
|
||||
mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
|
||||
dw_mci_cmd_interrupt(host, pending);
|
||||
|
||||
spin_unlock_irqrestore(&host->irq_lock, irqflags);
|
||||
spin_unlock(&host->irq_lock);
|
||||
}
|
||||
|
||||
if (pending & SDMMC_INT_CD) {
|
||||
|
|
|
|||
|
|
@ -1265,7 +1265,7 @@ static struct platform_driver meson_mmc_driver = {
|
|||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = of_match_ptr(meson_mmc_of_match),
|
||||
.of_match_table = meson_mmc_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -418,10 +418,9 @@ static irqreturn_t meson_mx_mmc_irq(int irq, void *data)
|
|||
{
|
||||
struct meson_mx_mmc_host *host = (void *) data;
|
||||
u32 irqs, send;
|
||||
unsigned long irqflags;
|
||||
irqreturn_t ret;
|
||||
|
||||
spin_lock_irqsave(&host->irq_lock, irqflags);
|
||||
spin_lock(&host->irq_lock);
|
||||
|
||||
irqs = readl(host->base + MESON_MX_SDIO_IRQS);
|
||||
send = readl(host->base + MESON_MX_SDIO_SEND);
|
||||
|
|
@ -434,7 +433,7 @@ static irqreturn_t meson_mx_mmc_irq(int irq, void *data)
|
|||
/* finally ACK all pending interrupts */
|
||||
writel(irqs, host->base + MESON_MX_SDIO_IRQS);
|
||||
|
||||
spin_unlock_irqrestore(&host->irq_lock, irqflags);
|
||||
spin_unlock(&host->irq_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -465,9 +465,8 @@ static irqreturn_t moxart_irq(int irq, void *devid)
|
|||
{
|
||||
struct moxart_host *host = (struct moxart_host *)devid;
|
||||
u32 status;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
spin_lock(&host->lock);
|
||||
|
||||
status = readl(host->base + REG_STATUS);
|
||||
if (status & CARD_CHANGE) {
|
||||
|
|
@ -484,7 +483,7 @@ static irqreturn_t moxart_irq(int irq, void *devid)
|
|||
if (status & (FIFO_ORUN | FIFO_URUN) && host->mrq)
|
||||
moxart_transfer_pio(host);
|
||||
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
spin_unlock(&host->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "cqhci.h"
|
||||
|
||||
#define MAX_BD_NUM 1024
|
||||
#define MSDC_NR_CLOCKS 3
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Common Definition */
|
||||
|
|
@ -77,9 +78,12 @@
|
|||
#define MSDC_PAD_TUNE0 0xf0
|
||||
#define PAD_DS_TUNE 0x188
|
||||
#define PAD_CMD_TUNE 0x18c
|
||||
#define EMMC51_CFG0 0x204
|
||||
#define EMMC50_CFG0 0x208
|
||||
#define EMMC50_CFG1 0x20c
|
||||
#define EMMC50_CFG3 0x220
|
||||
#define SDC_FIFO_CFG 0x228
|
||||
#define CQHCI_SETTING 0x7fc
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Top Pad Register Offset */
|
||||
|
|
@ -260,15 +264,26 @@
|
|||
|
||||
#define PAD_CMD_TUNE_RX_DLY3 (0x1f << 1) /* RW */
|
||||
|
||||
/* EMMC51_CFG0 mask */
|
||||
#define CMDQ_RDAT_CNT (0x3ff << 12) /* RW */
|
||||
|
||||
#define EMMC50_CFG_PADCMD_LATCHCK (0x1 << 0) /* RW */
|
||||
#define EMMC50_CFG_CRCSTS_EDGE (0x1 << 3) /* RW */
|
||||
#define EMMC50_CFG_CFCSTS_SEL (0x1 << 4) /* RW */
|
||||
#define EMMC50_CFG_CMD_RESP_SEL (0x1 << 9) /* RW */
|
||||
|
||||
/* EMMC50_CFG1 mask */
|
||||
#define EMMC50_CFG1_DS_CFG (0x1 << 28) /* RW */
|
||||
|
||||
#define EMMC50_CFG3_OUTS_WR (0x1f << 0) /* RW */
|
||||
|
||||
#define SDC_FIFO_CFG_WRVALIDSEL (0x1 << 24) /* RW */
|
||||
#define SDC_FIFO_CFG_RDVALIDSEL (0x1 << 25) /* RW */
|
||||
|
||||
/* CQHCI_SETTING */
|
||||
#define CQHCI_RD_CMD_WND_SEL (0x1 << 14) /* RW */
|
||||
#define CQHCI_WR_CMD_WND_SEL (0x1 << 15) /* RW */
|
||||
|
||||
/* EMMC_TOP_CONTROL mask */
|
||||
#define PAD_RXDLY_SEL (0x1 << 0) /* RW */
|
||||
#define DELAY_EN (0x1 << 1) /* RW */
|
||||
|
|
@ -425,6 +440,8 @@ struct msdc_host {
|
|||
struct clk *h_clk; /* msdc h_clk */
|
||||
struct clk *bus_clk; /* bus clock which used to access register */
|
||||
struct clk *src_clk_cg; /* msdc source clock control gate */
|
||||
struct clk *sys_clk_cg; /* msdc subsys clock control gate */
|
||||
struct clk_bulk_data bulk_clks[MSDC_NR_CLOCKS];
|
||||
u32 mclk; /* mmc subsystem clock frequency */
|
||||
u32 src_clk_freq; /* source clock frequency */
|
||||
unsigned char timing;
|
||||
|
|
@ -785,6 +802,7 @@ static void msdc_set_busy_timeout(struct msdc_host *host, u64 ns, u64 clks)
|
|||
|
||||
static void msdc_gate_clock(struct msdc_host *host)
|
||||
{
|
||||
clk_bulk_disable_unprepare(MSDC_NR_CLOCKS, host->bulk_clks);
|
||||
clk_disable_unprepare(host->src_clk_cg);
|
||||
clk_disable_unprepare(host->src_clk);
|
||||
clk_disable_unprepare(host->bus_clk);
|
||||
|
|
@ -793,10 +811,18 @@ static void msdc_gate_clock(struct msdc_host *host)
|
|||
|
||||
static void msdc_ungate_clock(struct msdc_host *host)
|
||||
{
|
||||
int ret;
|
||||
|
||||
clk_prepare_enable(host->h_clk);
|
||||
clk_prepare_enable(host->bus_clk);
|
||||
clk_prepare_enable(host->src_clk);
|
||||
clk_prepare_enable(host->src_clk_cg);
|
||||
ret = clk_bulk_prepare_enable(MSDC_NR_CLOCKS, host->bulk_clks);
|
||||
if (ret) {
|
||||
dev_err(host->dev, "Cannot enable pclk/axi/ahb clock gates\n");
|
||||
return;
|
||||
}
|
||||
|
||||
while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
|
||||
cpu_relax();
|
||||
}
|
||||
|
|
@ -1537,13 +1563,12 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
|
|||
struct mmc_host *mmc = mmc_from_priv(host);
|
||||
|
||||
while (true) {
|
||||
unsigned long flags;
|
||||
struct mmc_request *mrq;
|
||||
struct mmc_command *cmd;
|
||||
struct mmc_data *data;
|
||||
u32 events, event_mask;
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
spin_lock(&host->lock);
|
||||
events = readl(host->base + MSDC_INT);
|
||||
event_mask = readl(host->base + MSDC_INTEN);
|
||||
if ((events & event_mask) & MSDC_INT_SDIOIRQ)
|
||||
|
|
@ -1554,7 +1579,7 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
|
|||
mrq = host->mrq;
|
||||
cmd = host->cmd;
|
||||
data = host->data;
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
spin_unlock(&host->lock);
|
||||
|
||||
if ((events & event_mask) & MSDC_INT_SDIOIRQ)
|
||||
sdio_signal_irq(mmc);
|
||||
|
|
@ -2266,6 +2291,31 @@ static int msdc_get_cd(struct mmc_host *mmc)
|
|||
return !val;
|
||||
}
|
||||
|
||||
static void msdc_hs400_enhanced_strobe(struct mmc_host *mmc,
|
||||
struct mmc_ios *ios)
|
||||
{
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
|
||||
if (ios->enhanced_strobe) {
|
||||
msdc_prepare_hs400_tuning(mmc, ios);
|
||||
sdr_set_field(host->base + EMMC50_CFG0, EMMC50_CFG_PADCMD_LATCHCK, 1);
|
||||
sdr_set_field(host->base + EMMC50_CFG0, EMMC50_CFG_CMD_RESP_SEL, 1);
|
||||
sdr_set_field(host->base + EMMC50_CFG1, EMMC50_CFG1_DS_CFG, 1);
|
||||
|
||||
sdr_clr_bits(host->base + CQHCI_SETTING, CQHCI_RD_CMD_WND_SEL);
|
||||
sdr_clr_bits(host->base + CQHCI_SETTING, CQHCI_WR_CMD_WND_SEL);
|
||||
sdr_clr_bits(host->base + EMMC51_CFG0, CMDQ_RDAT_CNT);
|
||||
} else {
|
||||
sdr_set_field(host->base + EMMC50_CFG0, EMMC50_CFG_PADCMD_LATCHCK, 0);
|
||||
sdr_set_field(host->base + EMMC50_CFG0, EMMC50_CFG_CMD_RESP_SEL, 0);
|
||||
sdr_set_field(host->base + EMMC50_CFG1, EMMC50_CFG1_DS_CFG, 0);
|
||||
|
||||
sdr_set_bits(host->base + CQHCI_SETTING, CQHCI_RD_CMD_WND_SEL);
|
||||
sdr_set_bits(host->base + CQHCI_SETTING, CQHCI_WR_CMD_WND_SEL);
|
||||
sdr_set_field(host->base + EMMC51_CFG0, CMDQ_RDAT_CNT, 0xb4);
|
||||
}
|
||||
}
|
||||
|
||||
static void msdc_cqe_enable(struct mmc_host *mmc)
|
||||
{
|
||||
struct msdc_host *host = mmc_priv(mmc);
|
||||
|
|
@ -2323,6 +2373,7 @@ static const struct mmc_host_ops mt_msdc_ops = {
|
|||
.set_ios = msdc_ops_set_ios,
|
||||
.get_ro = mmc_gpio_get_ro,
|
||||
.get_cd = msdc_get_cd,
|
||||
.hs400_enhanced_strobe = msdc_hs400_enhanced_strobe,
|
||||
.enable_sdio_irq = msdc_enable_sdio_irq,
|
||||
.ack_sdio_irq = msdc_ack_sdio_irq,
|
||||
.start_signal_voltage_switch = msdc_ops_switch_volt,
|
||||
|
|
@ -2367,6 +2418,48 @@ static void msdc_of_property_parse(struct platform_device *pdev,
|
|||
host->cqhci = false;
|
||||
}
|
||||
|
||||
static int msdc_of_clock_parse(struct platform_device *pdev,
|
||||
struct msdc_host *host)
|
||||
{
|
||||
int ret;
|
||||
|
||||
host->src_clk = devm_clk_get(&pdev->dev, "source");
|
||||
if (IS_ERR(host->src_clk))
|
||||
return PTR_ERR(host->src_clk);
|
||||
|
||||
host->h_clk = devm_clk_get(&pdev->dev, "hclk");
|
||||
if (IS_ERR(host->h_clk))
|
||||
return PTR_ERR(host->h_clk);
|
||||
|
||||
host->bus_clk = devm_clk_get_optional(&pdev->dev, "bus_clk");
|
||||
if (IS_ERR(host->bus_clk))
|
||||
host->bus_clk = NULL;
|
||||
|
||||
/*source clock control gate is optional clock*/
|
||||
host->src_clk_cg = devm_clk_get_optional(&pdev->dev, "source_cg");
|
||||
if (IS_ERR(host->src_clk_cg))
|
||||
host->src_clk_cg = NULL;
|
||||
|
||||
host->sys_clk_cg = devm_clk_get_optional(&pdev->dev, "sys_cg");
|
||||
if (IS_ERR(host->sys_clk_cg))
|
||||
host->sys_clk_cg = NULL;
|
||||
|
||||
/* If present, always enable for this clock gate */
|
||||
clk_prepare_enable(host->sys_clk_cg);
|
||||
|
||||
host->bulk_clks[0].id = "pclk_cg";
|
||||
host->bulk_clks[1].id = "axi_cg";
|
||||
host->bulk_clks[2].id = "ahb_cg";
|
||||
ret = devm_clk_bulk_get_optional(&pdev->dev, MSDC_NR_CLOCKS,
|
||||
host->bulk_clks);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Cannot get pclk/axi/ahb clock gates\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msdc_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mmc_host *mmc;
|
||||
|
|
@ -2406,30 +2499,16 @@ static int msdc_drv_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto host_free;
|
||||
|
||||
host->src_clk = devm_clk_get(&pdev->dev, "source");
|
||||
if (IS_ERR(host->src_clk)) {
|
||||
ret = PTR_ERR(host->src_clk);
|
||||
ret = msdc_of_clock_parse(pdev, host);
|
||||
if (ret)
|
||||
goto host_free;
|
||||
}
|
||||
|
||||
host->h_clk = devm_clk_get(&pdev->dev, "hclk");
|
||||
if (IS_ERR(host->h_clk)) {
|
||||
ret = PTR_ERR(host->h_clk);
|
||||
goto host_free;
|
||||
}
|
||||
|
||||
host->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
|
||||
if (IS_ERR(host->bus_clk))
|
||||
host->bus_clk = NULL;
|
||||
/*source clock control gate is optional clock*/
|
||||
host->src_clk_cg = devm_clk_get(&pdev->dev, "source_cg");
|
||||
if (IS_ERR(host->src_clk_cg))
|
||||
host->src_clk_cg = NULL;
|
||||
|
||||
host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
|
||||
"hrst");
|
||||
if (IS_ERR(host->reset))
|
||||
return PTR_ERR(host->reset);
|
||||
if (IS_ERR(host->reset)) {
|
||||
ret = PTR_ERR(host->reset);
|
||||
goto host_free;
|
||||
}
|
||||
|
||||
host->irq = platform_get_irq(pdev, 0);
|
||||
if (host->irq < 0) {
|
||||
|
|
|
|||
|
|
@ -157,32 +157,16 @@ struct mxcmci_host {
|
|||
enum mxcmci_type devtype;
|
||||
};
|
||||
|
||||
static const struct platform_device_id mxcmci_devtype[] = {
|
||||
{
|
||||
.name = "imx21-mmc",
|
||||
.driver_data = IMX21_MMC,
|
||||
}, {
|
||||
.name = "imx31-mmc",
|
||||
.driver_data = IMX31_MMC,
|
||||
}, {
|
||||
.name = "mpc512x-sdhc",
|
||||
.driver_data = MPC512X_MMC,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, mxcmci_devtype);
|
||||
|
||||
static const struct of_device_id mxcmci_of_match[] = {
|
||||
{
|
||||
.compatible = "fsl,imx21-mmc",
|
||||
.data = &mxcmci_devtype[IMX21_MMC],
|
||||
.data = (void *) IMX21_MMC,
|
||||
}, {
|
||||
.compatible = "fsl,imx31-mmc",
|
||||
.data = &mxcmci_devtype[IMX31_MMC],
|
||||
.data = (void *) IMX31_MMC,
|
||||
}, {
|
||||
.compatible = "fsl,mpc5121-sdhc",
|
||||
.data = &mxcmci_devtype[MPC512X_MMC],
|
||||
.data = (void *) MPC512X_MMC,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
|
|
@ -1001,13 +985,10 @@ static int mxcmci_probe(struct platform_device *pdev)
|
|||
int ret = 0, irq;
|
||||
bool dat3_card_detect = false;
|
||||
dma_cap_mask_t mask;
|
||||
const struct of_device_id *of_id;
|
||||
struct imxmmc_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
pr_info("i.MX/MPC512x SDHC driver\n");
|
||||
|
||||
of_id = of_match_device(mxcmci_of_match, &pdev->dev);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
|
|
@ -1044,12 +1025,7 @@ static int mxcmci_probe(struct platform_device *pdev)
|
|||
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
|
||||
mmc->max_seg_size = mmc->max_req_size;
|
||||
|
||||
if (of_id) {
|
||||
const struct platform_device_id *id_entry = of_id->data;
|
||||
host->devtype = id_entry->driver_data;
|
||||
} else {
|
||||
host->devtype = pdev->id_entry->driver_data;
|
||||
}
|
||||
host->devtype = (enum mxcmci_type)of_device_get_match_data(&pdev->dev);
|
||||
|
||||
/* adjust max_segs after devtype detection */
|
||||
if (!is_mpc512x_mmc(host))
|
||||
|
|
@ -1241,7 +1217,6 @@ static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
|
|||
static struct platform_driver mxcmci_driver = {
|
||||
.probe = mxcmci_probe,
|
||||
.remove = mxcmci_remove,
|
||||
.id_table = mxcmci_devtype,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
|
|
|||
|
|
@ -545,19 +545,6 @@ static const struct mmc_host_ops mxs_mmc_ops = {
|
|||
.enable_sdio_irq = mxs_mmc_enable_sdio_irq,
|
||||
};
|
||||
|
||||
static const struct platform_device_id mxs_ssp_ids[] = {
|
||||
{
|
||||
.name = "imx23-mmc",
|
||||
.driver_data = IMX23_SSP,
|
||||
}, {
|
||||
.name = "imx28-mmc",
|
||||
.driver_data = IMX28_SSP,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, mxs_ssp_ids);
|
||||
|
||||
static const struct of_device_id mxs_mmc_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx23-mmc", .data = (void *) IMX23_SSP, },
|
||||
{ .compatible = "fsl,imx28-mmc", .data = (void *) IMX28_SSP, },
|
||||
|
|
@ -567,8 +554,6 @@ MODULE_DEVICE_TABLE(of, mxs_mmc_dt_ids);
|
|||
|
||||
static int mxs_mmc_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(mxs_mmc_dt_ids, &pdev->dev);
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct mxs_mmc_host *host;
|
||||
struct mmc_host *mmc;
|
||||
|
|
@ -593,7 +578,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
|
|||
goto out_mmc_free;
|
||||
}
|
||||
|
||||
ssp->devid = (enum mxs_ssp_id) of_id->data;
|
||||
ssp->devid = (enum mxs_ssp_id)of_device_get_match_data(&pdev->dev);
|
||||
|
||||
host->mmc = mmc;
|
||||
host->sdio_irq_en = 0;
|
||||
|
|
@ -723,7 +708,6 @@ static SIMPLE_DEV_PM_OPS(mxs_mmc_pm_ops, mxs_mmc_suspend, mxs_mmc_resume);
|
|||
static struct platform_driver mxs_mmc_driver = {
|
||||
.probe = mxs_mmc_probe,
|
||||
.remove = mxs_mmc_remove,
|
||||
.id_table = mxs_ssp_ids,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
|
|
|
|||
|
|
@ -134,10 +134,9 @@ static void owl_mmc_update_reg(void __iomem *reg, unsigned int val, bool state)
|
|||
static irqreturn_t owl_irq_handler(int irq, void *devid)
|
||||
{
|
||||
struct owl_mmc_host *owl_host = devid;
|
||||
unsigned long flags;
|
||||
u32 state;
|
||||
|
||||
spin_lock_irqsave(&owl_host->lock, flags);
|
||||
spin_lock(&owl_host->lock);
|
||||
|
||||
state = readl(owl_host->base + OWL_REG_SD_STATE);
|
||||
if (state & OWL_SD_STATE_TEI) {
|
||||
|
|
@ -147,7 +146,7 @@ static irqreturn_t owl_irq_handler(int irq, void *devid)
|
|||
complete(&owl_host->sdc_complete);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&owl_host->lock, flags);
|
||||
spin_unlock(&owl_host->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -522,11 +521,11 @@ static void owl_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
|
||||
/* Enable DDR mode if requested */
|
||||
if (ios->timing == MMC_TIMING_UHS_DDR50) {
|
||||
owl_host->ddr_50 = 1;
|
||||
owl_host->ddr_50 = true;
|
||||
owl_mmc_update_reg(owl_host->base + OWL_REG_SD_EN,
|
||||
OWL_SD_EN_DDREN, true);
|
||||
} else {
|
||||
owl_host->ddr_50 = 0;
|
||||
owl_host->ddr_50 = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -731,6 +731,7 @@ static int pxamci_probe(struct platform_device *pdev)
|
|||
|
||||
host->power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(host->power)) {
|
||||
ret = PTR_ERR(host->power);
|
||||
dev_err(dev, "Failed requesting gpio_power\n");
|
||||
goto out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,28 +18,39 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/tmio.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
#include <linux/mfd/tmio.h>
|
||||
#include <linux/sh_dma.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pinctrl/pinctrl-state.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/sh_dma.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sys_soc.h>
|
||||
|
||||
#include "renesas_sdhi.h"
|
||||
#include "tmio_mmc.h"
|
||||
|
||||
#define HOST_MODE 0xe4
|
||||
#define CTL_HOST_MODE 0xe4
|
||||
#define HOST_MODE_GEN2_SDR50_WMODE BIT(0)
|
||||
#define HOST_MODE_GEN2_SDR104_WMODE BIT(0)
|
||||
#define HOST_MODE_GEN3_WMODE BIT(0)
|
||||
#define HOST_MODE_GEN3_BUSWIDTH BIT(8)
|
||||
|
||||
#define HOST_MODE_GEN3_16BIT HOST_MODE_GEN3_WMODE
|
||||
#define HOST_MODE_GEN3_32BIT (HOST_MODE_GEN3_WMODE | HOST_MODE_GEN3_BUSWIDTH)
|
||||
#define HOST_MODE_GEN3_64BIT 0
|
||||
|
||||
#define CTL_SDIF_MODE 0xe6
|
||||
#define SDIF_MODE_HS400 BIT(0)
|
||||
|
||||
#define SDHI_VER_GEN2_SDR50 0x490c
|
||||
#define SDHI_VER_RZ_A1 0x820b
|
||||
|
|
@ -60,26 +71,26 @@ static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
|
|||
*/
|
||||
switch (sd_ctrl_read16(host, CTL_VERSION)) {
|
||||
case SDHI_VER_GEN2_SDR50:
|
||||
val = (width == 32) ? 0x0001 : 0x0000;
|
||||
val = (width == 32) ? HOST_MODE_GEN2_SDR50_WMODE : 0;
|
||||
break;
|
||||
case SDHI_VER_GEN2_SDR104:
|
||||
val = (width == 32) ? 0x0000 : 0x0001;
|
||||
val = (width == 32) ? 0 : HOST_MODE_GEN2_SDR104_WMODE;
|
||||
break;
|
||||
case SDHI_VER_GEN3_SD:
|
||||
case SDHI_VER_GEN3_SDMMC:
|
||||
if (width == 64)
|
||||
val = 0x0000;
|
||||
val = HOST_MODE_GEN3_64BIT;
|
||||
else if (width == 32)
|
||||
val = 0x0101;
|
||||
val = HOST_MODE_GEN3_32BIT;
|
||||
else
|
||||
val = 0x0001;
|
||||
val = HOST_MODE_GEN3_16BIT;
|
||||
break;
|
||||
default:
|
||||
/* nothing to do */
|
||||
return;
|
||||
}
|
||||
|
||||
sd_ctrl_write16(host, HOST_MODE, val);
|
||||
sd_ctrl_write16(host, CTL_HOST_MODE, val);
|
||||
}
|
||||
|
||||
static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
|
||||
|
|
@ -373,7 +384,7 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
|
|||
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
|
||||
|
||||
/* Set HS400 mode */
|
||||
sd_ctrl_write16(host, CTL_SDIF_MODE, 0x0001 |
|
||||
sd_ctrl_write16(host, CTL_SDIF_MODE, SDIF_MODE_HS400 |
|
||||
sd_ctrl_read16(host, CTL_SDIF_MODE));
|
||||
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF,
|
||||
|
|
@ -424,9 +435,11 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
|
|||
priv->needs_adjust_hs400 = true;
|
||||
}
|
||||
|
||||
static void renesas_sdhi_reset_scc(struct tmio_mmc_host *host,
|
||||
struct renesas_sdhi *priv)
|
||||
static void renesas_sdhi_disable_scc(struct mmc_host *mmc)
|
||||
{
|
||||
struct tmio_mmc_host *host = mmc_priv(mmc);
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
|
||||
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
|
||||
|
||||
|
|
@ -434,14 +447,6 @@ static void renesas_sdhi_reset_scc(struct tmio_mmc_host *host,
|
|||
~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL &
|
||||
sd_scc_read32(host, priv,
|
||||
SH_MOBILE_SDHI_SCC_CKSEL));
|
||||
}
|
||||
|
||||
static void renesas_sdhi_disable_scc(struct mmc_host *mmc)
|
||||
{
|
||||
struct tmio_mmc_host *host = mmc_priv(mmc);
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
|
||||
renesas_sdhi_reset_scc(host, priv);
|
||||
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
|
||||
~SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN &
|
||||
|
|
@ -527,7 +532,7 @@ static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host,
|
|||
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
|
||||
|
||||
/* Reset HS400 mode */
|
||||
sd_ctrl_write16(host, CTL_SDIF_MODE, ~0x0001 &
|
||||
sd_ctrl_write16(host, CTL_SDIF_MODE, ~SDIF_MODE_HS400 &
|
||||
sd_ctrl_read16(host, CTL_SDIF_MODE));
|
||||
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, priv->scc_tappos);
|
||||
|
|
@ -552,24 +557,38 @@ static int renesas_sdhi_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_io
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* only populated for TMIO_MMC_MIN_RCAR2 */
|
||||
static void renesas_sdhi_reset(struct tmio_mmc_host *host)
|
||||
{
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
u16 val;
|
||||
|
||||
renesas_sdhi_reset_scc(host, priv);
|
||||
renesas_sdhi_reset_hs400_mode(host, priv);
|
||||
priv->needs_adjust_hs400 = false;
|
||||
if (priv->scc_ctl) {
|
||||
renesas_sdhi_disable_scc(host->mmc);
|
||||
renesas_sdhi_reset_hs400_mode(host, priv);
|
||||
priv->needs_adjust_hs400 = false;
|
||||
|
||||
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
|
||||
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, TMIO_MASK_INIT_RCAR2);
|
||||
|
||||
if (sd_ctrl_read16(host, CTL_VERSION) >= SDHI_VER_GEN3_SD) {
|
||||
val = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
|
||||
val |= CARD_OPT_EXTOP;
|
||||
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, val);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int renesas_sdhi_gen3_get_cycles(struct tmio_mmc_host *host)
|
||||
{
|
||||
u16 num, val = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
|
||||
|
||||
num = (val & CARD_OPT_TOP_MASK) >> CARD_OPT_TOP_SHIFT;
|
||||
return 1 << ((val & CARD_OPT_EXTOP ? 14 : 13) + num);
|
||||
|
||||
if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
|
||||
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK,
|
||||
TMIO_MASK_INIT_RCAR2);
|
||||
}
|
||||
|
||||
#define SH_MOBILE_SDHI_MIN_TAP_ROW 3
|
||||
|
|
@ -803,7 +822,7 @@ static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
|
|||
case CTL_SD_MEM_CARD_OPT:
|
||||
case CTL_TRANSACTION_CTL:
|
||||
case CTL_DMA_ENABLE:
|
||||
case HOST_MODE:
|
||||
case CTL_HOST_MODE:
|
||||
if (host->pdata->flags & TMIO_MMC_HAVE_CBSY)
|
||||
bit = TMIO_STAT_CMD_BUSY;
|
||||
fallthrough;
|
||||
|
|
@ -1005,11 +1024,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
|||
host->ops.start_signal_voltage_switch =
|
||||
renesas_sdhi_start_signal_voltage_switch;
|
||||
host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27;
|
||||
|
||||
if (of_data && of_data->scc_offset) {
|
||||
priv->scc_ctl = host->ctl + of_data->scc_offset;
|
||||
host->reset = renesas_sdhi_reset;
|
||||
}
|
||||
host->reset = renesas_sdhi_reset;
|
||||
}
|
||||
|
||||
/* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
|
||||
|
|
@ -1042,6 +1057,9 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
|||
/* All SDHI have SDIO status bits which must be 1 */
|
||||
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
|
||||
|
||||
/* All SDHI support HW busy detection */
|
||||
mmc_data->flags |= TMIO_MMC_USE_BUSY_TIMEOUT;
|
||||
|
||||
dev_pm_domain_start(&pdev->dev);
|
||||
|
||||
ret = renesas_sdhi_clk_enable(host);
|
||||
|
|
@ -1065,9 +1083,9 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
|||
quirks->hs400_calib_table + 1);
|
||||
}
|
||||
|
||||
ret = tmio_mmc_host_probe(host);
|
||||
if (ret < 0)
|
||||
goto edisclk;
|
||||
/* these have an EXTOP bit */
|
||||
if (ver >= SDHI_VER_GEN3_SD)
|
||||
host->get_timeout_cycles = renesas_sdhi_gen3_get_cycles;
|
||||
|
||||
/* Enable tuning iff we have an SCC and a supported mode */
|
||||
if (of_data && of_data->scc_offset &&
|
||||
|
|
@ -1093,6 +1111,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
|||
if (!hit)
|
||||
dev_warn(&host->pdev->dev, "Unknown clock rate for tuning\n");
|
||||
|
||||
priv->scc_ctl = host->ctl + of_data->scc_offset;
|
||||
host->check_retune = renesas_sdhi_check_scc_error;
|
||||
host->ops.execute_tuning = renesas_sdhi_execute_tuning;
|
||||
host->ops.prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning;
|
||||
|
|
@ -1100,6 +1119,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
|||
host->ops.hs400_complete = renesas_sdhi_hs400_complete;
|
||||
}
|
||||
|
||||
ret = tmio_mmc_host_probe(host);
|
||||
if (ret < 0)
|
||||
goto edisclk;
|
||||
|
||||
num_irqs = platform_irq_count(pdev);
|
||||
if (num_irqs < 0) {
|
||||
ret = num_irqs;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ struct realtek_pci_sdmmc {
|
|||
bool using_cookie;
|
||||
};
|
||||
|
||||
static int sdmmc_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios);
|
||||
|
||||
static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host)
|
||||
{
|
||||
return &(host->pdev->dev);
|
||||
|
|
@ -896,7 +898,10 @@ static int sd_set_bus_width(struct realtek_pci_sdmmc *host,
|
|||
static int sd_power_on(struct realtek_pci_sdmmc *host)
|
||||
{
|
||||
struct rtsx_pcr *pcr = host->pcr;
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
int err;
|
||||
u32 val;
|
||||
u8 test_mode;
|
||||
|
||||
if (host->power_state == SDMMC_POWER_ON)
|
||||
return 0;
|
||||
|
|
@ -923,6 +928,30 @@ static int sd_power_on(struct realtek_pci_sdmmc *host)
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (PCI_PID(pcr) == PID_5261) {
|
||||
/*
|
||||
* If test mode is set switch to SD Express mandatorily,
|
||||
* this is only for factory testing.
|
||||
*/
|
||||
rtsx_pci_read_register(pcr, RTS5261_FW_CFG_INFO0, &test_mode);
|
||||
if (test_mode & RTS5261_FW_EXPRESS_TEST_MASK) {
|
||||
sdmmc_init_sd_express(mmc, NULL);
|
||||
return 0;
|
||||
}
|
||||
if (pcr->extra_caps & EXTRA_CAPS_SD_EXPRESS)
|
||||
mmc->caps2 |= MMC_CAP2_SD_EXP | MMC_CAP2_SD_EXP_1_2V;
|
||||
/*
|
||||
* HW read wp status when resuming from S3/S4,
|
||||
* and then picks SD legacy interface if it's set
|
||||
* in read-only mode.
|
||||
*/
|
||||
val = rtsx_pci_readl(pcr, RTSX_BIPR);
|
||||
if (val & SD_WRITE_PROTECT) {
|
||||
pcr->extra_caps &= ~EXTRA_CAPS_SD_EXPRESS;
|
||||
mmc->caps2 &= ~(MMC_CAP2_SD_EXP | MMC_CAP2_SD_EXP_1_2V);
|
||||
}
|
||||
}
|
||||
|
||||
host->power_state = SDMMC_POWER_ON;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1309,6 +1338,45 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int sdmmc_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
|
||||
{
|
||||
u32 relink_time;
|
||||
struct realtek_pci_sdmmc *host = mmc_priv(mmc);
|
||||
struct rtsx_pcr *pcr = host->pcr;
|
||||
|
||||
/* Set relink_time for changing to PCIe card */
|
||||
relink_time = 0x8FFF;
|
||||
|
||||
rtsx_pci_write_register(pcr, 0xFF01, 0xFF, relink_time);
|
||||
rtsx_pci_write_register(pcr, 0xFF02, 0xFF, relink_time >> 8);
|
||||
rtsx_pci_write_register(pcr, 0xFF03, 0x01, relink_time >> 16);
|
||||
|
||||
rtsx_pci_write_register(pcr, PETXCFG, 0x80, 0x80);
|
||||
rtsx_pci_write_register(pcr, LDO_VCC_CFG0,
|
||||
RTS5261_LDO1_OCP_THD_MASK,
|
||||
pcr->option.sd_800mA_ocp_thd);
|
||||
|
||||
if (pcr->ops->disable_auto_blink)
|
||||
pcr->ops->disable_auto_blink(pcr);
|
||||
|
||||
/* For PCIe/NVMe mode can't enter delink issue */
|
||||
pcr->hw_param.interrupt_en &= ~(SD_INT_EN);
|
||||
rtsx_pci_writel(pcr, RTSX_BIER, pcr->hw_param.interrupt_en);
|
||||
|
||||
rtsx_pci_write_register(pcr, RTS5260_AUTOLOAD_CFG4,
|
||||
RTS5261_AUX_CLK_16M_EN, RTS5261_AUX_CLK_16M_EN);
|
||||
rtsx_pci_write_register(pcr, RTS5261_FW_CFG0,
|
||||
RTS5261_FW_ENTER_EXPRESS, RTS5261_FW_ENTER_EXPRESS);
|
||||
rtsx_pci_write_register(pcr, RTS5261_FW_CFG1,
|
||||
RTS5261_MCU_CLOCK_GATING, RTS5261_MCU_CLOCK_GATING);
|
||||
rtsx_pci_write_register(pcr, RTS5261_FW_CFG1,
|
||||
RTS5261_MCU_BUS_SEL_MASK | RTS5261_MCU_CLOCK_SEL_MASK
|
||||
| RTS5261_DRIVER_ENABLE_FW,
|
||||
RTS5261_MCU_CLOCK_SEL_16M | RTS5261_DRIVER_ENABLE_FW);
|
||||
host->eject = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
|
||||
.pre_req = sdmmc_pre_req,
|
||||
.post_req = sdmmc_post_req,
|
||||
|
|
@ -1318,6 +1386,7 @@ static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
|
|||
.get_cd = sdmmc_get_cd,
|
||||
.start_signal_voltage_switch = sdmmc_switch_voltage,
|
||||
.execute_tuning = sdmmc_execute_tuning,
|
||||
.init_sd_express = sdmmc_init_sd_express,
|
||||
};
|
||||
|
||||
static void init_extra_caps(struct realtek_pci_sdmmc *host)
|
||||
|
|
@ -1339,6 +1408,8 @@ static void init_extra_caps(struct realtek_pci_sdmmc *host)
|
|||
mmc->caps |= MMC_CAP_8_BIT_DATA;
|
||||
if (pcr->extra_caps & EXTRA_CAPS_NO_MMC)
|
||||
mmc->caps2 |= MMC_CAP2_NO_MMC;
|
||||
if (pcr->extra_caps & EXTRA_CAPS_SD_EXPRESS)
|
||||
mmc->caps2 |= MMC_CAP2_SD_EXP | MMC_CAP2_SD_EXP_1_2V;
|
||||
}
|
||||
|
||||
static void realtek_init_host(struct realtek_pci_sdmmc *host)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
#include <linux/cpufreq.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
* Copyright (c) 2012, Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -545,10 +546,41 @@ struct amd_sdhci_host {
|
|||
|
||||
static int amd_select_drive_strength(struct mmc_card *card,
|
||||
unsigned int max_dtr, int host_drv,
|
||||
int card_drv, int *drv_type)
|
||||
int card_drv, int *host_driver_strength)
|
||||
{
|
||||
*drv_type = MMC_SET_DRIVER_TYPE_A;
|
||||
return MMC_SET_DRIVER_TYPE_A;
|
||||
struct sdhci_host *host = mmc_priv(card->host);
|
||||
u16 preset, preset_driver_strength;
|
||||
|
||||
/*
|
||||
* This method is only called by mmc_select_hs200 so we only need to
|
||||
* read from the HS200 (SDR104) preset register.
|
||||
*
|
||||
* Firmware that has "invalid/default" presets return a driver strength
|
||||
* of A. This matches the previously hard coded value.
|
||||
*/
|
||||
preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
|
||||
preset_driver_strength = FIELD_GET(SDHCI_PRESET_DRV_MASK, preset);
|
||||
|
||||
/*
|
||||
* We want the controller driver strength to match the card's driver
|
||||
* strength so they have similar rise/fall times.
|
||||
*
|
||||
* The controller driver strength set by this method is sticky for all
|
||||
* timings after this method is called. This unfortunately means that
|
||||
* while HS400 tuning is in progress we end up with mismatched driver
|
||||
* strengths between the controller and the card. HS400 tuning requires
|
||||
* switching from HS400->DDR52->HS->HS200->HS400. So the driver mismatch
|
||||
* happens while in DDR52 and HS modes. This has not been observed to
|
||||
* cause problems. Enabling presets would fix this issue.
|
||||
*/
|
||||
*host_driver_strength = preset_driver_strength;
|
||||
|
||||
/*
|
||||
* The resulting card driver strength is only set when switching the
|
||||
* card's timing to HS200 or HS400. The card will use the default driver
|
||||
* strength (B) for any other mode.
|
||||
*/
|
||||
return preset_driver_strength;
|
||||
}
|
||||
|
||||
static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host, bool enable)
|
||||
|
|
|
|||
|
|
@ -296,22 +296,6 @@ struct pltfm_imx_data {
|
|||
struct pm_qos_request pm_qos_req;
|
||||
};
|
||||
|
||||
static const struct platform_device_id imx_esdhc_devtype[] = {
|
||||
{
|
||||
.name = "sdhci-esdhc-imx25",
|
||||
.driver_data = (kernel_ulong_t) &esdhc_imx25_data,
|
||||
}, {
|
||||
.name = "sdhci-esdhc-imx35",
|
||||
.driver_data = (kernel_ulong_t) &esdhc_imx35_data,
|
||||
}, {
|
||||
.name = "sdhci-esdhc-imx51",
|
||||
.driver_data = (kernel_ulong_t) &esdhc_imx51_data,
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype);
|
||||
|
||||
static const struct of_device_id imx_esdhc_dt_ids[] = {
|
||||
{ .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data, },
|
||||
{ .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, },
|
||||
|
|
@ -1531,72 +1515,6 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
|
|||
}
|
||||
#endif
|
||||
|
||||
static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev,
|
||||
struct sdhci_host *host,
|
||||
struct pltfm_imx_data *imx_data)
|
||||
{
|
||||
struct esdhc_platform_data *boarddata = &imx_data->boarddata;
|
||||
int err;
|
||||
|
||||
if (!host->mmc->parent->platform_data) {
|
||||
dev_err(mmc_dev(host->mmc), "no board data!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
imx_data->boarddata = *((struct esdhc_platform_data *)
|
||||
host->mmc->parent->platform_data);
|
||||
/* write_protect */
|
||||
if (boarddata->wp_type == ESDHC_WP_GPIO) {
|
||||
host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
|
||||
|
||||
err = mmc_gpiod_request_ro(host->mmc, "wp", 0, 0);
|
||||
if (err) {
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
"failed to request write-protect gpio!\n");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* card_detect */
|
||||
switch (boarddata->cd_type) {
|
||||
case ESDHC_CD_GPIO:
|
||||
err = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0);
|
||||
if (err) {
|
||||
dev_err(mmc_dev(host->mmc),
|
||||
"failed to request card-detect gpio!\n");
|
||||
return err;
|
||||
}
|
||||
fallthrough;
|
||||
|
||||
case ESDHC_CD_CONTROLLER:
|
||||
/* we have a working card_detect back */
|
||||
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
|
||||
break;
|
||||
|
||||
case ESDHC_CD_PERMANENT:
|
||||
host->mmc->caps |= MMC_CAP_NONREMOVABLE;
|
||||
break;
|
||||
|
||||
case ESDHC_CD_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (boarddata->max_bus_width) {
|
||||
case 8:
|
||||
host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
|
||||
break;
|
||||
case 4:
|
||||
host->mmc->caps |= MMC_CAP_4_BIT_DATA;
|
||||
break;
|
||||
case 1:
|
||||
default:
|
||||
host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id =
|
||||
|
|
@ -1616,8 +1534,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
|
|||
|
||||
imx_data = sdhci_pltfm_priv(pltfm_host);
|
||||
|
||||
imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *)
|
||||
pdev->id_entry->driver_data;
|
||||
imx_data->socdata = of_id->data;
|
||||
|
||||
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
|
||||
cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0);
|
||||
|
|
@ -1713,10 +1630,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
|
|||
goto disable_ahb_clk;
|
||||
}
|
||||
|
||||
if (of_id)
|
||||
err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
|
||||
else
|
||||
err = sdhci_esdhc_imx_probe_nondt(pdev, host, imx_data);
|
||||
err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
|
||||
if (err)
|
||||
goto disable_ahb_clk;
|
||||
|
||||
|
|
@ -1929,7 +1843,6 @@ static struct platform_driver sdhci_esdhc_imx_driver = {
|
|||
.of_match_table = imx_esdhc_dt_ids,
|
||||
.pm = &sdhci_esdhc_pmops,
|
||||
},
|
||||
.id_table = imx_esdhc_devtype,
|
||||
.probe = sdhci_esdhc_imx_probe,
|
||||
.remove = sdhci_esdhc_imx_remove,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -248,7 +248,6 @@ struct sdhci_msm_variant_ops {
|
|||
struct sdhci_msm_variant_info {
|
||||
bool mci_removed;
|
||||
bool restore_dll_config;
|
||||
bool uses_tassadar_dll;
|
||||
const struct sdhci_msm_variant_ops *var_ops;
|
||||
const struct sdhci_msm_offset *offset;
|
||||
};
|
||||
|
|
@ -2154,18 +2153,10 @@ static const struct sdhci_msm_variant_info sdm845_sdhci_var = {
|
|||
.offset = &sdhci_msm_v5_offset,
|
||||
};
|
||||
|
||||
static const struct sdhci_msm_variant_info sm8250_sdhci_var = {
|
||||
.mci_removed = true,
|
||||
.uses_tassadar_dll = 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},
|
||||
{.compatible = "qcom,sm8250-sdhci", .data = &sm8250_sdhci_var},
|
||||
{.compatible = "qcom,sc7180-sdhci", .data = &sdm845_sdhci_var},
|
||||
{},
|
||||
};
|
||||
|
|
@ -2249,7 +2240,6 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
|||
msm_host->restore_dll_config = var_info->restore_dll_config;
|
||||
msm_host->var_ops = var_info->var_ops;
|
||||
msm_host->offset = var_info->offset;
|
||||
msm_host->uses_tassadar_dll = var_info->uses_tassadar_dll;
|
||||
|
||||
msm_offset = msm_host->offset;
|
||||
|
||||
|
|
@ -2396,6 +2386,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
|||
if (core_major == 1 && core_minor >= 0x49)
|
||||
msm_host->updated_ddr_cfg = true;
|
||||
|
||||
if (core_major == 1 && core_minor >= 0x71)
|
||||
msm_host->uses_tassadar_dll = true;
|
||||
|
||||
ret = sdhci_msm_register_vreg(msm_host);
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
|
|
|
|||
|
|
@ -624,6 +624,7 @@ static int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
|
|||
case MMC_TIMING_MMC_HS200:
|
||||
/* For 200MHz clock, 8 Taps are available */
|
||||
tap_max = 8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -692,6 +693,7 @@ static int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees)
|
|||
case MMC_TIMING_MMC_HS200:
|
||||
/* For 200MHz clock, 30 Taps are available */
|
||||
tap_max = 30;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -751,6 +753,7 @@ static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
|
|||
case MMC_TIMING_MMC_HS200:
|
||||
/* For 200MHz clock, 8 Taps are available */
|
||||
tap_max = 8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -817,6 +820,7 @@ static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees)
|
|||
case MMC_TIMING_MMC_HS200:
|
||||
/* For 200MHz clock, 30 Taps are available */
|
||||
tap_max = 30;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,9 @@
|
|||
#define PCIE_GLI_9763E_SCR 0x8E0
|
||||
#define GLI_9763E_SCR_AXI_REQ BIT(9)
|
||||
|
||||
#define PCIE_GLI_9763E_MMC_CTRL 0x960
|
||||
#define GLI_9763E_HS400_SLOW BIT(3)
|
||||
|
||||
#define SDHCI_GLI_9763E_CQE_BASE_ADDR 0x200
|
||||
#define GLI_9763E_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \
|
||||
SDHCI_TRNS_BLK_CNT_EN | \
|
||||
|
|
@ -97,6 +100,10 @@
|
|||
#define GLI_9755_WT_EN_ON 0x1
|
||||
#define GLI_9755_WT_EN_OFF 0x0
|
||||
|
||||
#define PCI_GLI_9755_PECONF 0x44
|
||||
#define PCI_GLI_9755_LFCLK GENMASK(14, 12)
|
||||
#define PCI_GLI_9755_DMACLK BIT(29)
|
||||
|
||||
#define PCI_GLI_9755_PLL 0x64
|
||||
#define PCI_GLI_9755_PLL_LDIV GENMASK(9, 0)
|
||||
#define PCI_GLI_9755_PLL_PDIV GENMASK(14, 12)
|
||||
|
|
@ -519,6 +526,21 @@ static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock)
|
|||
sdhci_enable_clk(host, clk);
|
||||
}
|
||||
|
||||
static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
struct pci_dev *pdev = slot->chip->pdev;
|
||||
u32 value;
|
||||
|
||||
gl9755_wt_on(pdev);
|
||||
|
||||
pci_read_config_dword(pdev, PCI_GLI_9755_PECONF, &value);
|
||||
value &= ~PCI_GLI_9755_LFCLK;
|
||||
value &= ~PCI_GLI_9755_DMACLK;
|
||||
pci_write_config_dword(pdev, PCI_GLI_9755_PECONF, value);
|
||||
|
||||
gl9755_wt_off(pdev);
|
||||
}
|
||||
|
||||
static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
|
||||
{
|
||||
struct sdhci_host *host = slot->host;
|
||||
|
|
@ -534,6 +556,7 @@ static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot)
|
|||
{
|
||||
struct sdhci_host *host = slot->host;
|
||||
|
||||
gl9755_hw_setting(slot);
|
||||
gli_pcie_enable_msi(slot);
|
||||
slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
|
||||
sdhci_enable_v4_mode(host);
|
||||
|
|
@ -764,6 +787,10 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
|
|||
value |= GLI_9763E_SCR_AXI_REQ;
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, &value);
|
||||
value &= ~GLI_9763E_HS400_SLOW;
|
||||
pci_write_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, value);
|
||||
|
||||
pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value);
|
||||
value &= ~GLI_9763E_VHS_REV;
|
||||
value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R);
|
||||
|
|
|
|||
|
|
@ -121,10 +121,9 @@ static void pic32_sdhci_shared_bus(struct platform_device *pdev)
|
|||
writel(bus, host->ioaddr + SDH_SHARED_BUS_CTRL);
|
||||
}
|
||||
|
||||
static int pic32_sdhci_probe_platform(struct platform_device *pdev,
|
||||
static void pic32_sdhci_probe_platform(struct platform_device *pdev,
|
||||
struct pic32_sdhci_priv *pdata)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 caps_slot_type;
|
||||
struct sdhci_host *host = platform_get_drvdata(pdev);
|
||||
|
||||
|
|
@ -133,8 +132,6 @@ static int pic32_sdhci_probe_platform(struct platform_device *pdev,
|
|||
caps_slot_type = (host->caps & SDH_CAPS_SDH_SLOT_TYPE_MASK) >> 30;
|
||||
if (caps_slot_type == SDH_SLOT_TYPE_SHARED_BUS)
|
||||
pic32_sdhci_shared_bus(pdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pic32_sdhci_probe(struct platform_device *pdev)
|
||||
|
|
@ -193,11 +190,7 @@ static int pic32_sdhci_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_base_clk;
|
||||
|
||||
ret = pic32_sdhci_probe_platform(pdev, sdhci_pdata);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to probe platform!\n");
|
||||
goto err_base_clk;
|
||||
}
|
||||
pic32_sdhci_probe_platform(pdev, sdhci_pdata);
|
||||
|
||||
ret = sdhci_add_host(host);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -788,7 +788,7 @@ static struct platform_driver sdhci_sprd_driver = {
|
|||
.driver = {
|
||||
.name = "sdhci_sprd_r11",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = of_match_ptr(sdhci_sprd_of_match),
|
||||
.of_match_table = sdhci_sprd_of_match,
|
||||
.pm = &sdhci_sprd_pm_ops,
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -523,7 +523,7 @@ static struct platform_driver sdhci_st_driver = {
|
|||
.name = "sdhci-st",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.pm = &sdhci_st_pmops,
|
||||
.of_match_table = of_match_ptr(st_sdhci_match),
|
||||
.of_match_table = st_sdhci_match,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1272,7 +1272,7 @@ static void tegra_sdhci_set_timeout(struct sdhci_host *host,
|
|||
* busy wait mode.
|
||||
*/
|
||||
val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
|
||||
if (cmd && cmd->busy_timeout >= 11 * HZ)
|
||||
if (cmd && cmd->busy_timeout >= 11 * MSEC_PER_SEC)
|
||||
val |= SDHCI_MISC_CTRL_ERASE_TIMEOUT_LIMIT;
|
||||
else
|
||||
val &= ~SDHCI_MISC_CTRL_ERASE_TIMEOUT_LIMIT;
|
||||
|
|
|
|||
|
|
@ -651,11 +651,13 @@ static int get_dt_pad_ctrl_data(struct sdhci_host *host,
|
|||
struct device_node *np,
|
||||
struct xenon_emmc_phy_params *params)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
|
||||
int ret = 0;
|
||||
const char *name;
|
||||
struct resource iomem;
|
||||
|
||||
if (of_device_is_compatible(np, "marvell,armada-3700-sdhci"))
|
||||
if (priv->hw_version == XENON_A3700)
|
||||
params->pad_ctrl.set_soc_pad = armada_3700_soc_pad_voltage_set;
|
||||
else
|
||||
return 0;
|
||||
|
|
@ -689,35 +691,37 @@ static int get_dt_pad_ctrl_data(struct sdhci_host *host,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int xenon_emmc_phy_parse_param_dt(struct sdhci_host *host,
|
||||
struct device_node *np,
|
||||
struct xenon_emmc_phy_params *params)
|
||||
static int xenon_emmc_phy_parse_params(struct sdhci_host *host,
|
||||
struct device *dev,
|
||||
struct xenon_emmc_phy_params *params)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
params->slow_mode = false;
|
||||
if (of_property_read_bool(np, "marvell,xenon-phy-slow-mode"))
|
||||
if (device_property_read_bool(dev, "marvell,xenon-phy-slow-mode"))
|
||||
params->slow_mode = true;
|
||||
|
||||
params->znr = XENON_ZNR_DEF_VALUE;
|
||||
if (!of_property_read_u32(np, "marvell,xenon-phy-znr", &value))
|
||||
if (!device_property_read_u32(dev, "marvell,xenon-phy-znr", &value))
|
||||
params->znr = value & XENON_ZNR_MASK;
|
||||
|
||||
params->zpr = XENON_ZPR_DEF_VALUE;
|
||||
if (!of_property_read_u32(np, "marvell,xenon-phy-zpr", &value))
|
||||
if (!device_property_read_u32(dev, "marvell,xenon-phy-zpr", &value))
|
||||
params->zpr = value & XENON_ZPR_MASK;
|
||||
|
||||
params->nr_tun_times = XENON_TUN_CONSECUTIVE_TIMES;
|
||||
if (!of_property_read_u32(np, "marvell,xenon-phy-nr-success-tun",
|
||||
&value))
|
||||
if (!device_property_read_u32(dev, "marvell,xenon-phy-nr-success-tun",
|
||||
&value))
|
||||
params->nr_tun_times = value & XENON_TUN_CONSECUTIVE_TIMES_MASK;
|
||||
|
||||
params->tun_step_divider = XENON_TUNING_STEP_DIVIDER;
|
||||
if (!of_property_read_u32(np, "marvell,xenon-phy-tun-step-divider",
|
||||
&value))
|
||||
if (!device_property_read_u32(dev, "marvell,xenon-phy-tun-step-divider",
|
||||
&value))
|
||||
params->tun_step_divider = value & 0xFF;
|
||||
|
||||
return get_dt_pad_ctrl_data(host, np, params);
|
||||
if (dev->of_node)
|
||||
return get_dt_pad_ctrl_data(host, dev->of_node, params);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set SoC PHY Voltage PAD */
|
||||
|
|
@ -811,7 +815,7 @@ int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int xenon_add_phy(struct device_node *np, struct sdhci_host *host,
|
||||
static int xenon_add_phy(struct device *dev, struct sdhci_host *host,
|
||||
const char *phy_name)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
|
@ -830,15 +834,15 @@ static int xenon_add_phy(struct device_node *np, struct sdhci_host *host,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return xenon_emmc_phy_parse_param_dt(host, np, priv->phy_params);
|
||||
return xenon_emmc_phy_parse_params(host, dev, priv->phy_params);
|
||||
}
|
||||
|
||||
int xenon_phy_parse_dt(struct device_node *np, struct sdhci_host *host)
|
||||
int xenon_phy_parse_params(struct device *dev, struct sdhci_host *host)
|
||||
{
|
||||
const char *phy_type = NULL;
|
||||
|
||||
if (!of_property_read_string(np, "marvell,xenon-phy-type", &phy_type))
|
||||
return xenon_add_phy(np, host, phy_type);
|
||||
if (!device_property_read_string(dev, "marvell,xenon-phy-type", &phy_type))
|
||||
return xenon_add_phy(dev, host, phy_type);
|
||||
|
||||
return xenon_add_phy(np, host, "emmc 5.1 phy");
|
||||
return xenon_add_phy(dev, host, "emmc 5.1 phy");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
* Special thanks to Video BG4 project team.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -247,6 +248,16 @@ static void xenon_voltage_switch(struct sdhci_host *host)
|
|||
sdhci_readw(host, SDHCI_HOST_CONTROL2);
|
||||
}
|
||||
|
||||
static unsigned int xenon_get_max_clock(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
||||
if (pltfm_host->clk)
|
||||
return sdhci_pltfm_clk_get_max_clock(host);
|
||||
else
|
||||
return pltfm_host->clock;
|
||||
}
|
||||
|
||||
static const struct sdhci_ops sdhci_xenon_ops = {
|
||||
.voltage_switch = xenon_voltage_switch,
|
||||
.set_clock = sdhci_set_clock,
|
||||
|
|
@ -254,7 +265,7 @@ static const struct sdhci_ops sdhci_xenon_ops = {
|
|||
.set_bus_width = sdhci_set_bus_width,
|
||||
.reset = xenon_reset,
|
||||
.set_uhs_signaling = xenon_set_uhs_signaling,
|
||||
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
||||
.get_max_clock = xenon_get_max_clock,
|
||||
};
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_xenon_pdata = {
|
||||
|
|
@ -407,9 +418,9 @@ static void xenon_replace_mmc_host_ops(struct sdhci_host *host)
|
|||
* Refer to XENON_SYS_CFG_INFO register
|
||||
* tun-count: the interval between re-tuning
|
||||
*/
|
||||
static int xenon_probe_dt(struct platform_device *pdev)
|
||||
static int xenon_probe_params(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sdhci_host *host = platform_get_drvdata(pdev);
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
|
|
@ -418,11 +429,11 @@ static int xenon_probe_dt(struct platform_device *pdev)
|
|||
u32 tuning_count;
|
||||
|
||||
/* Disable HS200 on Armada AP806 */
|
||||
if (of_device_is_compatible(np, "marvell,armada-ap806-sdhci"))
|
||||
if (priv->hw_version == XENON_AP806)
|
||||
host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
|
||||
|
||||
sdhc_id = 0x0;
|
||||
if (!of_property_read_u32(np, "marvell,xenon-sdhc-id", &sdhc_id)) {
|
||||
if (!device_property_read_u32(dev, "marvell,xenon-sdhc-id", &sdhc_id)) {
|
||||
nr_sdhc = sdhci_readl(host, XENON_SYS_CFG_INFO);
|
||||
nr_sdhc &= XENON_NR_SUPPORTED_SLOT_MASK;
|
||||
if (unlikely(sdhc_id > nr_sdhc)) {
|
||||
|
|
@ -434,8 +445,8 @@ static int xenon_probe_dt(struct platform_device *pdev)
|
|||
priv->sdhc_id = sdhc_id;
|
||||
|
||||
tuning_count = XENON_DEF_TUNING_COUNT;
|
||||
if (!of_property_read_u32(np, "marvell,xenon-tun-count",
|
||||
&tuning_count)) {
|
||||
if (!device_property_read_u32(dev, "marvell,xenon-tun-count",
|
||||
&tuning_count)) {
|
||||
if (unlikely(tuning_count >= XENON_TMR_RETUN_NO_PRESENT)) {
|
||||
dev_err(mmc_dev(mmc), "Wrong Re-tuning Count. Set default value %d\n",
|
||||
XENON_DEF_TUNING_COUNT);
|
||||
|
|
@ -444,7 +455,7 @@ static int xenon_probe_dt(struct platform_device *pdev)
|
|||
}
|
||||
priv->tuning_count = tuning_count;
|
||||
|
||||
return xenon_phy_parse_dt(np, host);
|
||||
return xenon_phy_parse_params(dev, host);
|
||||
}
|
||||
|
||||
static int xenon_sdhc_prepare(struct sdhci_host *host)
|
||||
|
|
@ -483,6 +494,7 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host)
|
|||
static int xenon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sdhci_host *host;
|
||||
struct xenon_priv *priv;
|
||||
int err;
|
||||
|
|
@ -495,43 +507,47 @@ static int xenon_probe(struct platform_device *pdev)
|
|||
pltfm_host = sdhci_priv(host);
|
||||
priv = sdhci_pltfm_priv(pltfm_host);
|
||||
|
||||
priv->hw_version = (unsigned long)device_get_match_data(&pdev->dev);
|
||||
|
||||
/*
|
||||
* Link Xenon specific mmc_host_ops function,
|
||||
* to replace standard ones in sdhci_ops.
|
||||
*/
|
||||
xenon_replace_mmc_host_ops(host);
|
||||
|
||||
pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
|
||||
if (IS_ERR(pltfm_host->clk)) {
|
||||
err = PTR_ERR(pltfm_host->clk);
|
||||
dev_err(&pdev->dev, "Failed to setup input clk: %d\n", err);
|
||||
goto free_pltfm;
|
||||
}
|
||||
err = clk_prepare_enable(pltfm_host->clk);
|
||||
if (err)
|
||||
goto free_pltfm;
|
||||
|
||||
priv->axi_clk = devm_clk_get(&pdev->dev, "axi");
|
||||
if (IS_ERR(priv->axi_clk)) {
|
||||
err = PTR_ERR(priv->axi_clk);
|
||||
if (err == -EPROBE_DEFER)
|
||||
goto err_clk;
|
||||
} else {
|
||||
err = clk_prepare_enable(priv->axi_clk);
|
||||
if (dev->of_node) {
|
||||
pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
|
||||
if (IS_ERR(pltfm_host->clk)) {
|
||||
err = PTR_ERR(pltfm_host->clk);
|
||||
dev_err(&pdev->dev, "Failed to setup input clk: %d\n", err);
|
||||
goto free_pltfm;
|
||||
}
|
||||
err = clk_prepare_enable(pltfm_host->clk);
|
||||
if (err)
|
||||
goto err_clk;
|
||||
goto free_pltfm;
|
||||
|
||||
priv->axi_clk = devm_clk_get(&pdev->dev, "axi");
|
||||
if (IS_ERR(priv->axi_clk)) {
|
||||
err = PTR_ERR(priv->axi_clk);
|
||||
if (err == -EPROBE_DEFER)
|
||||
goto err_clk;
|
||||
} else {
|
||||
err = clk_prepare_enable(priv->axi_clk);
|
||||
if (err)
|
||||
goto err_clk;
|
||||
}
|
||||
}
|
||||
|
||||
err = mmc_of_parse(host->mmc);
|
||||
if (err)
|
||||
goto err_clk_axi;
|
||||
|
||||
sdhci_get_of_property(pdev);
|
||||
sdhci_get_property(pdev);
|
||||
|
||||
xenon_set_acg(host, false);
|
||||
|
||||
/* Xenon specific dt parse */
|
||||
err = xenon_probe_dt(pdev);
|
||||
/* Xenon specific parameters parse */
|
||||
err = xenon_probe_params(pdev);
|
||||
if (err)
|
||||
goto err_clk_axi;
|
||||
|
||||
|
|
@ -667,18 +683,29 @@ static const struct dev_pm_ops sdhci_xenon_dev_pm_ops = {
|
|||
};
|
||||
|
||||
static const struct of_device_id sdhci_xenon_dt_ids[] = {
|
||||
{ .compatible = "marvell,armada-ap806-sdhci",},
|
||||
{ .compatible = "marvell,armada-cp110-sdhci",},
|
||||
{ .compatible = "marvell,armada-3700-sdhci",},
|
||||
{ .compatible = "marvell,armada-ap806-sdhci", .data = (void *)XENON_AP806},
|
||||
{ .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110},
|
||||
{ .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id sdhci_xenon_acpi_ids[] = {
|
||||
{ .id = "MRVL0002", XENON_AP806},
|
||||
{ .id = "MRVL0003", XENON_AP807},
|
||||
{ .id = "MRVL0004", XENON_CP110},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, sdhci_xenon_acpi_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver sdhci_xenon_driver = {
|
||||
.driver = {
|
||||
.name = "xenon-sdhci",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = sdhci_xenon_dt_ids,
|
||||
.acpi_match_table = ACPI_PTR(sdhci_xenon_acpi_ids),
|
||||
.pm = &sdhci_xenon_dev_pm_ops,
|
||||
},
|
||||
.probe = xenon_probe,
|
||||
|
|
|
|||
|
|
@ -53,6 +53,13 @@
|
|||
#define XENON_CTRL_HS200 0x5
|
||||
#define XENON_CTRL_HS400 0x6
|
||||
|
||||
enum xenon_variant {
|
||||
XENON_A3700,
|
||||
XENON_AP806,
|
||||
XENON_AP807,
|
||||
XENON_CP110
|
||||
};
|
||||
|
||||
struct xenon_priv {
|
||||
unsigned char tuning_count;
|
||||
/* idx of SDHC */
|
||||
|
|
@ -90,11 +97,12 @@ struct xenon_priv {
|
|||
void *phy_params;
|
||||
struct xenon_emmc_phy_regs *emmc_phy_regs;
|
||||
bool restore_needed;
|
||||
enum xenon_variant hw_version;
|
||||
};
|
||||
|
||||
int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios);
|
||||
int xenon_phy_parse_dt(struct device_node *np,
|
||||
struct sdhci_host *host);
|
||||
int xenon_phy_parse_params(struct device *dev,
|
||||
struct sdhci_host *host);
|
||||
void xenon_soc_pad_ctrl(struct sdhci_host *host,
|
||||
unsigned char signal_voltage);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3994,10 +3994,10 @@ void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver,
|
|||
if (host->v4_mode)
|
||||
sdhci_do_enable_v4_mode(host);
|
||||
|
||||
of_property_read_u64(mmc_dev(host->mmc)->of_node,
|
||||
"sdhci-caps-mask", &dt_caps_mask);
|
||||
of_property_read_u64(mmc_dev(host->mmc)->of_node,
|
||||
"sdhci-caps", &dt_caps);
|
||||
device_property_read_u64(mmc_dev(host->mmc),
|
||||
"sdhci-caps-mask", &dt_caps_mask);
|
||||
device_property_read_u64(mmc_dev(host->mmc),
|
||||
"sdhci-caps", &dt_caps);
|
||||
|
||||
v = ver ? *ver : sdhci_readw(host, SDHCI_HOST_VERSION);
|
||||
host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/mmc/sdio.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
|
@ -1515,7 +1516,7 @@ static struct platform_driver sunxi_mmc_driver = {
|
|||
.driver = {
|
||||
.name = "sunxi-mmc",
|
||||
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
|
||||
.of_match_table = of_match_ptr(sunxi_mmc_of_match),
|
||||
.of_match_table = sunxi_mmc_of_match,
|
||||
.pm = &sunxi_mmc_pm_ops,
|
||||
},
|
||||
.probe = sunxi_mmc_probe,
|
||||
|
|
|
|||
|
|
@ -174,8 +174,7 @@ static int tmio_mmc_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto host_remove;
|
||||
|
||||
pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
|
||||
(unsigned long)host->ctl, irq);
|
||||
pr_info("%s at 0x%p irq %d\n", mmc_hostname(host->mmc), host->ctl, irq);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
#define CTL_DMA_ENABLE 0xd8
|
||||
#define CTL_RESET_SD 0xe0
|
||||
#define CTL_VERSION 0xe2
|
||||
#define CTL_SDIF_MODE 0xe6
|
||||
|
||||
/* Definitions for values the CTL_STOP_INTERNAL_ACTION register can take */
|
||||
#define TMIO_STOP_STP BIT(0)
|
||||
|
|
@ -81,7 +80,11 @@
|
|||
#define CLK_CTL_SCLKEN BIT(8)
|
||||
|
||||
/* Definitions for values the CTL_SD_MEM_CARD_OPT register can take */
|
||||
#define CARD_OPT_TOP_MASK 0xf0
|
||||
#define CARD_OPT_TOP_SHIFT 4
|
||||
#define CARD_OPT_EXTOP BIT(9) /* first appeared on R-Car Gen3 SDHI */
|
||||
#define CARD_OPT_WIDTH8 BIT(13)
|
||||
#define CARD_OPT_ALWAYS1 BIT(14)
|
||||
#define CARD_OPT_WIDTH BIT(15)
|
||||
|
||||
/* Definitions for values the CTL_SDIO_STATUS register can take */
|
||||
|
|
@ -180,6 +183,7 @@ struct tmio_mmc_host {
|
|||
void (*reset)(struct tmio_mmc_host *host);
|
||||
bool (*check_retune)(struct tmio_mmc_host *host);
|
||||
void (*fixup_request)(struct tmio_mmc_host *host, struct mmc_request *mrq);
|
||||
unsigned int (*get_timeout_cycles)(struct tmio_mmc_host *host);
|
||||
|
||||
void (*prepare_hs400_tuning)(struct tmio_mmc_host *host);
|
||||
void (*hs400_downgrade)(struct tmio_mmc_host *host);
|
||||
|
|
|
|||
|
|
@ -796,8 +796,10 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
|
|||
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
if (mrq->cmd->error || (mrq->data && mrq->data->error))
|
||||
if (mrq->cmd->error || (mrq->data && mrq->data->error)) {
|
||||
tmio_mmc_ack_mmc_irqs(host, TMIO_MASK_IRQ); /* Clear all */
|
||||
tmio_mmc_abort_dma(host);
|
||||
}
|
||||
|
||||
/* Error means retune, but executed command was still successful */
|
||||
if (host->check_retune && host->check_retune(host))
|
||||
|
|
@ -885,6 +887,22 @@ static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
|
|||
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, reg);
|
||||
}
|
||||
|
||||
static unsigned int tmio_mmc_get_timeout_cycles(struct tmio_mmc_host *host)
|
||||
{
|
||||
u16 val = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
|
||||
|
||||
val = (val & CARD_OPT_TOP_MASK) >> CARD_OPT_TOP_SHIFT;
|
||||
return 1 << (13 + val);
|
||||
}
|
||||
|
||||
static void tmio_mmc_max_busy_timeout(struct tmio_mmc_host *host)
|
||||
{
|
||||
unsigned int clk_rate = host->mmc->actual_clock ?: host->mmc->f_max;
|
||||
|
||||
host->mmc->max_busy_timeout = host->get_timeout_cycles(host) /
|
||||
(clk_rate / MSEC_PER_SEC);
|
||||
}
|
||||
|
||||
/* Set MMC clock / power.
|
||||
* Note: This controller uses a simple divider scheme therefore it cannot
|
||||
* run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as
|
||||
|
|
@ -943,6 +961,9 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
break;
|
||||
}
|
||||
|
||||
if (host->pdata->flags & TMIO_MMC_USE_BUSY_TIMEOUT)
|
||||
tmio_mmc_max_busy_timeout(host);
|
||||
|
||||
/* Let things settle. delay taken from winCE driver */
|
||||
usleep_range(140, 200);
|
||||
if (PTR_ERR(host->mrq) == -EINTR)
|
||||
|
|
@ -1099,6 +1120,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
|
|||
if (!(pdata->flags & TMIO_MMC_HAS_IDLE_WAIT))
|
||||
_host->write16_hook = NULL;
|
||||
|
||||
if (pdata->flags & TMIO_MMC_USE_BUSY_TIMEOUT && !_host->get_timeout_cycles)
|
||||
_host->get_timeout_cycles = tmio_mmc_get_timeout_cycles;
|
||||
|
||||
_host->set_pwr = pdata->set_pwr;
|
||||
|
||||
ret = tmio_mmc_init_ocr(_host);
|
||||
|
|
|
|||
|
|
@ -586,6 +586,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
|
|||
|
||||
tmio_data = &priv->tmio_data;
|
||||
tmio_data->flags |= TMIO_MMC_32BIT_DATA_PORT;
|
||||
tmio_data->flags |= TMIO_MMC_USE_BUSY_TIMEOUT;
|
||||
|
||||
host = tmio_mmc_host_alloc(pdev, tmio_data);
|
||||
if (IS_ERR(host))
|
||||
|
|
|
|||
|
|
@ -266,36 +266,63 @@ EXPORT_SYMBOL(geni_se_init);
|
|||
static void geni_se_select_fifo_mode(struct geni_se *se)
|
||||
{
|
||||
u32 proto = geni_se_read_proto(se);
|
||||
u32 val;
|
||||
u32 val, val_old;
|
||||
|
||||
geni_se_irq_clear(se);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
|
||||
/*
|
||||
* The RX path for the UART is asynchronous and so needs more
|
||||
* complex logic for enabling / disabling its interrupts.
|
||||
*
|
||||
* Specific notes:
|
||||
* - The done and TX-related interrupts are managed manually.
|
||||
* - We don't RX from the main sequencer (we use the secondary) so
|
||||
* we don't need the RX-related interrupts enabled in the main
|
||||
* sequencer for UART.
|
||||
*/
|
||||
if (proto != GENI_SE_UART) {
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
|
||||
val |= M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN;
|
||||
val |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
|
||||
}
|
||||
writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
|
||||
if (proto != GENI_SE_UART)
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
|
||||
val |= S_CMD_DONE_EN;
|
||||
writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
|
||||
}
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
|
||||
val &= ~GENI_DMA_MODE_EN;
|
||||
writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
|
||||
}
|
||||
|
||||
static void geni_se_select_dma_mode(struct geni_se *se)
|
||||
{
|
||||
u32 val;
|
||||
u32 proto = geni_se_read_proto(se);
|
||||
u32 val, val_old;
|
||||
|
||||
geni_se_irq_clear(se);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
|
||||
if (proto != GENI_SE_UART) {
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
|
||||
val &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN);
|
||||
val &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
|
||||
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
|
||||
val &= ~S_CMD_DONE_EN;
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
|
||||
}
|
||||
|
||||
val_old = val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
|
||||
val |= GENI_DMA_MODE_EN;
|
||||
writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
|
||||
if (val != val_old)
|
||||
writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -651,7 +678,7 @@ int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
|||
writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_TX_PTR_L);
|
||||
writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_TX_PTR_H);
|
||||
writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR);
|
||||
writel_relaxed(len, se->base + SE_DMA_TX_LEN);
|
||||
writel(len, se->base + SE_DMA_TX_LEN);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_tx_dma_prep);
|
||||
|
|
@ -688,7 +715,7 @@ int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
|||
writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_RX_PTR_H);
|
||||
/* RX does not have EOT buffer type bit. So just reset RX_ATTR */
|
||||
writel_relaxed(0, se->base + SE_DMA_RX_ATTR);
|
||||
writel_relaxed(len, se->base + SE_DMA_RX_LEN);
|
||||
writel(len, se->base + SE_DMA_RX_LEN);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_rx_dma_prep);
|
||||
|
|
|
|||
|
|
@ -55,7 +55,12 @@
|
|||
*/
|
||||
#define TMIO_MMC_HAS_IDLE_WAIT BIT(4)
|
||||
|
||||
/* BIT(5) is unused */
|
||||
/*
|
||||
* Use the busy timeout feature. Probably all TMIO versions support it. Yet,
|
||||
* we don't have documentation for old variants, so we enable only known good
|
||||
* variants with this flag. Can be removed once all variants are known good.
|
||||
*/
|
||||
#define TMIO_MMC_USE_BUSY_TIMEOUT BIT(5)
|
||||
|
||||
/*
|
||||
* Some controllers have CMD12 automatically
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ struct mmc_ios {
|
|||
#define MMC_TIMING_MMC_DDR52 8
|
||||
#define MMC_TIMING_MMC_HS200 9
|
||||
#define MMC_TIMING_MMC_HS400 10
|
||||
#define MMC_TIMING_SD_EXP 11
|
||||
#define MMC_TIMING_SD_EXP_1_2V 12
|
||||
|
||||
unsigned char signal_voltage; /* signalling voltage (1.8V or 3.3V) */
|
||||
|
||||
|
|
@ -173,6 +175,9 @@ struct mmc_host_ops {
|
|||
*/
|
||||
int (*multi_io_quirk)(struct mmc_card *card,
|
||||
unsigned int direction, int blk_size);
|
||||
|
||||
/* Initialize an SD express card, mandatory for MMC_CAP2_SD_EXP. */
|
||||
int (*init_sd_express)(struct mmc_host *host, struct mmc_ios *ios);
|
||||
};
|
||||
|
||||
struct mmc_cqe_ops {
|
||||
|
|
@ -358,6 +363,8 @@ struct mmc_host {
|
|||
#define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */
|
||||
#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \
|
||||
MMC_CAP2_HS200_1_2V_SDR)
|
||||
#define MMC_CAP2_SD_EXP (1 << 7) /* SD express via PCIe */
|
||||
#define MMC_CAP2_SD_EXP_1_2V (1 << 8) /* SD express 1.2V */
|
||||
#define MMC_CAP2_CD_ACTIVE_HIGH (1 << 10) /* Card-detect signal active high */
|
||||
#define MMC_CAP2_RO_ACTIVE_HIGH (1 << 11) /* Write-protect signal active high */
|
||||
#define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@
|
|||
#define MS_OC_INT_EN (1 << 23)
|
||||
#define SD_OC_INT_EN (1 << 22)
|
||||
|
||||
#define RTSX_DUM_REG 0x1C
|
||||
|
||||
/*
|
||||
* macros for easy use
|
||||
|
|
@ -658,6 +659,23 @@
|
|||
#define PM_WAKE_EN 0x01
|
||||
#define PM_CTRL4 0xFF47
|
||||
|
||||
/* FW config info register */
|
||||
#define RTS5261_FW_CFG_INFO0 0xFF50
|
||||
#define RTS5261_FW_EXPRESS_TEST_MASK (0x01 << 0)
|
||||
#define RTS5261_FW_EA_MODE_MASK (0x01 << 5)
|
||||
#define RTS5261_FW_CFG0 0xFF54
|
||||
#define RTS5261_FW_ENTER_EXPRESS (0x01 << 0)
|
||||
|
||||
#define RTS5261_FW_CFG1 0xFF55
|
||||
#define RTS5261_SYS_CLK_SEL_MCU_CLK (0x01 << 7)
|
||||
#define RTS5261_CRC_CLK_SEL_MCU_CLK (0x01 << 6)
|
||||
#define RTS5261_FAKE_MCU_CLOCK_GATING (0x01 << 5)
|
||||
#define RTS5261_MCU_BUS_SEL_MASK (0x01 << 4)
|
||||
#define RTS5261_MCU_CLOCK_SEL_MASK (0x03 << 2)
|
||||
#define RTS5261_MCU_CLOCK_SEL_16M (0x01 << 2)
|
||||
#define RTS5261_MCU_CLOCK_GATING (0x01 << 1)
|
||||
#define RTS5261_DRIVER_ENABLE_FW (0x01 << 0)
|
||||
|
||||
#define REG_CFG_OOBS_OFF_TIMER 0xFEA6
|
||||
#define REG_CFG_OOBS_ON_TIMER 0xFEA7
|
||||
#define REG_CFG_VCM_ON_TIMER 0xFEA8
|
||||
|
|
@ -701,6 +719,13 @@
|
|||
#define RTS5260_DVCC_TUNE_MASK 0x70
|
||||
#define RTS5260_DVCC_33 0x70
|
||||
|
||||
/*RTS5261*/
|
||||
#define RTS5261_LDO1_CFG0 0xFF72
|
||||
#define RTS5261_LDO1_OCP_THD_MASK (0x07 << 5)
|
||||
#define RTS5261_LDO1_OCP_EN (0x01 << 4)
|
||||
#define RTS5261_LDO1_OCP_LMT_THD_MASK (0x03 << 2)
|
||||
#define RTS5261_LDO1_OCP_LMT_EN (0x01 << 1)
|
||||
|
||||
#define LDO_VCC_CFG1 0xFF73
|
||||
#define LDO_VCC_REF_TUNE_MASK 0x30
|
||||
#define LDO_VCC_REF_1V2 0x20
|
||||
|
|
@ -741,6 +766,8 @@
|
|||
|
||||
#define RTS5260_AUTOLOAD_CFG4 0xFF7F
|
||||
#define RTS5260_MIMO_DISABLE 0x8A
|
||||
/*RTS5261*/
|
||||
#define RTS5261_AUX_CLK_16M_EN (1 << 5)
|
||||
|
||||
#define RTS5260_REG_GPIO_CTL0 0xFC1A
|
||||
#define RTS5260_REG_GPIO_MASK 0x01
|
||||
|
|
@ -1193,6 +1220,7 @@ struct rtsx_pcr {
|
|||
#define EXTRA_CAPS_MMC_HS200 (1 << 4)
|
||||
#define EXTRA_CAPS_MMC_8BIT (1 << 5)
|
||||
#define EXTRA_CAPS_NO_MMC (1 << 7)
|
||||
#define EXTRA_CAPS_SD_EXPRESS (1 << 8)
|
||||
u32 extra_caps;
|
||||
|
||||
#define IC_VER_A 0
|
||||
|
|
@ -1247,6 +1275,8 @@ struct rtsx_pcr {
|
|||
#define PCI_PID(pcr) ((pcr)->pci->device)
|
||||
#define is_version(pcr, pid, ver) \
|
||||
(CHK_PCI_PID(pcr, pid) && (pcr)->ic_version == (ver))
|
||||
#define is_version_higher_than(pcr, pid, ver) \
|
||||
(CHK_PCI_PID(pcr, pid) && (pcr)->ic_version > (ver))
|
||||
#define pcr_dbg(pcr, fmt, arg...) \
|
||||
dev_dbg(&(pcr)->pci->dev, fmt, ##arg)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user