mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 14:24:11 +08:00
soc: convert ep93xx to devicetree
This concludes a long journey towards replacing the old board files with devictree description on the Cirrus Logic EP93xx platform. Nikita Shubin has been working on this for a long time, for details see the last post on https://lore.kernel.org/lkml/20240909-ep93xx-v12-0-e86ab2423d4b@maquefel.me/ -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmb1croACgkQYKtH/8kJ UicY0g//XXEXcBgE2CLfKzGimN3gREIElEqFCpd7v32XWGIQNFdS7StiGqNx1MeU UYdILm97ldgpx+NnHd3Cb9HbLQ1CTIIvAZ2ngFLDeeZO+wgzBVxWTrdUUp57ZIBn 5Fq0hNaR1bfqSr+J+ZbgizH5N96EvLr3OPz/eJetY7egVBUID/0OpwssPJxW1Ns0 f+W+yIc7BomVa71xGgI+RkHrG/5DSaoFtrB+ESt7q1nNUIeMn32JqBYqE0U2iCRN ADO8I+WfAjIcO1uN5n3KM3tigZI3GKSrBdllByr8wWNbp9l5rMYfFAPEaI109iyI 7PFrB6qhAlY9LckXMNhwLyjlnWt6qrI0B+tyg+3tW6+4OwFnpPN0cIhszFPOmrhv njsDSvybp0q9V6Mn7f394H6v9sk9RHr68mpu12hO65UBP7Qe7mrdl3snnFcm0FHL jCLnvjdmCSqRlV6YFsKDHuDzZOG88sAwH0mySKd3c/CVvgaNDsaJduelPGpuXlXX P7op6D8kyKFKfmwK0kz3t+3+2ozgYq3nu4amI7rJ72MOvJKBocTwwqpAesIuegde bn3ZN30yZDTbfEFuveOAzx7rqDlZYX/tN0uspL4VBN0rdayxBng5hneV2PypTtW0 wE9ptz5qIz8AssJ7NInwpgRTDjEut4SY3m3CS2/66V08B4EznAA= =Y3Cd -----END PGP SIGNATURE----- Merge tag 'soc-ep93xx-dt-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc Pull SoC update from Arnd Bergmann: "Convert ep93xx to devicetree This concludes a long journey towards replacing the old board files with devictree description on the Cirrus Logic EP93xx platform. Nikita Shubin has been working on this for a long time, for details see the last post on https://lore.kernel.org/lkml/20240909-ep93xx-v12-0-e86ab2423d4b@maquefel.me/" * tag 'soc-ep93xx-dt-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (47 commits) dt-bindings: gpio: ep9301: Add missing "#interrupt-cells" to examples MAINTAINERS: Update EP93XX ARM ARCHITECTURE maintainer soc: ep93xx: drop reference to removed EP93XX_SOC_COMMON config net: cirrus: use u8 for addr to calm down sparse dmaengine: cirrus: use snprintf() to calm down gcc 13.3.0 dmaengine: ep93xx: Fix a NULL vs IS_ERR() check in probe() pinctrl: ep93xx: Fix raster pins typo spi: ep93xx: update kerneldoc comments for ep93xx_spi clk: ep93xx: Fix off by one in ep93xx_div_recalc_rate() clk: ep93xx: add module license dmaengine: cirrus: remove platform code ASoC: cirrus: edb93xx: Delete driver ARM: ep93xx: soc: drop defines ARM: ep93xx: delete all boardfiles ata: pata_ep93xx: remove legacy pinctrl use pwm: ep93xx: drop legacy pinctrl ARM: ep93xx: DT for the Cirrus ep93xx SoC platforms ARM: dts: ep93xx: Add EDB9302 DT ARM: dts: ep93xx: add ts7250 board ARM: dts: add Cirrus EP93XX SoC .dtsi ...
This commit is contained in:
commit
075dbe9f6e
@ -0,0 +1,38 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/arm/cirrus/cirrus,ep9301.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cirrus Logic EP93xx platforms
|
||||
|
||||
description:
|
||||
The EP93xx SoC is a ARMv4T-based with 200 MHz ARM9 CPU.
|
||||
|
||||
maintainers:
|
||||
- Alexander Sverdlin <alexander.sverdlin@gmail.com>
|
||||
- Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
const: '/'
|
||||
compatible:
|
||||
oneOf:
|
||||
- description: The TS-7250 is a compact, full-featured Single Board
|
||||
Computer (SBC) based upon the Cirrus EP9302 ARM9 CPU
|
||||
items:
|
||||
- const: technologic,ts7250
|
||||
- const: cirrus,ep9301
|
||||
|
||||
- description: The Liebherr BK3 is a derivate from ts7250 board
|
||||
items:
|
||||
- const: liebherr,bk3
|
||||
- const: cirrus,ep9301
|
||||
|
||||
- description: EDB302 is an evaluation board by Cirrus Logic,
|
||||
based on a Cirrus Logic EP9302 CPU
|
||||
items:
|
||||
- const: cirrus,edb9302
|
||||
- const: cirrus,ep9301
|
||||
|
||||
additionalProperties: true
|
@ -0,0 +1,42 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/ata/cirrus,ep9312-pata.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cirrus Logic EP9312 PATA controller
|
||||
|
||||
maintainers:
|
||||
- Damien Le Moal <dlemoal@kernel.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: cirrus,ep9312-pata
|
||||
- items:
|
||||
- const: cirrus,ep9315-pata
|
||||
- const: cirrus,ep9312-pata
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
ide@800a0000 {
|
||||
compatible = "cirrus,ep9312-pata";
|
||||
reg = <0x800a0000 0x38>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <8>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&ide_default_pins>;
|
||||
};
|
@ -0,0 +1,84 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/dma/cirrus,ep9301-dma-m2m.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cirrus Logic ep93xx SoC DMA controller
|
||||
|
||||
maintainers:
|
||||
- Alexander Sverdlin <alexander.sverdlin@gmail.com>
|
||||
- Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
|
||||
allOf:
|
||||
- $ref: dma-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: cirrus,ep9301-dma-m2m
|
||||
- items:
|
||||
- enum:
|
||||
- cirrus,ep9302-dma-m2m
|
||||
- cirrus,ep9307-dma-m2m
|
||||
- cirrus,ep9312-dma-m2m
|
||||
- cirrus,ep9315-dma-m2m
|
||||
- const: cirrus,ep9301-dma-m2m
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: m2m0 channel registers
|
||||
- description: m2m1 channel registers
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: m2m0 channel gate clock
|
||||
- description: m2m1 channel gate clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: m2m0
|
||||
- const: m2m1
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: m2m0 channel interrupt
|
||||
- description: m2m1 channel interrupt
|
||||
|
||||
'#dma-cells':
|
||||
const: 2
|
||||
description: |
|
||||
The first cell is the unique device channel number as indicated by this
|
||||
table for ep93xx:
|
||||
|
||||
10: SPI controller
|
||||
11: IDE controller
|
||||
|
||||
The second cell is the DMA direction line number:
|
||||
|
||||
1: Memory to device
|
||||
2: Device to memory
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/cirrus,ep9301-syscon.h>
|
||||
dma-controller@80000100 {
|
||||
compatible = "cirrus,ep9301-dma-m2m";
|
||||
reg = <0x80000100 0x0040>,
|
||||
<0x80000140 0x0040>;
|
||||
clocks = <&syscon EP93XX_CLK_M2M0>,
|
||||
<&syscon EP93XX_CLK_M2M1>;
|
||||
clock-names = "m2m0", "m2m1";
|
||||
interrupt-parent = <&vic0>;
|
||||
interrupts = <17>, <18>;
|
||||
#dma-cells = <2>;
|
||||
};
|
144
Documentation/devicetree/bindings/dma/cirrus,ep9301-dma-m2p.yaml
Normal file
144
Documentation/devicetree/bindings/dma/cirrus,ep9301-dma-m2p.yaml
Normal file
@ -0,0 +1,144 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/dma/cirrus,ep9301-dma-m2p.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cirrus Logic ep93xx SoC M2P DMA controller
|
||||
|
||||
maintainers:
|
||||
- Alexander Sverdlin <alexander.sverdlin@gmail.com>
|
||||
- Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
|
||||
allOf:
|
||||
- $ref: dma-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: cirrus,ep9301-dma-m2p
|
||||
- items:
|
||||
- enum:
|
||||
- cirrus,ep9302-dma-m2p
|
||||
- cirrus,ep9307-dma-m2p
|
||||
- cirrus,ep9312-dma-m2p
|
||||
- cirrus,ep9315-dma-m2p
|
||||
- const: cirrus,ep9301-dma-m2p
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: m2p0 channel registers
|
||||
- description: m2p1 channel registers
|
||||
- description: m2p2 channel registers
|
||||
- description: m2p3 channel registers
|
||||
- description: m2p4 channel registers
|
||||
- description: m2p5 channel registers
|
||||
- description: m2p6 channel registers
|
||||
- description: m2p7 channel registers
|
||||
- description: m2p8 channel registers
|
||||
- description: m2p9 channel registers
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: m2p0 channel gate clock
|
||||
- description: m2p1 channel gate clock
|
||||
- description: m2p2 channel gate clock
|
||||
- description: m2p3 channel gate clock
|
||||
- description: m2p4 channel gate clock
|
||||
- description: m2p5 channel gate clock
|
||||
- description: m2p6 channel gate clock
|
||||
- description: m2p7 channel gate clock
|
||||
- description: m2p8 channel gate clock
|
||||
- description: m2p9 channel gate clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: m2p0
|
||||
- const: m2p1
|
||||
- const: m2p2
|
||||
- const: m2p3
|
||||
- const: m2p4
|
||||
- const: m2p5
|
||||
- const: m2p6
|
||||
- const: m2p7
|
||||
- const: m2p8
|
||||
- const: m2p9
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: m2p0 channel interrupt
|
||||
- description: m2p1 channel interrupt
|
||||
- description: m2p2 channel interrupt
|
||||
- description: m2p3 channel interrupt
|
||||
- description: m2p4 channel interrupt
|
||||
- description: m2p5 channel interrupt
|
||||
- description: m2p6 channel interrupt
|
||||
- description: m2p7 channel interrupt
|
||||
- description: m2p8 channel interrupt
|
||||
- description: m2p9 channel interrupt
|
||||
|
||||
'#dma-cells':
|
||||
const: 2
|
||||
description: |
|
||||
The first cell is the unique device channel number as indicated by this
|
||||
table for ep93xx:
|
||||
|
||||
0: I2S channel 1
|
||||
1: I2S channel 2 (unused)
|
||||
2: AC97 channel 1 (unused)
|
||||
3: AC97 channel 2 (unused)
|
||||
4: AC97 channel 3 (unused)
|
||||
5: I2S channel 3 (unused)
|
||||
6: UART1 (unused)
|
||||
7: UART2 (unused)
|
||||
8: UART3 (unused)
|
||||
9: IRDA (unused)
|
||||
|
||||
The second cell is the DMA direction line number:
|
||||
|
||||
1: Memory to device
|
||||
2: Device to memory
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- interrupts
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/cirrus,ep9301-syscon.h>
|
||||
dma-controller@80000000 {
|
||||
compatible = "cirrus,ep9301-dma-m2p";
|
||||
reg = <0x80000000 0x0040>,
|
||||
<0x80000040 0x0040>,
|
||||
<0x80000080 0x0040>,
|
||||
<0x800000c0 0x0040>,
|
||||
<0x80000240 0x0040>,
|
||||
<0x80000200 0x0040>,
|
||||
<0x800002c0 0x0040>,
|
||||
<0x80000280 0x0040>,
|
||||
<0x80000340 0x0040>,
|
||||
<0x80000300 0x0040>;
|
||||
clocks = <&syscon EP93XX_CLK_M2P0>,
|
||||
<&syscon EP93XX_CLK_M2P1>,
|
||||
<&syscon EP93XX_CLK_M2P2>,
|
||||
<&syscon EP93XX_CLK_M2P3>,
|
||||
<&syscon EP93XX_CLK_M2P4>,
|
||||
<&syscon EP93XX_CLK_M2P5>,
|
||||
<&syscon EP93XX_CLK_M2P6>,
|
||||
<&syscon EP93XX_CLK_M2P7>,
|
||||
<&syscon EP93XX_CLK_M2P8>,
|
||||
<&syscon EP93XX_CLK_M2P9>;
|
||||
clock-names = "m2p0", "m2p1",
|
||||
"m2p2", "m2p3",
|
||||
"m2p4", "m2p5",
|
||||
"m2p6", "m2p7",
|
||||
"m2p8", "m2p9";
|
||||
interrupt-parent = <&vic0>;
|
||||
interrupts = <7>, <8>, <9>, <10>, <11>, <12>, <13>, <14>, <15>, <16>;
|
||||
#dma-cells = <2>;
|
||||
};
|
@ -73,9 +73,10 @@ examples:
|
||||
reg-names = "data", "dir", "intr";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <27>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <27>;
|
||||
};
|
||||
|
||||
gpio@80840004 {
|
||||
@ -87,6 +88,7 @@ examples:
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <27>;
|
||||
};
|
||||
@ -127,6 +129,7 @@ examples:
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts-extended = <&vic0 19>, <&vic0 20>,
|
||||
<&vic0 21>, <&vic0 22>,
|
||||
<&vic1 15>, <&vic1 16>,
|
||||
|
@ -0,0 +1,87 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/cirrus,ep9307-keypad.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cirrus ep93xx keypad
|
||||
|
||||
maintainers:
|
||||
- Alexander Sverdlin <alexander.sverdlin@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: /schemas/input/matrix-keymap.yaml#
|
||||
|
||||
description:
|
||||
The KPP is designed to interface with a keypad matrix with 2-point contact
|
||||
or 3-point contact keys. The KPP is designed to simplify the software task
|
||||
of scanning a keypad matrix. The KPP is capable of detecting, debouncing,
|
||||
and decoding one or multiple keys pressed simultaneously on a keypad.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: cirrus,ep9307-keypad
|
||||
- items:
|
||||
- enum:
|
||||
- cirrus,ep9312-keypad
|
||||
- cirrus,ep9315-keypad
|
||||
- const: cirrus,ep9307-keypad
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
debounce-delay-ms:
|
||||
description: |
|
||||
Time in microseconds that key must be pressed or
|
||||
released for state change interrupt to trigger.
|
||||
|
||||
cirrus,prescale:
|
||||
description: row/column counter pre-scaler load value
|
||||
$ref: /schemas/types.yaml#/definitions/uint16
|
||||
maximum: 1023
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- linux,keymap
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/clock/cirrus,ep9301-syscon.h>
|
||||
keypad@800f0000 {
|
||||
compatible = "cirrus,ep9307-keypad";
|
||||
reg = <0x800f0000 0x0c>;
|
||||
interrupt-parent = <&vic0>;
|
||||
interrupts = <29>;
|
||||
clocks = <&eclk EP93XX_CLK_KEYPAD>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&keypad_default_pins>;
|
||||
linux,keymap = <KEY_UP>,
|
||||
<KEY_DOWN>,
|
||||
<KEY_VOLUMEDOWN>,
|
||||
<KEY_HOME>,
|
||||
<KEY_RIGHT>,
|
||||
<KEY_LEFT>,
|
||||
<KEY_ENTER>,
|
||||
<KEY_VOLUMEUP>,
|
||||
<KEY_F6>,
|
||||
<KEY_F8>,
|
||||
<KEY_F9>,
|
||||
<KEY_F10>,
|
||||
<KEY_F1>,
|
||||
<KEY_F2>,
|
||||
<KEY_F3>,
|
||||
<KEY_POWER>;
|
||||
};
|
45
Documentation/devicetree/bindings/mtd/technologic,nand.yaml
Normal file
45
Documentation/devicetree/bindings/mtd/technologic,nand.yaml
Normal file
@ -0,0 +1,45 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/technologic,nand.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Technologic Systems NAND controller
|
||||
|
||||
maintainers:
|
||||
- Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
|
||||
allOf:
|
||||
- $ref: nand-controller.yaml
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: technologic,ts7200-nand
|
||||
- items:
|
||||
- enum:
|
||||
- technologic,ts7300-nand
|
||||
- technologic,ts7260-nand
|
||||
- technologic,ts7250-nand
|
||||
- const: technologic,ts7200-nand
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
nand-controller@60000000 {
|
||||
compatible = "technologic,ts7200-nand";
|
||||
reg = <0x60000000 0x8000000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
nand@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
59
Documentation/devicetree/bindings/net/cirrus,ep9301-eth.yaml
Normal file
59
Documentation/devicetree/bindings/net/cirrus,ep9301-eth.yaml
Normal file
@ -0,0 +1,59 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/cirrus,ep9301-eth.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: EP93xx SoC Ethernet Controller
|
||||
|
||||
maintainers:
|
||||
- Alexander Sverdlin <alexander.sverdlin@gmail.com>
|
||||
- Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
|
||||
allOf:
|
||||
- $ref: ethernet-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: cirrus,ep9301-eth
|
||||
- items:
|
||||
- enum:
|
||||
- cirrus,ep9302-eth
|
||||
- cirrus,ep9307-eth
|
||||
- cirrus,ep9312-eth
|
||||
- cirrus,ep9315-eth
|
||||
- const: cirrus,ep9301-eth
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: The physical base address and size of IO range
|
||||
|
||||
interrupts:
|
||||
items:
|
||||
- description: Combined signal for various interrupt events
|
||||
|
||||
phy-handle: true
|
||||
|
||||
mdio:
|
||||
$ref: mdio.yaml#
|
||||
unevaluatedProperties: false
|
||||
description: optional node for embedded MDIO controller
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- phy-handle
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
ethernet@80010000 {
|
||||
compatible = "cirrus,ep9301-eth";
|
||||
reg = <0x80010000 0x10000>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <7>;
|
||||
phy-handle = <&phy0>;
|
||||
};
|
53
Documentation/devicetree/bindings/pwm/cirrus,ep9301-pwm.yaml
Normal file
53
Documentation/devicetree/bindings/pwm/cirrus,ep9301-pwm.yaml
Normal file
@ -0,0 +1,53 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/pwm/cirrus,ep9301-pwm.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cirrus Logic ep93xx PWM controller
|
||||
|
||||
maintainers:
|
||||
- Alexander Sverdlin <alexander.sverdlin@gmail.com>
|
||||
- Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
|
||||
allOf:
|
||||
- $ref: pwm.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: cirrus,ep9301-pwm
|
||||
- items:
|
||||
- enum:
|
||||
- cirrus,ep9302-pwm
|
||||
- cirrus,ep9307-pwm
|
||||
- cirrus,ep9312-pwm
|
||||
- cirrus,ep9315-pwm
|
||||
- const: cirrus,ep9301-pwm
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: SoC PWM clock
|
||||
|
||||
"#pwm-cells":
|
||||
const: 3
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/cirrus,ep9301-syscon.h>
|
||||
pwm@80910000 {
|
||||
compatible = "cirrus,ep9301-pwm";
|
||||
reg = <0x80910000 0x10>;
|
||||
clocks = <&syscon EP93XX_CLK_PWM>;
|
||||
#pwm-cells = <3>;
|
||||
};
|
@ -0,0 +1,94 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/soc/cirrus/cirrus,ep9301-syscon.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cirrus Logic EP93xx Platforms System Controller
|
||||
|
||||
maintainers:
|
||||
- Alexander Sverdlin <alexander.sverdlin@gmail.com>
|
||||
- Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
|
||||
description: |
|
||||
Central resources are controlled by a set of software-locked registers,
|
||||
which can be used to prevent accidental accesses. Syscon generates
|
||||
the various bus and peripheral clocks and controls the system startup
|
||||
configuration.
|
||||
|
||||
The System Controller (Syscon) provides:
|
||||
- Clock control
|
||||
- Power management
|
||||
- System configuration management
|
||||
|
||||
Syscon registers are common for all EP93xx SoC's, through some actual peripheral
|
||||
may be missing depending on actual SoC model.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- cirrus,ep9302-syscon
|
||||
- cirrus,ep9307-syscon
|
||||
- cirrus,ep9312-syscon
|
||||
- cirrus,ep9315-syscon
|
||||
- const: cirrus,ep9301-syscon
|
||||
- const: syscon
|
||||
- items:
|
||||
- const: cirrus,ep9301-syscon
|
||||
- const: syscon
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#clock-cells":
|
||||
const: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: reference clock
|
||||
|
||||
patternProperties:
|
||||
'^pins-':
|
||||
type: object
|
||||
description: pin node
|
||||
$ref: /schemas/pinctrl/pinmux-node.yaml
|
||||
|
||||
properties:
|
||||
function:
|
||||
enum: [ spi, ac97, i2s, pwm, keypad, pata, lcd, gpio ]
|
||||
|
||||
groups:
|
||||
enum: [ ssp, ac97, i2s_on_ssp, i2s_on_ac97, pwm1, gpio1agrp,
|
||||
gpio2agrp, gpio3agrp, gpio4agrp, gpio6agrp, gpio7agrp,
|
||||
rasteronsdram0grp, rasteronsdram3grp, keypadgrp, idegrp ]
|
||||
|
||||
required:
|
||||
- function
|
||||
- groups
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#clock-cells"
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
syscon@80930000 {
|
||||
compatible = "cirrus,ep9301-syscon", "syscon";
|
||||
reg = <0x80930000 0x1000>;
|
||||
|
||||
#clock-cells = <1>;
|
||||
clocks = <&xtali>;
|
||||
|
||||
spi_default_pins: pins-spi {
|
||||
function = "spi";
|
||||
groups = "ssp";
|
||||
};
|
||||
};
|
@ -40,6 +40,20 @@ properties:
|
||||
- const: sclk
|
||||
- const: lrclk
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: out DMA channel
|
||||
- description: in DMA channel
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: tx
|
||||
- const: rx
|
||||
|
||||
port:
|
||||
$ref: audio-graph-port.yaml#
|
||||
unevaluatedProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- '#sound-dai-cells'
|
||||
@ -61,6 +75,8 @@ examples:
|
||||
<&syscon 30>,
|
||||
<&syscon 31>;
|
||||
clock-names = "mclk", "sclk", "lrclk";
|
||||
dmas = <&dma0 0 1>, <&dma0 0 2>;
|
||||
dma-names = "tx", "rx";
|
||||
};
|
||||
|
||||
...
|
||||
|
70
Documentation/devicetree/bindings/spi/cirrus,ep9301-spi.yaml
Normal file
70
Documentation/devicetree/bindings/spi/cirrus,ep9301-spi.yaml
Normal file
@ -0,0 +1,70 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/spi/cirrus,ep9301-spi.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: EP93xx SoC SPI controller
|
||||
|
||||
maintainers:
|
||||
- Alexander Sverdlin <alexander.sverdlin@gmail.com>
|
||||
- Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
|
||||
allOf:
|
||||
- $ref: spi-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: cirrus,ep9301-spi
|
||||
- items:
|
||||
- enum:
|
||||
- cirrus,ep9302-spi
|
||||
- cirrus,ep9307-spi
|
||||
- cirrus,ep9312-spi
|
||||
- cirrus,ep9315-spi
|
||||
- const: cirrus,ep9301-spi
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: SPI registers region
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: SPI Controller reference clock source
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: rx DMA channel
|
||||
- description: tx DMA channel
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: rx
|
||||
- const: tx
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/clock/cirrus,ep9301-syscon.h>
|
||||
spi@808a0000 {
|
||||
compatible = "cirrus,ep9301-spi";
|
||||
reg = <0x808a0000 0x18>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <21>;
|
||||
clocks = <&syscon EP93XX_CLK_SPI>;
|
||||
dmas = <&dma1 10 2>, <&dma1 10 1>;
|
||||
dma-names = "rx", "tx";
|
||||
cs-gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>;
|
||||
};
|
@ -2272,6 +2272,7 @@ N: clps711x
|
||||
ARM/CIRRUS LOGIC EP93XX ARM ARCHITECTURE
|
||||
M: Hartley Sweeten <hsweeten@visionengravers.com>
|
||||
M: Alexander Sverdlin <alexander.sverdlin@gmail.com>
|
||||
M: Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/adc/cirrus,ep9301-adc.yaml
|
||||
|
@ -183,7 +183,6 @@ machine-$(CONFIG_ARCH_CLPS711X) += clps711x
|
||||
machine-$(CONFIG_ARCH_DAVINCI) += davinci
|
||||
machine-$(CONFIG_ARCH_DIGICOLOR) += digicolor
|
||||
machine-$(CONFIG_ARCH_DOVE) += dove
|
||||
machine-$(CONFIG_ARCH_EP93XX) += ep93xx
|
||||
machine-$(CONFIG_ARCH_EXYNOS) += exynos
|
||||
machine-$(CONFIG_ARCH_FOOTBRIDGE) += footbridge
|
||||
machine-$(CONFIG_ARCH_GEMINI) += gemini
|
||||
|
@ -3,3 +3,7 @@ dtb-$(CONFIG_ARCH_CLPS711X) += \
|
||||
ep7211-edb7211.dtb
|
||||
dtb-$(CONFIG_ARCH_CLPS711X) += \
|
||||
ep7211-edb7211.dtb
|
||||
dtb-$(CONFIG_ARCH_EP93XX) += \
|
||||
ep93xx-edb9302.dtb \
|
||||
ep93xx-bk3.dtb \
|
||||
ep93xx-ts7250.dtb
|
||||
|
125
arch/arm/boot/dts/cirrus/ep93xx-bk3.dts
Normal file
125
arch/arm/boot/dts/cirrus/ep93xx-bk3.dts
Normal file
@ -0,0 +1,125 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Device Tree file for Liebherr controller BK3.1 based on Cirrus EP9302 SoC
|
||||
*/
|
||||
/dts-v1/;
|
||||
#include "ep93xx.dtsi"
|
||||
|
||||
/ {
|
||||
model = "Liebherr controller BK3.1";
|
||||
compatible = "liebherr,bk3", "cirrus,ep9301";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
chosen {
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
/* should be set from ATAGS */
|
||||
reg = <0x00000000 0x02000000>,
|
||||
<0x000530c0 0x01fdd000>;
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
led-0 {
|
||||
label = "grled";
|
||||
gpios = <&gpio4 0 GPIO_ACTIVE_HIGH>;
|
||||
linux,default-trigger = "heartbeat";
|
||||
function = LED_FUNCTION_HEARTBEAT;
|
||||
};
|
||||
|
||||
led-1 {
|
||||
label = "rdled";
|
||||
gpios = <&gpio4 1 GPIO_ACTIVE_HIGH>;
|
||||
function = LED_FUNCTION_FAULT;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&ebi {
|
||||
nand-controller@60000000 {
|
||||
compatible = "technologic,ts7200-nand";
|
||||
reg = <0x60000000 0x8000000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
nand@0 {
|
||||
reg = <0>;
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "System";
|
||||
reg = <0x00000000 0x01e00000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@1e00000 {
|
||||
label = "Data";
|
||||
reg = <0x01e00000 0x05f20000>;
|
||||
};
|
||||
|
||||
partition@7d20000 {
|
||||
label = "RedBoot";
|
||||
reg = <0x07d20000 0x002e0000>;
|
||||
read-only;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
ð0 {
|
||||
phy-handle = <&phy0>;
|
||||
};
|
||||
|
||||
&i2s {
|
||||
dmas = <&dma0 0 1>, <&dma0 0 2>;
|
||||
dma-names = "tx", "rx";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2s_on_ac97_pins>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio1 {
|
||||
/* PWM */
|
||||
gpio-ranges = <&syscon 6 163 1>;
|
||||
};
|
||||
|
||||
&gpio4 {
|
||||
gpio-ranges = <&syscon 0 97 2>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio6 {
|
||||
gpio-ranges = <&syscon 0 87 2>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio7 {
|
||||
gpio-ranges = <&syscon 2 199 4>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&mdio0 {
|
||||
phy0: ethernet-phy@1 {
|
||||
reg = <1>;
|
||||
device_type = "ethernet-phy";
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&uart1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb0 {
|
||||
status = "okay";
|
||||
};
|
181
arch/arm/boot/dts/cirrus/ep93xx-edb9302.dts
Normal file
181
arch/arm/boot/dts/cirrus/ep93xx-edb9302.dts
Normal file
@ -0,0 +1,181 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
/*
|
||||
* Device Tree file for Cirrus Logic EDB9302 board based on EP9302 SoC
|
||||
*/
|
||||
/dts-v1/;
|
||||
#include "ep93xx.dtsi"
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "cirrus,edb9302", "cirrus,ep9301";
|
||||
model = "cirrus,edb9302";
|
||||
|
||||
chosen {
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
/* should be set from ATAGS */
|
||||
reg = <0x0000000 0x800000>,
|
||||
<0x1000000 0x800000>,
|
||||
<0x4000000 0x800000>,
|
||||
<0x5000000 0x800000>;
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "audio-graph-card2";
|
||||
label = "EDB93XX";
|
||||
links = <&i2s_port>;
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
led-0 {
|
||||
label = "grled";
|
||||
gpios = <&gpio4 0 GPIO_ACTIVE_HIGH>;
|
||||
linux,default-trigger = "heartbeat";
|
||||
function = LED_FUNCTION_HEARTBEAT;
|
||||
};
|
||||
|
||||
led-1 {
|
||||
label = "rdled";
|
||||
gpios = <&gpio4 1 GPIO_ACTIVE_HIGH>;
|
||||
function = LED_FUNCTION_FAULT;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&adc {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&ebi {
|
||||
flash@60000000 {
|
||||
compatible = "cfi-flash";
|
||||
reg = <0x60000000 0x1000000>;
|
||||
bank-width = <2>;
|
||||
};
|
||||
};
|
||||
|
||||
ð0 {
|
||||
phy-handle = <&phy0>;
|
||||
};
|
||||
|
||||
&gpio0 {
|
||||
gpio-ranges = <&syscon 0 153 1>,
|
||||
<&syscon 1 152 1>,
|
||||
<&syscon 2 151 1>,
|
||||
<&syscon 3 148 1>,
|
||||
<&syscon 4 147 1>,
|
||||
<&syscon 5 146 1>,
|
||||
<&syscon 6 145 1>,
|
||||
<&syscon 7 144 1>;
|
||||
};
|
||||
|
||||
&gpio1 {
|
||||
gpio-ranges = <&syscon 0 143 1>,
|
||||
<&syscon 1 142 1>,
|
||||
<&syscon 2 141 1>,
|
||||
<&syscon 3 140 1>,
|
||||
<&syscon 4 165 1>,
|
||||
<&syscon 5 164 1>,
|
||||
<&syscon 6 163 1>,
|
||||
<&syscon 7 160 1>;
|
||||
};
|
||||
|
||||
&gpio2 {
|
||||
gpio-ranges = <&syscon 0 115 1>;
|
||||
};
|
||||
|
||||
/* edb9302 doesn't have GPIO Port D present */
|
||||
&gpio3 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&gpio4 {
|
||||
gpio-ranges = <&syscon 0 97 2>;
|
||||
};
|
||||
|
||||
&gpio5 {
|
||||
gpio-ranges = <&syscon 1 170 1>,
|
||||
<&syscon 2 169 1>,
|
||||
<&syscon 3 168 1>;
|
||||
};
|
||||
|
||||
&gpio6 {
|
||||
gpio-ranges = <&syscon 0 87 2>;
|
||||
};
|
||||
|
||||
&gpio7 {
|
||||
gpio-ranges = <&syscon 2 199 4>;
|
||||
};
|
||||
|
||||
&i2s {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2s_on_ac97_pins>;
|
||||
status = "okay";
|
||||
i2s_port: port {
|
||||
i2s_ep: endpoint {
|
||||
system-clock-direction-out;
|
||||
frame-master;
|
||||
bitclock-master;
|
||||
mclk-fs = <256>;
|
||||
dai-format = "i2s";
|
||||
convert-channels = <2>;
|
||||
convert-sample-format = "s32_le";
|
||||
remote-endpoint = <&codec_ep>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&mdio0 {
|
||||
phy0: ethernet-phy@1 {
|
||||
reg = <1>;
|
||||
device_type = "ethernet-phy";
|
||||
};
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
cs-gpios = <&gpio0 6 GPIO_ACTIVE_LOW
|
||||
&gpio0 7 GPIO_ACTIVE_LOW>;
|
||||
dmas = <&dma1 10 2>, <&dma1 10 1>;
|
||||
dma-names = "rx", "tx";
|
||||
status = "okay";
|
||||
|
||||
cs4271: codec@0 {
|
||||
compatible = "cirrus,cs4271";
|
||||
reg = <0>;
|
||||
#sound-dai-cells = <0>;
|
||||
spi-max-frequency = <6000000>;
|
||||
spi-cpol;
|
||||
spi-cpha;
|
||||
reset-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
|
||||
port {
|
||||
codec_ep: endpoint {
|
||||
remote-endpoint = <&i2s_ep>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
at25f1024: eeprom@1 {
|
||||
compatible = "atmel,at25";
|
||||
reg = <1>;
|
||||
address-width = <8>;
|
||||
size = <0x20000>;
|
||||
pagesize = <256>;
|
||||
spi-max-frequency = <20000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&uart1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb0 {
|
||||
status = "okay";
|
||||
};
|
145
arch/arm/boot/dts/cirrus/ep93xx-ts7250.dts
Normal file
145
arch/arm/boot/dts/cirrus/ep93xx-ts7250.dts
Normal file
@ -0,0 +1,145 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Device Tree file for Technologic Systems ts7250 board based on Cirrus EP9302 SoC
|
||||
*/
|
||||
/dts-v1/;
|
||||
#include "ep93xx.dtsi"
|
||||
|
||||
/ {
|
||||
compatible = "technologic,ts7250", "cirrus,ep9301";
|
||||
model = "TS-7250 SBC";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
chosen {
|
||||
};
|
||||
|
||||
memory@0 {
|
||||
device_type = "memory";
|
||||
/* should be set from ATAGS */
|
||||
reg = <0x00000000 0x02000000>,
|
||||
<0x000530c0 0x01fdd000>;
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
led-0 {
|
||||
label = "grled";
|
||||
gpios = <&gpio4 0 GPIO_ACTIVE_HIGH>;
|
||||
linux,default-trigger = "heartbeat";
|
||||
function = LED_FUNCTION_HEARTBEAT;
|
||||
};
|
||||
|
||||
led-1 {
|
||||
label = "rdled";
|
||||
gpios = <&gpio4 1 GPIO_ACTIVE_HIGH>;
|
||||
function = LED_FUNCTION_FAULT;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&ebi {
|
||||
nand-controller@60000000 {
|
||||
compatible = "technologic,ts7200-nand";
|
||||
reg = <0x60000000 0x8000000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
nand@0 {
|
||||
reg = <0>;
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
label = "TS-BOOTROM";
|
||||
reg = <0x00000000 0x00020000>;
|
||||
read-only;
|
||||
};
|
||||
|
||||
partition@20000 {
|
||||
label = "Linux";
|
||||
reg = <0x00020000 0x07d00000>;
|
||||
};
|
||||
|
||||
partition@7d20000 {
|
||||
label = "RedBoot";
|
||||
reg = <0x07d20000 0x002e0000>;
|
||||
read-only;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
rtc@10800000 {
|
||||
compatible = "st,m48t86";
|
||||
reg = <0x10800000 0x1>,
|
||||
<0x11700000 0x1>;
|
||||
};
|
||||
|
||||
watchdog@23800000 {
|
||||
compatible = "technologic,ts7200-wdt";
|
||||
reg = <0x23800000 0x01>,
|
||||
<0x23c00000 0x01>;
|
||||
timeout-sec = <30>;
|
||||
};
|
||||
};
|
||||
|
||||
ð0 {
|
||||
phy-handle = <&phy0>;
|
||||
};
|
||||
|
||||
&gpio1 {
|
||||
/* PWM */
|
||||
gpio-ranges = <&syscon 6 163 1>;
|
||||
};
|
||||
|
||||
/* ts7250 doesn't have GPIO Port D present */
|
||||
&gpio3 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&gpio4 {
|
||||
gpio-ranges = <&syscon 0 97 2>;
|
||||
};
|
||||
|
||||
&gpio6 {
|
||||
gpio-ranges = <&syscon 0 87 2>;
|
||||
};
|
||||
|
||||
&gpio7 {
|
||||
gpio-ranges = <&syscon 2 199 4>;
|
||||
};
|
||||
|
||||
&spi0 {
|
||||
cs-gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>;
|
||||
dmas = <&dma1 10 2>, <&dma1 10 1>;
|
||||
dma-names = "rx", "tx";
|
||||
status = "okay";
|
||||
|
||||
tmp122: temperature-sensor@0 {
|
||||
compatible = "ti,tmp122";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <2000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&mdio0 {
|
||||
phy0: ethernet-phy@1 {
|
||||
reg = <1>;
|
||||
device_type = "ethernet-phy";
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&uart1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb0 {
|
||||
status = "okay";
|
||||
};
|
444
arch/arm/boot/dts/cirrus/ep93xx.dtsi
Normal file
444
arch/arm/boot/dts/cirrus/ep93xx.dtsi
Normal file
@ -0,0 +1,444 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Device Tree file for Cirrus Logic systems EP93XX SoC
|
||||
*/
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/leds/common.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/clock/cirrus,ep9301-syscon.h>
|
||||
/ {
|
||||
soc: soc {
|
||||
compatible = "simple-bus";
|
||||
ranges;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
syscon: syscon@80930000 {
|
||||
compatible = "cirrus,ep9301-syscon", "syscon";
|
||||
reg = <0x80930000 0x1000>;
|
||||
|
||||
#clock-cells = <1>;
|
||||
clocks = <&xtali>;
|
||||
|
||||
spi_default_pins: pins-spi {
|
||||
function = "spi";
|
||||
groups = "ssp";
|
||||
};
|
||||
|
||||
ac97_default_pins: pins-ac97 {
|
||||
function = "ac97";
|
||||
groups = "ac97";
|
||||
};
|
||||
|
||||
i2s_on_ssp_pins: pins-i2sonssp {
|
||||
function = "i2s";
|
||||
groups = "i2s_on_ssp";
|
||||
};
|
||||
|
||||
i2s_on_ac97_pins: pins-i2sonac97 {
|
||||
function = "i2s";
|
||||
groups = "i2s_on_ac97";
|
||||
};
|
||||
|
||||
gpio1_default_pins: pins-gpio1 {
|
||||
function = "gpio";
|
||||
groups = "gpio1agrp";
|
||||
};
|
||||
|
||||
pwm1_default_pins: pins-pwm1 {
|
||||
function = "pwm";
|
||||
groups = "pwm1";
|
||||
};
|
||||
|
||||
gpio2_default_pins: pins-gpio2 {
|
||||
function = "gpio";
|
||||
groups = "gpio2agrp";
|
||||
};
|
||||
|
||||
gpio3_default_pins: pins-gpio3 {
|
||||
function = "gpio";
|
||||
groups = "gpio3agrp";
|
||||
};
|
||||
|
||||
keypad_default_pins: pins-keypad {
|
||||
function = "keypad";
|
||||
groups = "keypadgrp";
|
||||
};
|
||||
|
||||
gpio4_default_pins: pins-gpio4 {
|
||||
function = "gpio";
|
||||
groups = "gpio4agrp";
|
||||
};
|
||||
|
||||
gpio6_default_pins: pins-gpio6 {
|
||||
function = "gpio";
|
||||
groups = "gpio6agrp";
|
||||
};
|
||||
|
||||
gpio7_default_pins: pins-gpio7 {
|
||||
function = "gpio";
|
||||
groups = "gpio7agrp";
|
||||
};
|
||||
|
||||
ide_default_pins: pins-ide {
|
||||
function = "pata";
|
||||
groups = "idegrp";
|
||||
};
|
||||
|
||||
lcd_on_dram0_pins: pins-rasteronsdram0 {
|
||||
function = "lcd";
|
||||
groups = "rasteronsdram0grp";
|
||||
};
|
||||
|
||||
lcd_on_dram3_pins: pins-rasteronsdram3 {
|
||||
function = "lcd";
|
||||
groups = "rasteronsdram3grp";
|
||||
};
|
||||
};
|
||||
|
||||
adc: adc@80900000 {
|
||||
compatible = "cirrus,ep9301-adc";
|
||||
reg = <0x80900000 0x28>;
|
||||
clocks = <&syscon EP93XX_CLK_ADC>;
|
||||
interrupt-parent = <&vic0>;
|
||||
interrupts = <30>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
/*
|
||||
* The EP93XX expansion bus is a set of up to 7 each up to 16MB
|
||||
* windows in the 256MB space from 0x50000000 to 0x5fffffff.
|
||||
* But since we don't require to setup it in any way, we can
|
||||
* represent it as a simple-bus.
|
||||
*/
|
||||
ebi: bus@80080000 {
|
||||
compatible = "simple-bus";
|
||||
reg = <0x80080000 0x20>;
|
||||
native-endian;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
};
|
||||
|
||||
dma0: dma-controller@80000000 {
|
||||
compatible = "cirrus,ep9301-dma-m2p";
|
||||
reg = <0x80000000 0x0040>,
|
||||
<0x80000040 0x0040>,
|
||||
<0x80000080 0x0040>,
|
||||
<0x800000c0 0x0040>,
|
||||
<0x80000240 0x0040>,
|
||||
<0x80000200 0x0040>,
|
||||
<0x800002c0 0x0040>,
|
||||
<0x80000280 0x0040>,
|
||||
<0x80000340 0x0040>,
|
||||
<0x80000300 0x0040>;
|
||||
clocks = <&syscon EP93XX_CLK_M2P0>,
|
||||
<&syscon EP93XX_CLK_M2P1>,
|
||||
<&syscon EP93XX_CLK_M2P2>,
|
||||
<&syscon EP93XX_CLK_M2P3>,
|
||||
<&syscon EP93XX_CLK_M2P4>,
|
||||
<&syscon EP93XX_CLK_M2P5>,
|
||||
<&syscon EP93XX_CLK_M2P6>,
|
||||
<&syscon EP93XX_CLK_M2P7>,
|
||||
<&syscon EP93XX_CLK_M2P8>,
|
||||
<&syscon EP93XX_CLK_M2P9>;
|
||||
clock-names = "m2p0", "m2p1",
|
||||
"m2p2", "m2p3",
|
||||
"m2p4", "m2p5",
|
||||
"m2p6", "m2p7",
|
||||
"m2p8", "m2p9";
|
||||
interrupt-parent = <&vic0>;
|
||||
interrupts = <7>, <8>, <9>, <10>, <11>,
|
||||
<12>, <13>, <14>, <15>, <16>;
|
||||
#dma-cells = <2>;
|
||||
};
|
||||
|
||||
dma1: dma-controller@80000100 {
|
||||
compatible = "cirrus,ep9301-dma-m2m";
|
||||
reg = <0x80000100 0x0040>,
|
||||
<0x80000140 0x0040>;
|
||||
clocks = <&syscon EP93XX_CLK_M2M0>,
|
||||
<&syscon EP93XX_CLK_M2M1>;
|
||||
clock-names = "m2m0", "m2m1";
|
||||
interrupt-parent = <&vic0>;
|
||||
interrupts = <17>, <18>;
|
||||
#dma-cells = <2>;
|
||||
};
|
||||
|
||||
eth0: ethernet@80010000 {
|
||||
compatible = "cirrus,ep9301-eth";
|
||||
reg = <0x80010000 0x10000>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <7>;
|
||||
mdio0: mdio {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
gpio0: gpio@80840000 {
|
||||
compatible = "cirrus,ep9301-gpio";
|
||||
reg = <0x80840000 0x04>,
|
||||
<0x80840010 0x04>,
|
||||
<0x80840090 0x1c>;
|
||||
reg-names = "data", "dir", "intr";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <27>;
|
||||
};
|
||||
|
||||
gpio1: gpio@80840004 {
|
||||
compatible = "cirrus,ep9301-gpio";
|
||||
reg = <0x80840004 0x04>,
|
||||
<0x80840014 0x04>,
|
||||
<0x808400ac 0x1c>;
|
||||
reg-names = "data", "dir", "intr";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <27>;
|
||||
};
|
||||
|
||||
gpio2: gpio@80840008 {
|
||||
compatible = "cirrus,ep9301-gpio";
|
||||
reg = <0x80840008 0x04>,
|
||||
<0x80840018 0x04>;
|
||||
reg-names = "data", "dir";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&gpio2_default_pins>;
|
||||
};
|
||||
|
||||
gpio3: gpio@8084000c {
|
||||
compatible = "cirrus,ep9301-gpio";
|
||||
reg = <0x8084000c 0x04>,
|
||||
<0x8084001c 0x04>;
|
||||
reg-names = "data", "dir";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&gpio3_default_pins>;
|
||||
};
|
||||
|
||||
gpio4: gpio@80840020 {
|
||||
compatible = "cirrus,ep9301-gpio";
|
||||
reg = <0x80840020 0x04>,
|
||||
<0x80840024 0x04>;
|
||||
reg-names = "data", "dir";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&gpio4_default_pins>;
|
||||
};
|
||||
|
||||
gpio5: gpio@80840030 {
|
||||
compatible = "cirrus,ep9301-gpio";
|
||||
reg = <0x80840030 0x04>,
|
||||
<0x80840034 0x04>,
|
||||
<0x8084004c 0x1c>;
|
||||
reg-names = "data", "dir", "intr";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts-extended = <&vic0 19>, <&vic0 20>,
|
||||
<&vic0 21>, <&vic0 22>,
|
||||
<&vic1 15>, <&vic1 16>,
|
||||
<&vic1 17>, <&vic1 18>;
|
||||
};
|
||||
|
||||
gpio6: gpio@80840038 {
|
||||
compatible = "cirrus,ep9301-gpio";
|
||||
reg = <0x80840038 0x04>,
|
||||
<0x8084003c 0x04>;
|
||||
reg-names = "data", "dir";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&gpio6_default_pins>;
|
||||
};
|
||||
|
||||
gpio7: gpio@80840040 {
|
||||
compatible = "cirrus,ep9301-gpio";
|
||||
reg = <0x80840040 0x04>,
|
||||
<0x80840044 0x04>;
|
||||
reg-names = "data", "dir";
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&gpio7_default_pins>;
|
||||
};
|
||||
|
||||
i2s: i2s@80820000 {
|
||||
compatible = "cirrus,ep9301-i2s";
|
||||
reg = <0x80820000 0x100>;
|
||||
#sound-dai-cells = <0>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <28>;
|
||||
clocks = <&syscon EP93XX_CLK_I2S_MCLK>,
|
||||
<&syscon EP93XX_CLK_I2S_SCLK>,
|
||||
<&syscon EP93XX_CLK_I2S_LRCLK>;
|
||||
clock-names = "mclk", "sclk", "lrclk";
|
||||
dmas = <&dma0 0 1>, <&dma0 0 2>;
|
||||
dma-names = "tx", "rx";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
ide: ide@800a0000 {
|
||||
compatible = "cirrus,ep9312-pata";
|
||||
reg = <0x800a0000 0x38>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <8>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&ide_default_pins>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
vic0: interrupt-controller@800b0000 {
|
||||
compatible = "arm,pl192-vic";
|
||||
reg = <0x800b0000 0x1000>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
valid-mask = <0x7ffffffc>;
|
||||
valid-wakeup-mask = <0x0>;
|
||||
};
|
||||
|
||||
vic1: interrupt-controller@800c0000 {
|
||||
compatible = "arm,pl192-vic";
|
||||
reg = <0x800c0000 0x1000>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <1>;
|
||||
valid-mask = <0x1fffffff>;
|
||||
valid-wakeup-mask = <0x0>;
|
||||
};
|
||||
|
||||
keypad: keypad@800f0000 {
|
||||
compatible = "cirrus,ep9307-keypad";
|
||||
reg = <0x800f0000 0x0c>;
|
||||
interrupt-parent = <&vic0>;
|
||||
interrupts = <29>;
|
||||
clocks = <&syscon EP93XX_CLK_KEYPAD>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&keypad_default_pins>;
|
||||
linux,keymap = <KEY_UP>,
|
||||
<KEY_DOWN>,
|
||||
<KEY_VOLUMEDOWN>,
|
||||
<KEY_HOME>,
|
||||
<KEY_RIGHT>,
|
||||
<KEY_LEFT>,
|
||||
<KEY_ENTER>,
|
||||
<KEY_VOLUMEUP>,
|
||||
<KEY_F6>,
|
||||
<KEY_F8>,
|
||||
<KEY_F9>,
|
||||
<KEY_F10>,
|
||||
<KEY_F1>,
|
||||
<KEY_F2>,
|
||||
<KEY_F3>,
|
||||
<KEY_POWER>;
|
||||
};
|
||||
|
||||
pwm0: pwm@80910000 {
|
||||
compatible = "cirrus,ep9301-pwm";
|
||||
reg = <0x80910000 0x10>;
|
||||
clocks = <&syscon EP93XX_CLK_PWM>;
|
||||
#pwm-cells = <3>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pwm1: pwm@80910020 {
|
||||
compatible = "cirrus,ep9301-pwm";
|
||||
reg = <0x80910020 0x10>;
|
||||
clocks = <&syscon EP93XX_CLK_PWM>;
|
||||
#pwm-cells = <3>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pwm1_default_pins>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
rtc0: rtc@80920000 {
|
||||
compatible = "cirrus,ep9301-rtc";
|
||||
reg = <0x80920000 0x100>;
|
||||
};
|
||||
|
||||
spi0: spi@808a0000 {
|
||||
compatible = "cirrus,ep9301-spi";
|
||||
reg = <0x808a0000 0x18>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <21>;
|
||||
clocks = <&syscon EP93XX_CLK_SPI>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spi_default_pins>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
timer: timer@80810000 {
|
||||
compatible = "cirrus,ep9301-timer";
|
||||
reg = <0x80810000 0x100>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <19>;
|
||||
};
|
||||
|
||||
uart0: serial@808c0000 {
|
||||
compatible = "arm,pl011", "arm,primecell";
|
||||
reg = <0x808c0000 0x1000>;
|
||||
arm,primecell-periphid = <0x00041010>;
|
||||
clocks = <&syscon EP93XX_CLK_UART1>, <&syscon EP93XX_CLK_UART>;
|
||||
clock-names = "uartclk", "apb_pclk";
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <20>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
uart1: uart@808d0000 {
|
||||
compatible = "arm,primecell";
|
||||
reg = <0x808d0000 0x1000>;
|
||||
arm,primecell-periphid = <0x00041010>;
|
||||
clocks = <&syscon EP93XX_CLK_UART2>, <&syscon EP93XX_CLK_UART>;
|
||||
clock-names = "apb:uart2", "apb_pclk";
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <22>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
uart2: uart@808b0000 {
|
||||
compatible = "arm,primecell";
|
||||
reg = <0x808b0000 0x1000>;
|
||||
arm,primecell-periphid = <0x00041010>;
|
||||
clocks = <&syscon EP93XX_CLK_UART3>, <&syscon EP93XX_CLK_UART>;
|
||||
clock-names = "apb:uart3", "apb_pclk";
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <23>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
usb0: usb@80020000 {
|
||||
compatible = "generic-ohci";
|
||||
reg = <0x80020000 0x10000>;
|
||||
interrupt-parent = <&vic1>;
|
||||
interrupts = <24>;
|
||||
clocks = <&syscon EP93XX_CLK_USB>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
watchdog0: watchdog@80940000 {
|
||||
compatible = "cirrus,ep9301-wdt";
|
||||
reg = <0x80940000 0x08>;
|
||||
};
|
||||
};
|
||||
|
||||
xtali: oscillator {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <14745600>;
|
||||
clock-output-names = "xtali";
|
||||
};
|
||||
};
|
@ -3,27 +3,27 @@ menuconfig ARCH_EP93XX
|
||||
bool "EP93xx-based"
|
||||
depends on ATAGS
|
||||
depends on ARCH_MULTI_V4T
|
||||
# CONFIG_ARCH_MULTI_V7 is not set
|
||||
depends on CPU_LITTLE_ENDIAN
|
||||
select ARCH_HAS_RESET_CONTROLLER
|
||||
select ARCH_SPARSEMEM_ENABLE
|
||||
select ARM_AMBA
|
||||
select ARM_VIC
|
||||
select ARM_APPENDED_DTB # Old Redboot bootloaders deployed
|
||||
select ARM_ATAG_DTB_COMPAT # we need this to update dt memory node
|
||||
select COMMON_CLK_EP93XX
|
||||
select EP93XX_TIMER
|
||||
select CLKSRC_MMIO
|
||||
select CPU_ARM920T
|
||||
select GPIOLIB
|
||||
select PINCTRL
|
||||
select PINCTRL_EP93XX
|
||||
help
|
||||
This enables support for the Cirrus EP93xx series of CPUs.
|
||||
|
||||
if ARCH_EP93XX
|
||||
|
||||
menu "Cirrus EP93xx Implementation Options"
|
||||
|
||||
config EP93XX_SOC_COMMON
|
||||
bool
|
||||
default y
|
||||
select SOC_BUS
|
||||
select LEDS_GPIO_REGISTER
|
||||
|
||||
comment "EP93xx Platforms"
|
||||
# menu "EP93xx Platforms"
|
||||
|
||||
config MACH_BK3
|
||||
bool "Support Liebherr BK3.1"
|
||||
@ -103,6 +103,6 @@ config MACH_VISION_EP9307
|
||||
Say 'Y' here if you want your kernel to support the
|
||||
Vision Engraving Systems EP9307 SoM.
|
||||
|
||||
endmenu
|
||||
# endmenu
|
||||
|
||||
endif
|
||||
|
@ -1,11 +0,0 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for the linux kernel.
|
||||
#
|
||||
obj-y := core.o clock.o timer-ep93xx.o
|
||||
|
||||
obj-$(CONFIG_EP93XX_DMA) += dma.o
|
||||
|
||||
obj-$(CONFIG_MACH_EDB93XX) += edb93xx.o
|
||||
obj-$(CONFIG_MACH_TS72XX) += ts72xx.o
|
||||
obj-$(CONFIG_MACH_VISION_EP9307)+= vision_ep9307.o
|
@ -1,733 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* arch/arm/mach-ep93xx/clock.c
|
||||
* Clock control for Cirrus EP93xx chips.
|
||||
*
|
||||
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/clkdev.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/soc/cirrus/ep93xx.h>
|
||||
|
||||
#include "hardware.h"
|
||||
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "soc.h"
|
||||
|
||||
static DEFINE_SPINLOCK(clk_lock);
|
||||
|
||||
static char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
|
||||
static char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
|
||||
static char pclk_divisors[] = { 1, 2, 4, 8 };
|
||||
|
||||
static char adc_divisors[] = { 16, 4 };
|
||||
static char sclk_divisors[] = { 2, 4 };
|
||||
static char lrclk_divisors[] = { 32, 64, 128 };
|
||||
|
||||
static const char * const mux_parents[] = {
|
||||
"xtali",
|
||||
"pll1",
|
||||
"pll2"
|
||||
};
|
||||
|
||||
/*
|
||||
* PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS
|
||||
*/
|
||||
static unsigned long calc_pll_rate(unsigned long long rate, u32 config_word)
|
||||
{
|
||||
int i;
|
||||
|
||||
rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */
|
||||
rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */
|
||||
do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */
|
||||
for (i = 0; i < ((config_word >> 16) & 3); i++) /* PS */
|
||||
rate >>= 1;
|
||||
|
||||
return (unsigned long)rate;
|
||||
}
|
||||
|
||||
struct clk_psc {
|
||||
struct clk_hw hw;
|
||||
void __iomem *reg;
|
||||
u8 bit_idx;
|
||||
u32 mask;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
char *div;
|
||||
u8 num_div;
|
||||
spinlock_t *lock;
|
||||
};
|
||||
|
||||
#define to_clk_psc(_hw) container_of(_hw, struct clk_psc, hw)
|
||||
|
||||
static int ep93xx_clk_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_psc *psc = to_clk_psc(hw);
|
||||
u32 val = readl(psc->reg);
|
||||
|
||||
return (val & BIT(psc->bit_idx)) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int ep93xx_clk_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_psc *psc = to_clk_psc(hw);
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
if (psc->lock)
|
||||
spin_lock_irqsave(psc->lock, flags);
|
||||
|
||||
val = __raw_readl(psc->reg);
|
||||
val |= BIT(psc->bit_idx);
|
||||
|
||||
ep93xx_syscon_swlocked_write(val, psc->reg);
|
||||
|
||||
if (psc->lock)
|
||||
spin_unlock_irqrestore(psc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ep93xx_clk_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_psc *psc = to_clk_psc(hw);
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
if (psc->lock)
|
||||
spin_lock_irqsave(psc->lock, flags);
|
||||
|
||||
val = __raw_readl(psc->reg);
|
||||
val &= ~BIT(psc->bit_idx);
|
||||
|
||||
ep93xx_syscon_swlocked_write(val, psc->reg);
|
||||
|
||||
if (psc->lock)
|
||||
spin_unlock_irqrestore(psc->lock, flags);
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_ep93xx_gate_ops = {
|
||||
.enable = ep93xx_clk_enable,
|
||||
.disable = ep93xx_clk_disable,
|
||||
.is_enabled = ep93xx_clk_is_enabled,
|
||||
};
|
||||
|
||||
static struct clk_hw *ep93xx_clk_register_gate(const char *name,
|
||||
const char *parent_name,
|
||||
void __iomem *reg,
|
||||
u8 bit_idx)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
struct clk_psc *psc;
|
||||
struct clk *clk;
|
||||
|
||||
psc = kzalloc(sizeof(*psc), GFP_KERNEL);
|
||||
if (!psc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_ep93xx_gate_ops;
|
||||
init.flags = CLK_SET_RATE_PARENT;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = (parent_name ? 1 : 0);
|
||||
|
||||
psc->reg = reg;
|
||||
psc->bit_idx = bit_idx;
|
||||
psc->hw.init = &init;
|
||||
psc->lock = &clk_lock;
|
||||
|
||||
clk = clk_register(NULL, &psc->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
kfree(psc);
|
||||
return ERR_CAST(clk);
|
||||
}
|
||||
|
||||
return &psc->hw;
|
||||
}
|
||||
|
||||
static u8 ep93xx_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_psc *psc = to_clk_psc(hw);
|
||||
u32 val = __raw_readl(psc->reg);
|
||||
|
||||
if (!(val & EP93XX_SYSCON_CLKDIV_ESEL))
|
||||
return 0;
|
||||
|
||||
if (!(val & EP93XX_SYSCON_CLKDIV_PSEL))
|
||||
return 1;
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int ep93xx_mux_set_parent_lock(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_psc *psc = to_clk_psc(hw);
|
||||
unsigned long flags = 0;
|
||||
u32 val;
|
||||
|
||||
if (index >= ARRAY_SIZE(mux_parents))
|
||||
return -EINVAL;
|
||||
|
||||
if (psc->lock)
|
||||
spin_lock_irqsave(psc->lock, flags);
|
||||
|
||||
val = __raw_readl(psc->reg);
|
||||
val &= ~(EP93XX_SYSCON_CLKDIV_ESEL | EP93XX_SYSCON_CLKDIV_PSEL);
|
||||
|
||||
|
||||
if (index != 0) {
|
||||
val |= EP93XX_SYSCON_CLKDIV_ESEL;
|
||||
val |= (index - 1) ? EP93XX_SYSCON_CLKDIV_PSEL : 0;
|
||||
}
|
||||
|
||||
ep93xx_syscon_swlocked_write(val, psc->reg);
|
||||
|
||||
if (psc->lock)
|
||||
spin_unlock_irqrestore(psc->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_best(unsigned long rate, unsigned long now,
|
||||
unsigned long best)
|
||||
{
|
||||
return abs(rate - now) < abs(rate - best);
|
||||
}
|
||||
|
||||
static int ep93xx_mux_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long rate = req->rate;
|
||||
struct clk *best_parent = NULL;
|
||||
unsigned long __parent_rate;
|
||||
unsigned long best_rate = 0, actual_rate, mclk_rate;
|
||||
unsigned long best_parent_rate;
|
||||
int __div = 0, __pdiv = 0;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Try the two pll's and the external clock
|
||||
* Because the valid predividers are 2, 2.5 and 3, we multiply
|
||||
* all the clocks by 2 to avoid floating point math.
|
||||
*
|
||||
* This is based on the algorithm in the ep93xx raster guide:
|
||||
* http://be-a-maverick.com/en/pubs/appNote/AN269REV1.pdf
|
||||
*
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(mux_parents); i++) {
|
||||
struct clk *parent = clk_get_sys(mux_parents[i], NULL);
|
||||
|
||||
__parent_rate = clk_get_rate(parent);
|
||||
mclk_rate = __parent_rate * 2;
|
||||
|
||||
/* Try each predivider value */
|
||||
for (__pdiv = 4; __pdiv <= 6; __pdiv++) {
|
||||
__div = mclk_rate / (rate * __pdiv);
|
||||
if (__div < 2 || __div > 127)
|
||||
continue;
|
||||
|
||||
actual_rate = mclk_rate / (__pdiv * __div);
|
||||
if (is_best(rate, actual_rate, best_rate)) {
|
||||
best_rate = actual_rate;
|
||||
best_parent_rate = __parent_rate;
|
||||
best_parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!best_parent)
|
||||
return -EINVAL;
|
||||
|
||||
req->best_parent_rate = best_parent_rate;
|
||||
req->best_parent_hw = __clk_get_hw(best_parent);
|
||||
req->rate = best_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long ep93xx_ddiv_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_psc *psc = to_clk_psc(hw);
|
||||
unsigned long rate = 0;
|
||||
u32 val = __raw_readl(psc->reg);
|
||||
int __pdiv = ((val >> EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) & 0x03);
|
||||
int __div = val & 0x7f;
|
||||
|
||||
if (__div > 0)
|
||||
rate = (parent_rate * 2) / ((__pdiv + 3) * __div);
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int ep93xx_ddiv_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_psc *psc = to_clk_psc(hw);
|
||||
int pdiv = 0, div = 0;
|
||||
unsigned long best_rate = 0, actual_rate, mclk_rate;
|
||||
int __div = 0, __pdiv = 0;
|
||||
u32 val;
|
||||
|
||||
mclk_rate = parent_rate * 2;
|
||||
|
||||
for (__pdiv = 4; __pdiv <= 6; __pdiv++) {
|
||||
__div = mclk_rate / (rate * __pdiv);
|
||||
if (__div < 2 || __div > 127)
|
||||
continue;
|
||||
|
||||
actual_rate = mclk_rate / (__pdiv * __div);
|
||||
if (is_best(rate, actual_rate, best_rate)) {
|
||||
pdiv = __pdiv - 3;
|
||||
div = __div;
|
||||
best_rate = actual_rate;
|
||||
}
|
||||
}
|
||||
|
||||
if (!best_rate)
|
||||
return -EINVAL;
|
||||
|
||||
val = __raw_readl(psc->reg);
|
||||
|
||||
/* Clear old dividers */
|
||||
val &= ~0x37f;
|
||||
|
||||
/* Set the new pdiv and div bits for the new clock rate */
|
||||
val |= (pdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | div;
|
||||
ep93xx_syscon_swlocked_write(val, psc->reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_ddiv_ops = {
|
||||
.enable = ep93xx_clk_enable,
|
||||
.disable = ep93xx_clk_disable,
|
||||
.is_enabled = ep93xx_clk_is_enabled,
|
||||
.get_parent = ep93xx_mux_get_parent,
|
||||
.set_parent = ep93xx_mux_set_parent_lock,
|
||||
.determine_rate = ep93xx_mux_determine_rate,
|
||||
.recalc_rate = ep93xx_ddiv_recalc_rate,
|
||||
.set_rate = ep93xx_ddiv_set_rate,
|
||||
};
|
||||
|
||||
static struct clk_hw *clk_hw_register_ddiv(const char *name,
|
||||
void __iomem *reg,
|
||||
u8 bit_idx)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
struct clk_psc *psc;
|
||||
struct clk *clk;
|
||||
|
||||
psc = kzalloc(sizeof(*psc), GFP_KERNEL);
|
||||
if (!psc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_ddiv_ops;
|
||||
init.flags = 0;
|
||||
init.parent_names = mux_parents;
|
||||
init.num_parents = ARRAY_SIZE(mux_parents);
|
||||
|
||||
psc->reg = reg;
|
||||
psc->bit_idx = bit_idx;
|
||||
psc->lock = &clk_lock;
|
||||
psc->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &psc->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
kfree(psc);
|
||||
return ERR_CAST(clk);
|
||||
}
|
||||
return &psc->hw;
|
||||
}
|
||||
|
||||
static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_psc *psc = to_clk_psc(hw);
|
||||
u32 val = __raw_readl(psc->reg);
|
||||
u8 index = (val & psc->mask) >> psc->shift;
|
||||
|
||||
if (index > psc->num_div)
|
||||
return 0;
|
||||
|
||||
return DIV_ROUND_UP_ULL(parent_rate, psc->div[index]);
|
||||
}
|
||||
|
||||
static long ep93xx_div_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct clk_psc *psc = to_clk_psc(hw);
|
||||
unsigned long best = 0, now, maxdiv;
|
||||
int i;
|
||||
|
||||
maxdiv = psc->div[psc->num_div - 1];
|
||||
|
||||
for (i = 0; i < psc->num_div; i++) {
|
||||
if ((rate * psc->div[i]) == *parent_rate)
|
||||
return DIV_ROUND_UP_ULL((u64)*parent_rate, psc->div[i]);
|
||||
|
||||
now = DIV_ROUND_UP_ULL((u64)*parent_rate, psc->div[i]);
|
||||
|
||||
if (is_best(rate, now, best))
|
||||
best = now;
|
||||
}
|
||||
|
||||
if (!best)
|
||||
best = DIV_ROUND_UP_ULL(*parent_rate, maxdiv);
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
static int ep93xx_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_psc *psc = to_clk_psc(hw);
|
||||
u32 val = __raw_readl(psc->reg) & ~psc->mask;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < psc->num_div; i++)
|
||||
if (rate == parent_rate / psc->div[i]) {
|
||||
val |= i << psc->shift;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == psc->num_div)
|
||||
return -EINVAL;
|
||||
|
||||
ep93xx_syscon_swlocked_write(val, psc->reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops ep93xx_div_ops = {
|
||||
.enable = ep93xx_clk_enable,
|
||||
.disable = ep93xx_clk_disable,
|
||||
.is_enabled = ep93xx_clk_is_enabled,
|
||||
.recalc_rate = ep93xx_div_recalc_rate,
|
||||
.round_rate = ep93xx_div_round_rate,
|
||||
.set_rate = ep93xx_div_set_rate,
|
||||
};
|
||||
|
||||
static struct clk_hw *clk_hw_register_div(const char *name,
|
||||
const char *parent_name,
|
||||
void __iomem *reg,
|
||||
u8 enable_bit,
|
||||
u8 shift,
|
||||
u8 width,
|
||||
char *clk_divisors,
|
||||
u8 num_div)
|
||||
{
|
||||
struct clk_init_data init;
|
||||
struct clk_psc *psc;
|
||||
struct clk *clk;
|
||||
|
||||
psc = kzalloc(sizeof(*psc), GFP_KERNEL);
|
||||
if (!psc)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
init.name = name;
|
||||
init.ops = &ep93xx_div_ops;
|
||||
init.flags = 0;
|
||||
init.parent_names = (parent_name ? &parent_name : NULL);
|
||||
init.num_parents = 1;
|
||||
|
||||
psc->reg = reg;
|
||||
psc->bit_idx = enable_bit;
|
||||
psc->mask = GENMASK(shift + width - 1, shift);
|
||||
psc->shift = shift;
|
||||
psc->div = clk_divisors;
|
||||
psc->num_div = num_div;
|
||||
psc->lock = &clk_lock;
|
||||
psc->hw.init = &init;
|
||||
|
||||
clk = clk_register(NULL, &psc->hw);
|
||||
if (IS_ERR(clk)) {
|
||||
kfree(psc);
|
||||
return ERR_CAST(clk);
|
||||
}
|
||||
return &psc->hw;
|
||||
}
|
||||
|
||||
struct ep93xx_gate {
|
||||
unsigned int bit;
|
||||
const char *dev_id;
|
||||
const char *con_id;
|
||||
};
|
||||
|
||||
static struct ep93xx_gate ep93xx_uarts[] = {
|
||||
{EP93XX_SYSCON_DEVCFG_U1EN, "apb:uart1", NULL},
|
||||
{EP93XX_SYSCON_DEVCFG_U2EN, "apb:uart2", NULL},
|
||||
{EP93XX_SYSCON_DEVCFG_U3EN, "apb:uart3", NULL},
|
||||
};
|
||||
|
||||
static void __init ep93xx_uart_clock_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
struct clk_hw *hw;
|
||||
u32 value;
|
||||
unsigned int clk_uart_div;
|
||||
|
||||
value = __raw_readl(EP93XX_SYSCON_PWRCNT);
|
||||
if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD)
|
||||
clk_uart_div = 1;
|
||||
else
|
||||
clk_uart_div = 2;
|
||||
|
||||
hw = clk_hw_register_fixed_factor(NULL, "uart", "xtali", 0, 1, clk_uart_div);
|
||||
|
||||
/* parenting uart gate clocks to uart clock */
|
||||
for (i = 0; i < ARRAY_SIZE(ep93xx_uarts); i++) {
|
||||
hw = ep93xx_clk_register_gate(ep93xx_uarts[i].dev_id,
|
||||
"uart",
|
||||
EP93XX_SYSCON_DEVCFG,
|
||||
ep93xx_uarts[i].bit);
|
||||
|
||||
clk_hw_register_clkdev(hw, NULL, ep93xx_uarts[i].dev_id);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ep93xx_gate ep93xx_dmas[] = {
|
||||
{EP93XX_SYSCON_PWRCNT_DMA_M2P0, NULL, "m2p0"},
|
||||
{EP93XX_SYSCON_PWRCNT_DMA_M2P1, NULL, "m2p1"},
|
||||
{EP93XX_SYSCON_PWRCNT_DMA_M2P2, NULL, "m2p2"},
|
||||
{EP93XX_SYSCON_PWRCNT_DMA_M2P3, NULL, "m2p3"},
|
||||
{EP93XX_SYSCON_PWRCNT_DMA_M2P4, NULL, "m2p4"},
|
||||
{EP93XX_SYSCON_PWRCNT_DMA_M2P5, NULL, "m2p5"},
|
||||
{EP93XX_SYSCON_PWRCNT_DMA_M2P6, NULL, "m2p6"},
|
||||
{EP93XX_SYSCON_PWRCNT_DMA_M2P7, NULL, "m2p7"},
|
||||
{EP93XX_SYSCON_PWRCNT_DMA_M2P8, NULL, "m2p8"},
|
||||
{EP93XX_SYSCON_PWRCNT_DMA_M2P9, NULL, "m2p9"},
|
||||
{EP93XX_SYSCON_PWRCNT_DMA_M2M0, NULL, "m2m0"},
|
||||
{EP93XX_SYSCON_PWRCNT_DMA_M2M1, NULL, "m2m1"},
|
||||
};
|
||||
|
||||
static void __init ep93xx_dma_clock_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
struct clk_hw *hw;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ep93xx_dmas); i++) {
|
||||
hw = clk_hw_register_gate(NULL, ep93xx_dmas[i].con_id,
|
||||
"hclk", 0,
|
||||
EP93XX_SYSCON_PWRCNT,
|
||||
ep93xx_dmas[i].bit,
|
||||
0,
|
||||
&clk_lock);
|
||||
|
||||
ret = clk_hw_register_clkdev(hw, ep93xx_dmas[i].con_id, NULL);
|
||||
if (ret)
|
||||
pr_err("%s: failed to register lookup %s\n",
|
||||
__func__, ep93xx_dmas[i].con_id);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init ep93xx_clock_init(void)
|
||||
{
|
||||
u32 value;
|
||||
struct clk_hw *hw;
|
||||
unsigned long clk_pll1_rate;
|
||||
unsigned long clk_f_rate;
|
||||
unsigned long clk_h_rate;
|
||||
unsigned long clk_p_rate;
|
||||
unsigned long clk_pll2_rate;
|
||||
unsigned int clk_f_div;
|
||||
unsigned int clk_h_div;
|
||||
unsigned int clk_p_div;
|
||||
unsigned int clk_usb_div;
|
||||
unsigned long clk_spi_div;
|
||||
|
||||
hw = clk_hw_register_fixed_rate(NULL, "xtali", NULL, 0, EP93XX_EXT_CLK_RATE);
|
||||
clk_hw_register_clkdev(hw, NULL, "xtali");
|
||||
|
||||
/* Determine the bootloader configured pll1 rate */
|
||||
value = __raw_readl(EP93XX_SYSCON_CLKSET1);
|
||||
if (!(value & EP93XX_SYSCON_CLKSET1_NBYP1))
|
||||
clk_pll1_rate = EP93XX_EXT_CLK_RATE;
|
||||
else
|
||||
clk_pll1_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value);
|
||||
|
||||
hw = clk_hw_register_fixed_rate(NULL, "pll1", "xtali", 0, clk_pll1_rate);
|
||||
clk_hw_register_clkdev(hw, NULL, "pll1");
|
||||
|
||||
/* Initialize the pll1 derived clocks */
|
||||
clk_f_div = fclk_divisors[(value >> 25) & 0x7];
|
||||
clk_h_div = hclk_divisors[(value >> 20) & 0x7];
|
||||
clk_p_div = pclk_divisors[(value >> 18) & 0x3];
|
||||
|
||||
hw = clk_hw_register_fixed_factor(NULL, "fclk", "pll1", 0, 1, clk_f_div);
|
||||
clk_f_rate = clk_get_rate(hw->clk);
|
||||
hw = clk_hw_register_fixed_factor(NULL, "hclk", "pll1", 0, 1, clk_h_div);
|
||||
clk_h_rate = clk_get_rate(hw->clk);
|
||||
hw = clk_hw_register_fixed_factor(NULL, "pclk", "hclk", 0, 1, clk_p_div);
|
||||
clk_p_rate = clk_get_rate(hw->clk);
|
||||
|
||||
clk_hw_register_clkdev(hw, "apb_pclk", NULL);
|
||||
|
||||
ep93xx_dma_clock_init();
|
||||
|
||||
/* Determine the bootloader configured pll2 rate */
|
||||
value = __raw_readl(EP93XX_SYSCON_CLKSET2);
|
||||
if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2))
|
||||
clk_pll2_rate = EP93XX_EXT_CLK_RATE;
|
||||
else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN)
|
||||
clk_pll2_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value);
|
||||
else
|
||||
clk_pll2_rate = 0;
|
||||
|
||||
hw = clk_hw_register_fixed_rate(NULL, "pll2", "xtali", 0, clk_pll2_rate);
|
||||
clk_hw_register_clkdev(hw, NULL, "pll2");
|
||||
|
||||
/* Initialize the pll2 derived clocks */
|
||||
/*
|
||||
* These four bits set the divide ratio between the PLL2
|
||||
* output and the USB clock.
|
||||
* 0000 - Divide by 1
|
||||
* 0001 - Divide by 2
|
||||
* 0010 - Divide by 3
|
||||
* 0011 - Divide by 4
|
||||
* 0100 - Divide by 5
|
||||
* 0101 - Divide by 6
|
||||
* 0110 - Divide by 7
|
||||
* 0111 - Divide by 8
|
||||
* 1000 - Divide by 9
|
||||
* 1001 - Divide by 10
|
||||
* 1010 - Divide by 11
|
||||
* 1011 - Divide by 12
|
||||
* 1100 - Divide by 13
|
||||
* 1101 - Divide by 14
|
||||
* 1110 - Divide by 15
|
||||
* 1111 - Divide by 1
|
||||
* On power-on-reset these bits are reset to 0000b.
|
||||
*/
|
||||
clk_usb_div = (((value >> 28) & 0xf) + 1);
|
||||
hw = clk_hw_register_fixed_factor(NULL, "usb_clk", "pll2", 0, 1, clk_usb_div);
|
||||
hw = clk_hw_register_gate(NULL, "ohci-platform",
|
||||
"usb_clk", 0,
|
||||
EP93XX_SYSCON_PWRCNT,
|
||||
EP93XX_SYSCON_PWRCNT_USH_EN,
|
||||
0,
|
||||
&clk_lock);
|
||||
clk_hw_register_clkdev(hw, NULL, "ohci-platform");
|
||||
|
||||
/*
|
||||
* EP93xx SSP clock rate was doubled in version E2. For more information
|
||||
* see:
|
||||
* http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
|
||||
*/
|
||||
clk_spi_div = 1;
|
||||
if (ep93xx_chip_revision() < EP93XX_CHIP_REV_E2)
|
||||
clk_spi_div = 2;
|
||||
hw = clk_hw_register_fixed_factor(NULL, "ep93xx-spi.0", "xtali", 0, 1, clk_spi_div);
|
||||
clk_hw_register_clkdev(hw, NULL, "ep93xx-spi.0");
|
||||
|
||||
/* pwm clock */
|
||||
hw = clk_hw_register_fixed_factor(NULL, "pwm_clk", "xtali", 0, 1, 1);
|
||||
clk_hw_register_clkdev(hw, "pwm_clk", NULL);
|
||||
|
||||
pr_info("PLL1 running at %ld MHz, PLL2 at %ld MHz\n",
|
||||
clk_pll1_rate / 1000000, clk_pll2_rate / 1000000);
|
||||
pr_info("FCLK %ld MHz, HCLK %ld MHz, PCLK %ld MHz\n",
|
||||
clk_f_rate / 1000000, clk_h_rate / 1000000,
|
||||
clk_p_rate / 1000000);
|
||||
|
||||
ep93xx_uart_clock_init();
|
||||
|
||||
/* touchscreen/adc clock */
|
||||
hw = clk_hw_register_div("ep93xx-adc",
|
||||
"xtali",
|
||||
EP93XX_SYSCON_KEYTCHCLKDIV,
|
||||
EP93XX_SYSCON_KEYTCHCLKDIV_TSEN,
|
||||
EP93XX_SYSCON_KEYTCHCLKDIV_ADIV,
|
||||
1,
|
||||
adc_divisors,
|
||||
ARRAY_SIZE(adc_divisors));
|
||||
|
||||
clk_hw_register_clkdev(hw, NULL, "ep93xx-adc");
|
||||
|
||||
/* keypad clock */
|
||||
hw = clk_hw_register_div("ep93xx-keypad",
|
||||
"xtali",
|
||||
EP93XX_SYSCON_KEYTCHCLKDIV,
|
||||
EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
|
||||
EP93XX_SYSCON_KEYTCHCLKDIV_KDIV,
|
||||
1,
|
||||
adc_divisors,
|
||||
ARRAY_SIZE(adc_divisors));
|
||||
|
||||
clk_hw_register_clkdev(hw, NULL, "ep93xx-keypad");
|
||||
|
||||
/* On reset PDIV and VDIV is set to zero, while PDIV zero
|
||||
* means clock disable, VDIV shouldn't be zero.
|
||||
* So i set both dividers to minimum.
|
||||
*/
|
||||
/* ENA - Enable CLK divider. */
|
||||
/* PDIV - 00 - Disable clock */
|
||||
/* VDIV - at least 2 */
|
||||
/* Check and enable video clk registers */
|
||||
value = __raw_readl(EP93XX_SYSCON_VIDCLKDIV);
|
||||
value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
|
||||
ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_VIDCLKDIV);
|
||||
|
||||
/* check and enable i2s clk registers */
|
||||
value = __raw_readl(EP93XX_SYSCON_I2SCLKDIV);
|
||||
value |= (1 << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
|
||||
ep93xx_syscon_swlocked_write(value, EP93XX_SYSCON_I2SCLKDIV);
|
||||
|
||||
/* video clk */
|
||||
hw = clk_hw_register_ddiv("ep93xx-fb",
|
||||
EP93XX_SYSCON_VIDCLKDIV,
|
||||
EP93XX_SYSCON_CLKDIV_ENABLE);
|
||||
|
||||
clk_hw_register_clkdev(hw, NULL, "ep93xx-fb");
|
||||
|
||||
/* i2s clk */
|
||||
hw = clk_hw_register_ddiv("mclk",
|
||||
EP93XX_SYSCON_I2SCLKDIV,
|
||||
EP93XX_SYSCON_CLKDIV_ENABLE);
|
||||
|
||||
clk_hw_register_clkdev(hw, "mclk", "ep93xx-i2s");
|
||||
|
||||
/* i2s sclk */
|
||||
#define EP93XX_I2SCLKDIV_SDIV_SHIFT 16
|
||||
#define EP93XX_I2SCLKDIV_SDIV_WIDTH 1
|
||||
hw = clk_hw_register_div("sclk",
|
||||
"mclk",
|
||||
EP93XX_SYSCON_I2SCLKDIV,
|
||||
EP93XX_SYSCON_I2SCLKDIV_SENA,
|
||||
EP93XX_I2SCLKDIV_SDIV_SHIFT,
|
||||
EP93XX_I2SCLKDIV_SDIV_WIDTH,
|
||||
sclk_divisors,
|
||||
ARRAY_SIZE(sclk_divisors));
|
||||
|
||||
clk_hw_register_clkdev(hw, "sclk", "ep93xx-i2s");
|
||||
|
||||
/* i2s lrclk */
|
||||
#define EP93XX_I2SCLKDIV_LRDIV32_SHIFT 17
|
||||
#define EP93XX_I2SCLKDIV_LRDIV32_WIDTH 3
|
||||
hw = clk_hw_register_div("lrclk",
|
||||
"sclk",
|
||||
EP93XX_SYSCON_I2SCLKDIV,
|
||||
EP93XX_SYSCON_I2SCLKDIV_SENA,
|
||||
EP93XX_I2SCLKDIV_LRDIV32_SHIFT,
|
||||
EP93XX_I2SCLKDIV_LRDIV32_WIDTH,
|
||||
lrclk_divisors,
|
||||
ARRAY_SIZE(lrclk_divisors));
|
||||
|
||||
clk_hw_register_clkdev(hw, "lrclk", "ep93xx-i2s");
|
||||
|
||||
return 0;
|
||||
}
|
||||
postcore_initcall(ep93xx_clock_init);
|
File diff suppressed because it is too large
Load Diff
@ -1,114 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* arch/arm/mach-ep93xx/dma.c
|
||||
*
|
||||
* Platform support code for the EP93xx dmaengine driver.
|
||||
*
|
||||
* Copyright (C) 2011 Mika Westerberg
|
||||
*
|
||||
* This work is based on the original dma-m2p implementation with
|
||||
* following copyrights:
|
||||
*
|
||||
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
|
||||
* Copyright (C) 2006 Applied Data Systems
|
||||
* Copyright (C) 2009 Ryan Mallon <rmallon@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/platform_data/dma-ep93xx.h>
|
||||
#include "hardware.h"
|
||||
|
||||
#include "soc.h"
|
||||
|
||||
#define DMA_CHANNEL(_name, _base, _irq) \
|
||||
{ .name = (_name), .base = (_base), .irq = (_irq) }
|
||||
|
||||
/*
|
||||
* DMA M2P channels.
|
||||
*
|
||||
* On the EP93xx chip the following peripherals my be allocated to the 10
|
||||
* Memory to Internal Peripheral (M2P) channels (5 transmit + 5 receive).
|
||||
*
|
||||
* I2S contains 3 Tx and 3 Rx DMA Channels
|
||||
* AAC contains 3 Tx and 3 Rx DMA Channels
|
||||
* UART1 contains 1 Tx and 1 Rx DMA Channels
|
||||
* UART2 contains 1 Tx and 1 Rx DMA Channels
|
||||
* UART3 contains 1 Tx and 1 Rx DMA Channels
|
||||
* IrDA contains 1 Tx and 1 Rx DMA Channels
|
||||
*
|
||||
* Registers are mapped statically in ep93xx_map_io().
|
||||
*/
|
||||
static struct ep93xx_dma_chan_data ep93xx_dma_m2p_channels[] = {
|
||||
DMA_CHANNEL("m2p0", EP93XX_DMA_BASE + 0x0000, IRQ_EP93XX_DMAM2P0),
|
||||
DMA_CHANNEL("m2p1", EP93XX_DMA_BASE + 0x0040, IRQ_EP93XX_DMAM2P1),
|
||||
DMA_CHANNEL("m2p2", EP93XX_DMA_BASE + 0x0080, IRQ_EP93XX_DMAM2P2),
|
||||
DMA_CHANNEL("m2p3", EP93XX_DMA_BASE + 0x00c0, IRQ_EP93XX_DMAM2P3),
|
||||
DMA_CHANNEL("m2p4", EP93XX_DMA_BASE + 0x0240, IRQ_EP93XX_DMAM2P4),
|
||||
DMA_CHANNEL("m2p5", EP93XX_DMA_BASE + 0x0200, IRQ_EP93XX_DMAM2P5),
|
||||
DMA_CHANNEL("m2p6", EP93XX_DMA_BASE + 0x02c0, IRQ_EP93XX_DMAM2P6),
|
||||
DMA_CHANNEL("m2p7", EP93XX_DMA_BASE + 0x0280, IRQ_EP93XX_DMAM2P7),
|
||||
DMA_CHANNEL("m2p8", EP93XX_DMA_BASE + 0x0340, IRQ_EP93XX_DMAM2P8),
|
||||
DMA_CHANNEL("m2p9", EP93XX_DMA_BASE + 0x0300, IRQ_EP93XX_DMAM2P9),
|
||||
};
|
||||
|
||||
static struct ep93xx_dma_platform_data ep93xx_dma_m2p_data = {
|
||||
.channels = ep93xx_dma_m2p_channels,
|
||||
.num_channels = ARRAY_SIZE(ep93xx_dma_m2p_channels),
|
||||
};
|
||||
|
||||
static u64 ep93xx_dma_m2p_mask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct platform_device ep93xx_dma_m2p_device = {
|
||||
.name = "ep93xx-dma-m2p",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &ep93xx_dma_m2p_data,
|
||||
.dma_mask = &ep93xx_dma_m2p_mask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* DMA M2M channels.
|
||||
*
|
||||
* There are 2 M2M channels which support memcpy/memset and in addition simple
|
||||
* hardware requests from/to SSP and IDE. We do not implement an external
|
||||
* hardware requests.
|
||||
*
|
||||
* Registers are mapped statically in ep93xx_map_io().
|
||||
*/
|
||||
static struct ep93xx_dma_chan_data ep93xx_dma_m2m_channels[] = {
|
||||
DMA_CHANNEL("m2m0", EP93XX_DMA_BASE + 0x0100, IRQ_EP93XX_DMAM2M0),
|
||||
DMA_CHANNEL("m2m1", EP93XX_DMA_BASE + 0x0140, IRQ_EP93XX_DMAM2M1),
|
||||
};
|
||||
|
||||
static struct ep93xx_dma_platform_data ep93xx_dma_m2m_data = {
|
||||
.channels = ep93xx_dma_m2m_channels,
|
||||
.num_channels = ARRAY_SIZE(ep93xx_dma_m2m_channels),
|
||||
};
|
||||
|
||||
static u64 ep93xx_dma_m2m_mask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct platform_device ep93xx_dma_m2m_device = {
|
||||
.name = "ep93xx-dma-m2m",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &ep93xx_dma_m2m_data,
|
||||
.dma_mask = &ep93xx_dma_m2m_mask,
|
||||
.coherent_dma_mask = DMA_BIT_MASK(32),
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ep93xx_dma_init(void)
|
||||
{
|
||||
platform_device_register(&ep93xx_dma_m2p_device);
|
||||
platform_device_register(&ep93xx_dma_m2m_device);
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(ep93xx_dma_init);
|
@ -1,368 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* arch/arm/mach-ep93xx/edb93xx.c
|
||||
* Cirrus Logic EDB93xx Development Board support.
|
||||
*
|
||||
* EDB93XX, EDB9301, EDB9307A
|
||||
* Copyright (C) 2008-2009 H Hartley Sweeten <hsweeten@visionengravers.com>
|
||||
*
|
||||
* EDB9302
|
||||
* Copyright (C) 2006 George Kashperko <george@chas.com.ua>
|
||||
*
|
||||
* EDB9302A, EDB9315, EDB9315A
|
||||
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
|
||||
*
|
||||
* EDB9307
|
||||
* Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
*
|
||||
* EDB9312
|
||||
* Copyright (C) 2006 Infosys Technologies Limited
|
||||
* Toufeeq Hussain <toufeeq_hussain@infosys.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
|
||||
#include <sound/cs4271.h>
|
||||
|
||||
#include "hardware.h"
|
||||
#include <linux/platform_data/video-ep93xx.h>
|
||||
#include <linux/platform_data/spi-ep93xx.h>
|
||||
#include "gpio-ep93xx.h"
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
#include "soc.h"
|
||||
|
||||
static void __init edb93xx_register_flash(void)
|
||||
{
|
||||
if (machine_is_edb9307() || machine_is_edb9312() ||
|
||||
machine_is_edb9315()) {
|
||||
ep93xx_register_flash(4, EP93XX_CS6_PHYS_BASE, SZ_32M);
|
||||
} else {
|
||||
ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_16M);
|
||||
}
|
||||
}
|
||||
|
||||
static struct ep93xx_eth_data __initdata edb93xx_eth_data = {
|
||||
.phy_id = 1,
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* EDB93xx i2c peripheral handling
|
||||
*************************************************************************/
|
||||
|
||||
static struct i2c_board_info __initdata edb93xxa_i2c_board_info[] = {
|
||||
{
|
||||
I2C_BOARD_INFO("isl1208", 0x6f),
|
||||
},
|
||||
};
|
||||
|
||||
static struct i2c_board_info __initdata edb93xx_i2c_board_info[] = {
|
||||
{
|
||||
I2C_BOARD_INFO("ds1337", 0x68),
|
||||
},
|
||||
};
|
||||
|
||||
static void __init edb93xx_register_i2c(void)
|
||||
{
|
||||
if (machine_is_edb9302a() || machine_is_edb9307a() ||
|
||||
machine_is_edb9315a()) {
|
||||
ep93xx_register_i2c(edb93xxa_i2c_board_info,
|
||||
ARRAY_SIZE(edb93xxa_i2c_board_info));
|
||||
} else if (machine_is_edb9302() || machine_is_edb9307()
|
||||
|| machine_is_edb9312() || machine_is_edb9315()) {
|
||||
ep93xx_register_i2c(edb93xx_i2c_board_info,
|
||||
ARRAY_SIZE(edb93xx_i2c_board_info));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* EDB93xx SPI peripheral handling
|
||||
*************************************************************************/
|
||||
static struct cs4271_platform_data edb93xx_cs4271_data = {
|
||||
/* Intentionally left blank */
|
||||
};
|
||||
|
||||
static struct spi_board_info edb93xx_spi_board_info[] __initdata = {
|
||||
{
|
||||
.modalias = "cs4271",
|
||||
.platform_data = &edb93xx_cs4271_data,
|
||||
.max_speed_hz = 6000000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table edb93xx_spi_cs_gpio_table = {
|
||||
.dev_id = "spi0",
|
||||
.table = {
|
||||
GPIO_LOOKUP("A", 6, "cs", GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static struct ep93xx_spi_info edb93xx_spi_info __initdata = {
|
||||
/* Intentionally left blank */
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table edb93xx_cs4272_edb9301_gpio_table = {
|
||||
.dev_id = "spi0.0", /* CS0 on SPI0 */
|
||||
.table = {
|
||||
GPIO_LOOKUP("A", 1, "reset", GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table edb93xx_cs4272_edb9302_gpio_table = {
|
||||
.dev_id = "spi0.0", /* CS0 on SPI0 */
|
||||
.table = {
|
||||
GPIO_LOOKUP("H", 2, "reset", GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table edb93xx_cs4272_edb9315_gpio_table = {
|
||||
.dev_id = "spi0.0", /* CS0 on SPI0 */
|
||||
.table = {
|
||||
GPIO_LOOKUP("B", 6, "reset", GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static void __init edb93xx_register_spi(void)
|
||||
{
|
||||
if (machine_is_edb9301() || machine_is_edb9302())
|
||||
gpiod_add_lookup_table(&edb93xx_cs4272_edb9301_gpio_table);
|
||||
else if (machine_is_edb9302a() || machine_is_edb9307a())
|
||||
gpiod_add_lookup_table(&edb93xx_cs4272_edb9302_gpio_table);
|
||||
else if (machine_is_edb9315a())
|
||||
gpiod_add_lookup_table(&edb93xx_cs4272_edb9315_gpio_table);
|
||||
|
||||
gpiod_add_lookup_table(&edb93xx_spi_cs_gpio_table);
|
||||
ep93xx_register_spi(&edb93xx_spi_info, edb93xx_spi_board_info,
|
||||
ARRAY_SIZE(edb93xx_spi_board_info));
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* EDB93xx I2S
|
||||
*************************************************************************/
|
||||
static struct platform_device edb93xx_audio_device = {
|
||||
.name = "edb93xx-audio",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static int __init edb93xx_has_audio(void)
|
||||
{
|
||||
return (machine_is_edb9301() || machine_is_edb9302() ||
|
||||
machine_is_edb9302a() || machine_is_edb9307a() ||
|
||||
machine_is_edb9315a());
|
||||
}
|
||||
|
||||
static void __init edb93xx_register_i2s(void)
|
||||
{
|
||||
if (edb93xx_has_audio()) {
|
||||
ep93xx_register_i2s();
|
||||
platform_device_register(&edb93xx_audio_device);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* EDB93xx pwm
|
||||
*************************************************************************/
|
||||
static void __init edb93xx_register_pwm(void)
|
||||
{
|
||||
if (machine_is_edb9301() ||
|
||||
machine_is_edb9302() || machine_is_edb9302a()) {
|
||||
/* EP9301 and EP9302 only have pwm.1 (EGPIO14) */
|
||||
ep93xx_register_pwm(0, 1);
|
||||
} else if (machine_is_edb9307() || machine_is_edb9307a()) {
|
||||
/* EP9307 only has pwm.0 (PWMOUT) */
|
||||
ep93xx_register_pwm(1, 0);
|
||||
} else {
|
||||
/* EP9312 and EP9315 have both */
|
||||
ep93xx_register_pwm(1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* EDB93xx framebuffer
|
||||
*************************************************************************/
|
||||
static struct ep93xxfb_mach_info __initdata edb93xxfb_info = {
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
static int __init edb93xx_has_fb(void)
|
||||
{
|
||||
/* These platforms have an ep93xx with video capability */
|
||||
return machine_is_edb9307() || machine_is_edb9307a() ||
|
||||
machine_is_edb9312() || machine_is_edb9315() ||
|
||||
machine_is_edb9315a();
|
||||
}
|
||||
|
||||
static void __init edb93xx_register_fb(void)
|
||||
{
|
||||
if (!edb93xx_has_fb())
|
||||
return;
|
||||
|
||||
if (machine_is_edb9307a() || machine_is_edb9315a())
|
||||
edb93xxfb_info.flags |= EP93XXFB_USE_SDCSN0;
|
||||
else
|
||||
edb93xxfb_info.flags |= EP93XXFB_USE_SDCSN3;
|
||||
|
||||
ep93xx_register_fb(&edb93xxfb_info);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* EDB93xx IDE
|
||||
*************************************************************************/
|
||||
static int __init edb93xx_has_ide(void)
|
||||
{
|
||||
/*
|
||||
* Although EDB9312 and EDB9315 do have IDE capability, they have
|
||||
* INTRQ line wired as pull-up, which makes using IDE interface
|
||||
* problematic.
|
||||
*/
|
||||
return machine_is_edb9312() || machine_is_edb9315() ||
|
||||
machine_is_edb9315a();
|
||||
}
|
||||
|
||||
static void __init edb93xx_register_ide(void)
|
||||
{
|
||||
if (!edb93xx_has_ide())
|
||||
return;
|
||||
|
||||
ep93xx_register_ide();
|
||||
}
|
||||
|
||||
|
||||
static void __init edb93xx_init_machine(void)
|
||||
{
|
||||
ep93xx_init_devices();
|
||||
edb93xx_register_flash();
|
||||
ep93xx_register_eth(&edb93xx_eth_data, 1);
|
||||
edb93xx_register_i2c();
|
||||
edb93xx_register_spi();
|
||||
edb93xx_register_i2s();
|
||||
edb93xx_register_pwm();
|
||||
edb93xx_register_fb();
|
||||
edb93xx_register_ide();
|
||||
ep93xx_register_adc();
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_MACH_EDB9301
|
||||
MACHINE_START(EDB9301, "Cirrus Logic EDB9301 Evaluation Board")
|
||||
/* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */
|
||||
.atag_offset = 0x100,
|
||||
.nr_irqs = NR_EP93XX_IRQS,
|
||||
.map_io = ep93xx_map_io,
|
||||
.init_irq = ep93xx_init_irq,
|
||||
.init_time = ep93xx_timer_init,
|
||||
.init_machine = edb93xx_init_machine,
|
||||
.restart = ep93xx_restart,
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MACH_EDB9302
|
||||
MACHINE_START(EDB9302, "Cirrus Logic EDB9302 Evaluation Board")
|
||||
/* Maintainer: George Kashperko <george@chas.com.ua> */
|
||||
.atag_offset = 0x100,
|
||||
.nr_irqs = NR_EP93XX_IRQS,
|
||||
.map_io = ep93xx_map_io,
|
||||
.init_irq = ep93xx_init_irq,
|
||||
.init_time = ep93xx_timer_init,
|
||||
.init_machine = edb93xx_init_machine,
|
||||
.restart = ep93xx_restart,
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MACH_EDB9302A
|
||||
MACHINE_START(EDB9302A, "Cirrus Logic EDB9302A Evaluation Board")
|
||||
/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
|
||||
.atag_offset = 0x100,
|
||||
.nr_irqs = NR_EP93XX_IRQS,
|
||||
.map_io = ep93xx_map_io,
|
||||
.init_irq = ep93xx_init_irq,
|
||||
.init_time = ep93xx_timer_init,
|
||||
.init_machine = edb93xx_init_machine,
|
||||
.restart = ep93xx_restart,
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MACH_EDB9307
|
||||
MACHINE_START(EDB9307, "Cirrus Logic EDB9307 Evaluation Board")
|
||||
/* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */
|
||||
.atag_offset = 0x100,
|
||||
.nr_irqs = NR_EP93XX_IRQS,
|
||||
.map_io = ep93xx_map_io,
|
||||
.init_irq = ep93xx_init_irq,
|
||||
.init_time = ep93xx_timer_init,
|
||||
.init_machine = edb93xx_init_machine,
|
||||
.restart = ep93xx_restart,
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MACH_EDB9307A
|
||||
MACHINE_START(EDB9307A, "Cirrus Logic EDB9307A Evaluation Board")
|
||||
/* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */
|
||||
.atag_offset = 0x100,
|
||||
.nr_irqs = NR_EP93XX_IRQS,
|
||||
.map_io = ep93xx_map_io,
|
||||
.init_irq = ep93xx_init_irq,
|
||||
.init_time = ep93xx_timer_init,
|
||||
.init_machine = edb93xx_init_machine,
|
||||
.restart = ep93xx_restart,
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MACH_EDB9312
|
||||
MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board")
|
||||
/* Maintainer: Toufeeq Hussain <toufeeq_hussain@infosys.com> */
|
||||
.atag_offset = 0x100,
|
||||
.nr_irqs = NR_EP93XX_IRQS,
|
||||
.map_io = ep93xx_map_io,
|
||||
.init_irq = ep93xx_init_irq,
|
||||
.init_time = ep93xx_timer_init,
|
||||
.init_machine = edb93xx_init_machine,
|
||||
.restart = ep93xx_restart,
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MACH_EDB9315
|
||||
MACHINE_START(EDB9315, "Cirrus Logic EDB9315 Evaluation Board")
|
||||
/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
|
||||
.atag_offset = 0x100,
|
||||
.nr_irqs = NR_EP93XX_IRQS,
|
||||
.map_io = ep93xx_map_io,
|
||||
.init_irq = ep93xx_init_irq,
|
||||
.init_time = ep93xx_timer_init,
|
||||
.init_machine = edb93xx_init_machine,
|
||||
.restart = ep93xx_restart,
|
||||
MACHINE_END
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MACH_EDB9315A
|
||||
MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board")
|
||||
/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
|
||||
.atag_offset = 0x100,
|
||||
.nr_irqs = NR_EP93XX_IRQS,
|
||||
.map_io = ep93xx_map_io,
|
||||
.init_irq = ep93xx_init_irq,
|
||||
.init_time = ep93xx_timer_init,
|
||||
.init_machine = edb93xx_init_machine,
|
||||
.restart = ep93xx_restart,
|
||||
MACHINE_END
|
||||
#endif
|
@ -1,38 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __ASM_ARCH_EP93XX_REGS_H
|
||||
#define __ASM_ARCH_EP93XX_REGS_H
|
||||
|
||||
/*
|
||||
* EP93xx linux memory map:
|
||||
*
|
||||
* virt phys size
|
||||
* fe800000 5M per-platform mappings
|
||||
* fed00000 80800000 2M APB
|
||||
* fef00000 80000000 1M AHB
|
||||
*/
|
||||
|
||||
#define EP93XX_AHB_PHYS_BASE 0x80000000
|
||||
#define EP93XX_AHB_VIRT_BASE 0xfef00000
|
||||
#define EP93XX_AHB_SIZE 0x00100000
|
||||
|
||||
#define EP93XX_AHB_PHYS(x) (EP93XX_AHB_PHYS_BASE + (x))
|
||||
#define EP93XX_AHB_IOMEM(x) IOMEM(EP93XX_AHB_VIRT_BASE + (x))
|
||||
|
||||
#define EP93XX_APB_PHYS_BASE 0x80800000
|
||||
#define EP93XX_APB_VIRT_BASE 0xfed00000
|
||||
#define EP93XX_APB_SIZE 0x00200000
|
||||
|
||||
#define EP93XX_APB_PHYS(x) (EP93XX_APB_PHYS_BASE + (x))
|
||||
#define EP93XX_APB_IOMEM(x) IOMEM(EP93XX_APB_VIRT_BASE + (x))
|
||||
|
||||
/* APB UARTs */
|
||||
#define EP93XX_UART1_PHYS_BASE EP93XX_APB_PHYS(0x000c0000)
|
||||
#define EP93XX_UART1_BASE EP93XX_APB_IOMEM(0x000c0000)
|
||||
|
||||
#define EP93XX_UART2_PHYS_BASE EP93XX_APB_PHYS(0x000d0000)
|
||||
#define EP93XX_UART2_BASE EP93XX_APB_IOMEM(0x000d0000)
|
||||
|
||||
#define EP93XX_UART3_PHYS_BASE EP93XX_APB_PHYS(0x000e0000)
|
||||
#define EP93XX_UART3_BASE EP93XX_APB_IOMEM(0x000e0000)
|
||||
|
||||
#endif
|
@ -1,111 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Include file for the EP93XX GPIO controller machine specifics */
|
||||
|
||||
#ifndef __GPIO_EP93XX_H
|
||||
#define __GPIO_EP93XX_H
|
||||
|
||||
#include "ep93xx-regs.h"
|
||||
|
||||
#define EP93XX_GPIO_PHYS_BASE EP93XX_APB_PHYS(0x00040000)
|
||||
#define EP93XX_GPIO_BASE EP93XX_APB_IOMEM(0x00040000)
|
||||
#define EP93XX_GPIO_REG(x) (EP93XX_GPIO_BASE + (x))
|
||||
#define EP93XX_GPIO_F_INT_STATUS EP93XX_GPIO_REG(0x5c)
|
||||
#define EP93XX_GPIO_A_INT_STATUS EP93XX_GPIO_REG(0xa0)
|
||||
#define EP93XX_GPIO_B_INT_STATUS EP93XX_GPIO_REG(0xbc)
|
||||
#define EP93XX_GPIO_EEDRIVE EP93XX_GPIO_REG(0xc8)
|
||||
|
||||
/* GPIO port A. */
|
||||
#define EP93XX_GPIO_LINE_A(x) ((x) + 0)
|
||||
#define EP93XX_GPIO_LINE_EGPIO0 EP93XX_GPIO_LINE_A(0)
|
||||
#define EP93XX_GPIO_LINE_EGPIO1 EP93XX_GPIO_LINE_A(1)
|
||||
#define EP93XX_GPIO_LINE_EGPIO2 EP93XX_GPIO_LINE_A(2)
|
||||
#define EP93XX_GPIO_LINE_EGPIO3 EP93XX_GPIO_LINE_A(3)
|
||||
#define EP93XX_GPIO_LINE_EGPIO4 EP93XX_GPIO_LINE_A(4)
|
||||
#define EP93XX_GPIO_LINE_EGPIO5 EP93XX_GPIO_LINE_A(5)
|
||||
#define EP93XX_GPIO_LINE_EGPIO6 EP93XX_GPIO_LINE_A(6)
|
||||
#define EP93XX_GPIO_LINE_EGPIO7 EP93XX_GPIO_LINE_A(7)
|
||||
|
||||
/* GPIO port B. */
|
||||
#define EP93XX_GPIO_LINE_B(x) ((x) + 8)
|
||||
#define EP93XX_GPIO_LINE_EGPIO8 EP93XX_GPIO_LINE_B(0)
|
||||
#define EP93XX_GPIO_LINE_EGPIO9 EP93XX_GPIO_LINE_B(1)
|
||||
#define EP93XX_GPIO_LINE_EGPIO10 EP93XX_GPIO_LINE_B(2)
|
||||
#define EP93XX_GPIO_LINE_EGPIO11 EP93XX_GPIO_LINE_B(3)
|
||||
#define EP93XX_GPIO_LINE_EGPIO12 EP93XX_GPIO_LINE_B(4)
|
||||
#define EP93XX_GPIO_LINE_EGPIO13 EP93XX_GPIO_LINE_B(5)
|
||||
#define EP93XX_GPIO_LINE_EGPIO14 EP93XX_GPIO_LINE_B(6)
|
||||
#define EP93XX_GPIO_LINE_EGPIO15 EP93XX_GPIO_LINE_B(7)
|
||||
|
||||
/* GPIO port C. */
|
||||
#define EP93XX_GPIO_LINE_C(x) ((x) + 40)
|
||||
#define EP93XX_GPIO_LINE_ROW0 EP93XX_GPIO_LINE_C(0)
|
||||
#define EP93XX_GPIO_LINE_ROW1 EP93XX_GPIO_LINE_C(1)
|
||||
#define EP93XX_GPIO_LINE_ROW2 EP93XX_GPIO_LINE_C(2)
|
||||
#define EP93XX_GPIO_LINE_ROW3 EP93XX_GPIO_LINE_C(3)
|
||||
#define EP93XX_GPIO_LINE_ROW4 EP93XX_GPIO_LINE_C(4)
|
||||
#define EP93XX_GPIO_LINE_ROW5 EP93XX_GPIO_LINE_C(5)
|
||||
#define EP93XX_GPIO_LINE_ROW6 EP93XX_GPIO_LINE_C(6)
|
||||
#define EP93XX_GPIO_LINE_ROW7 EP93XX_GPIO_LINE_C(7)
|
||||
|
||||
/* GPIO port D. */
|
||||
#define EP93XX_GPIO_LINE_D(x) ((x) + 24)
|
||||
#define EP93XX_GPIO_LINE_COL0 EP93XX_GPIO_LINE_D(0)
|
||||
#define EP93XX_GPIO_LINE_COL1 EP93XX_GPIO_LINE_D(1)
|
||||
#define EP93XX_GPIO_LINE_COL2 EP93XX_GPIO_LINE_D(2)
|
||||
#define EP93XX_GPIO_LINE_COL3 EP93XX_GPIO_LINE_D(3)
|
||||
#define EP93XX_GPIO_LINE_COL4 EP93XX_GPIO_LINE_D(4)
|
||||
#define EP93XX_GPIO_LINE_COL5 EP93XX_GPIO_LINE_D(5)
|
||||
#define EP93XX_GPIO_LINE_COL6 EP93XX_GPIO_LINE_D(6)
|
||||
#define EP93XX_GPIO_LINE_COL7 EP93XX_GPIO_LINE_D(7)
|
||||
|
||||
/* GPIO port E. */
|
||||
#define EP93XX_GPIO_LINE_E(x) ((x) + 32)
|
||||
#define EP93XX_GPIO_LINE_GRLED EP93XX_GPIO_LINE_E(0)
|
||||
#define EP93XX_GPIO_LINE_RDLED EP93XX_GPIO_LINE_E(1)
|
||||
#define EP93XX_GPIO_LINE_DIORn EP93XX_GPIO_LINE_E(2)
|
||||
#define EP93XX_GPIO_LINE_IDECS1n EP93XX_GPIO_LINE_E(3)
|
||||
#define EP93XX_GPIO_LINE_IDECS2n EP93XX_GPIO_LINE_E(4)
|
||||
#define EP93XX_GPIO_LINE_IDEDA0 EP93XX_GPIO_LINE_E(5)
|
||||
#define EP93XX_GPIO_LINE_IDEDA1 EP93XX_GPIO_LINE_E(6)
|
||||
#define EP93XX_GPIO_LINE_IDEDA2 EP93XX_GPIO_LINE_E(7)
|
||||
|
||||
/* GPIO port F. */
|
||||
#define EP93XX_GPIO_LINE_F(x) ((x) + 16)
|
||||
#define EP93XX_GPIO_LINE_WP EP93XX_GPIO_LINE_F(0)
|
||||
#define EP93XX_GPIO_LINE_MCCD1 EP93XX_GPIO_LINE_F(1)
|
||||
#define EP93XX_GPIO_LINE_MCCD2 EP93XX_GPIO_LINE_F(2)
|
||||
#define EP93XX_GPIO_LINE_MCBVD1 EP93XX_GPIO_LINE_F(3)
|
||||
#define EP93XX_GPIO_LINE_MCBVD2 EP93XX_GPIO_LINE_F(4)
|
||||
#define EP93XX_GPIO_LINE_VS1 EP93XX_GPIO_LINE_F(5)
|
||||
#define EP93XX_GPIO_LINE_READY EP93XX_GPIO_LINE_F(6)
|
||||
#define EP93XX_GPIO_LINE_VS2 EP93XX_GPIO_LINE_F(7)
|
||||
|
||||
/* GPIO port G. */
|
||||
#define EP93XX_GPIO_LINE_G(x) ((x) + 48)
|
||||
#define EP93XX_GPIO_LINE_EECLK EP93XX_GPIO_LINE_G(0)
|
||||
#define EP93XX_GPIO_LINE_EEDAT EP93XX_GPIO_LINE_G(1)
|
||||
#define EP93XX_GPIO_LINE_SLA0 EP93XX_GPIO_LINE_G(2)
|
||||
#define EP93XX_GPIO_LINE_SLA1 EP93XX_GPIO_LINE_G(3)
|
||||
#define EP93XX_GPIO_LINE_DD12 EP93XX_GPIO_LINE_G(4)
|
||||
#define EP93XX_GPIO_LINE_DD13 EP93XX_GPIO_LINE_G(5)
|
||||
#define EP93XX_GPIO_LINE_DD14 EP93XX_GPIO_LINE_G(6)
|
||||
#define EP93XX_GPIO_LINE_DD15 EP93XX_GPIO_LINE_G(7)
|
||||
|
||||
/* GPIO port H. */
|
||||
#define EP93XX_GPIO_LINE_H(x) ((x) + 56)
|
||||
#define EP93XX_GPIO_LINE_DD0 EP93XX_GPIO_LINE_H(0)
|
||||
#define EP93XX_GPIO_LINE_DD1 EP93XX_GPIO_LINE_H(1)
|
||||
#define EP93XX_GPIO_LINE_DD2 EP93XX_GPIO_LINE_H(2)
|
||||
#define EP93XX_GPIO_LINE_DD3 EP93XX_GPIO_LINE_H(3)
|
||||
#define EP93XX_GPIO_LINE_DD4 EP93XX_GPIO_LINE_H(4)
|
||||
#define EP93XX_GPIO_LINE_DD5 EP93XX_GPIO_LINE_H(5)
|
||||
#define EP93XX_GPIO_LINE_DD6 EP93XX_GPIO_LINE_H(6)
|
||||
#define EP93XX_GPIO_LINE_DD7 EP93XX_GPIO_LINE_H(7)
|
||||
|
||||
/* maximum value for gpio line identifiers */
|
||||
#define EP93XX_GPIO_LINE_MAX EP93XX_GPIO_LINE_H(7)
|
||||
|
||||
/* maximum value for irq capable line identifiers */
|
||||
#define EP93XX_GPIO_LINE_MAX_IRQ EP93XX_GPIO_LINE_F(7)
|
||||
|
||||
#endif /* __GPIO_EP93XX_H */
|
@ -1,25 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* arch/arm/mach-ep93xx/include/mach/hardware.h
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARCH_HARDWARE_H
|
||||
#define __ASM_ARCH_HARDWARE_H
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
/*
|
||||
* The EP93xx has two external crystal oscillators. To generate the
|
||||
* required high-frequency clocks, the processor uses two phase-locked-
|
||||
* loops (PLLs) to multiply the incoming external clock signal to much
|
||||
* higher frequencies that are then divided down by programmable dividers
|
||||
* to produce the needed clocks. The PLLs operate independently of one
|
||||
* another.
|
||||
*/
|
||||
#define EP93XX_EXT_CLK_RATE 14745600
|
||||
#define EP93XX_EXT_RTC_RATE 32768
|
||||
|
||||
#define EP93XX_KEYTCHCLK_DIV4 (EP93XX_EXT_CLK_RATE / 4)
|
||||
#define EP93XX_KEYTCHCLK_DIV16 (EP93XX_EXT_CLK_RATE / 16)
|
||||
|
||||
#endif
|
@ -1,76 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __ASM_ARCH_IRQS_H
|
||||
#define __ASM_ARCH_IRQS_H
|
||||
|
||||
#define IRQ_EP93XX_VIC0 1
|
||||
|
||||
#define IRQ_EP93XX_COMMRX (IRQ_EP93XX_VIC0 + 2)
|
||||
#define IRQ_EP93XX_COMMTX (IRQ_EP93XX_VIC0 + 3)
|
||||
#define IRQ_EP93XX_TIMER1 (IRQ_EP93XX_VIC0 + 4)
|
||||
#define IRQ_EP93XX_TIMER2 (IRQ_EP93XX_VIC0 + 5)
|
||||
#define IRQ_EP93XX_AACINTR (IRQ_EP93XX_VIC0 + 6)
|
||||
#define IRQ_EP93XX_DMAM2P0 (IRQ_EP93XX_VIC0 + 7)
|
||||
#define IRQ_EP93XX_DMAM2P1 (IRQ_EP93XX_VIC0 + 8)
|
||||
#define IRQ_EP93XX_DMAM2P2 (IRQ_EP93XX_VIC0 + 9)
|
||||
#define IRQ_EP93XX_DMAM2P3 (IRQ_EP93XX_VIC0 + 10)
|
||||
#define IRQ_EP93XX_DMAM2P4 (IRQ_EP93XX_VIC0 + 11)
|
||||
#define IRQ_EP93XX_DMAM2P5 (IRQ_EP93XX_VIC0 + 12)
|
||||
#define IRQ_EP93XX_DMAM2P6 (IRQ_EP93XX_VIC0 + 13)
|
||||
#define IRQ_EP93XX_DMAM2P7 (IRQ_EP93XX_VIC0 + 14)
|
||||
#define IRQ_EP93XX_DMAM2P8 (IRQ_EP93XX_VIC0 + 15)
|
||||
#define IRQ_EP93XX_DMAM2P9 (IRQ_EP93XX_VIC0 + 16)
|
||||
#define IRQ_EP93XX_DMAM2M0 (IRQ_EP93XX_VIC0 + 17)
|
||||
#define IRQ_EP93XX_DMAM2M1 (IRQ_EP93XX_VIC0 + 18)
|
||||
#define IRQ_EP93XX_GPIO0MUX (IRQ_EP93XX_VIC0 + 19)
|
||||
#define IRQ_EP93XX_GPIO1MUX (IRQ_EP93XX_VIC0 + 20)
|
||||
#define IRQ_EP93XX_GPIO2MUX (IRQ_EP93XX_VIC0 + 21)
|
||||
#define IRQ_EP93XX_GPIO3MUX (IRQ_EP93XX_VIC0 + 22)
|
||||
#define IRQ_EP93XX_UART1RX (IRQ_EP93XX_VIC0 + 23)
|
||||
#define IRQ_EP93XX_UART1TX (IRQ_EP93XX_VIC0 + 24)
|
||||
#define IRQ_EP93XX_UART2RX (IRQ_EP93XX_VIC0 + 25)
|
||||
#define IRQ_EP93XX_UART2TX (IRQ_EP93XX_VIC0 + 26)
|
||||
#define IRQ_EP93XX_UART3RX (IRQ_EP93XX_VIC0 + 27)
|
||||
#define IRQ_EP93XX_UART3TX (IRQ_EP93XX_VIC0 + 28)
|
||||
#define IRQ_EP93XX_KEY (IRQ_EP93XX_VIC0 + 29)
|
||||
#define IRQ_EP93XX_TOUCH (IRQ_EP93XX_VIC0 + 30)
|
||||
#define EP93XX_VIC1_VALID_IRQ_MASK 0x7ffffffc
|
||||
|
||||
#define IRQ_EP93XX_VIC1 (IRQ_EP93XX_VIC0 + 32)
|
||||
|
||||
#define IRQ_EP93XX_EXT0 (IRQ_EP93XX_VIC1 + 0)
|
||||
#define IRQ_EP93XX_EXT1 (IRQ_EP93XX_VIC1 + 1)
|
||||
#define IRQ_EP93XX_EXT2 (IRQ_EP93XX_VIC1 + 2)
|
||||
#define IRQ_EP93XX_64HZ (IRQ_EP93XX_VIC1 + 3)
|
||||
#define IRQ_EP93XX_WATCHDOG (IRQ_EP93XX_VIC1 + 4)
|
||||
#define IRQ_EP93XX_RTC (IRQ_EP93XX_VIC1 + 5)
|
||||
#define IRQ_EP93XX_IRDA (IRQ_EP93XX_VIC1 + 6)
|
||||
#define IRQ_EP93XX_ETHERNET (IRQ_EP93XX_VIC1 + 7)
|
||||
#define IRQ_EP93XX_EXT3 (IRQ_EP93XX_VIC1 + 8)
|
||||
#define IRQ_EP93XX_PROG (IRQ_EP93XX_VIC1 + 9)
|
||||
#define IRQ_EP93XX_1HZ (IRQ_EP93XX_VIC1 + 10)
|
||||
#define IRQ_EP93XX_VSYNC (IRQ_EP93XX_VIC1 + 11)
|
||||
#define IRQ_EP93XX_VIDEO_FIFO (IRQ_EP93XX_VIC1 + 12)
|
||||
#define IRQ_EP93XX_SSP1RX (IRQ_EP93XX_VIC1 + 13)
|
||||
#define IRQ_EP93XX_SSP1TX (IRQ_EP93XX_VIC1 + 14)
|
||||
#define IRQ_EP93XX_GPIO4MUX (IRQ_EP93XX_VIC1 + 15)
|
||||
#define IRQ_EP93XX_GPIO5MUX (IRQ_EP93XX_VIC1 + 16)
|
||||
#define IRQ_EP93XX_GPIO6MUX (IRQ_EP93XX_VIC1 + 17)
|
||||
#define IRQ_EP93XX_GPIO7MUX (IRQ_EP93XX_VIC1 + 18)
|
||||
#define IRQ_EP93XX_TIMER3 (IRQ_EP93XX_VIC1 + 19)
|
||||
#define IRQ_EP93XX_UART1 (IRQ_EP93XX_VIC1 + 20)
|
||||
#define IRQ_EP93XX_SSP (IRQ_EP93XX_VIC1 + 21)
|
||||
#define IRQ_EP93XX_UART2 (IRQ_EP93XX_VIC1 + 22)
|
||||
#define IRQ_EP93XX_UART3 (IRQ_EP93XX_VIC1 + 23)
|
||||
#define IRQ_EP93XX_USB (IRQ_EP93XX_VIC1 + 24)
|
||||
#define IRQ_EP93XX_ETHERNET_PME (IRQ_EP93XX_VIC1 + 25)
|
||||
#define IRQ_EP93XX_DSP (IRQ_EP93XX_VIC1 + 26)
|
||||
#define IRQ_EP93XX_GPIO_AB (IRQ_EP93XX_VIC1 + 27)
|
||||
#define IRQ_EP93XX_SAI (IRQ_EP93XX_VIC1 + 28)
|
||||
#define EP93XX_VIC2_VALID_IRQ_MASK 0x1fffffff
|
||||
|
||||
#define NR_EP93XX_IRQS (IRQ_EP93XX_VIC1 + 32 + 24)
|
||||
|
||||
#define EP93XX_BOARD_IRQ(x) (NR_EP93XX_IRQS + (x))
|
||||
#define EP93XX_BOARD_IRQS 32
|
||||
|
||||
#endif
|
@ -1,42 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* arch/arm/mach-ep93xx/include/mach/platform.h
|
||||
*/
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/platform_data/eth-ep93xx.h>
|
||||
#include <linux/reboot.h>
|
||||
|
||||
struct device;
|
||||
struct i2c_board_info;
|
||||
struct spi_board_info;
|
||||
struct platform_device;
|
||||
struct ep93xxfb_mach_info;
|
||||
struct ep93xx_keypad_platform_data;
|
||||
struct ep93xx_spi_info;
|
||||
|
||||
void ep93xx_map_io(void);
|
||||
void ep93xx_init_irq(void);
|
||||
|
||||
void ep93xx_register_flash(unsigned int width,
|
||||
resource_size_t start, resource_size_t size);
|
||||
|
||||
void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
|
||||
void ep93xx_register_i2c(struct i2c_board_info *devices, int num);
|
||||
void ep93xx_register_spi(struct ep93xx_spi_info *info,
|
||||
struct spi_board_info *devices, int num);
|
||||
void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
|
||||
void ep93xx_register_pwm(int pwm0, int pwm1);
|
||||
void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
|
||||
void ep93xx_register_i2s(void);
|
||||
void ep93xx_register_ac97(void);
|
||||
void ep93xx_register_ide(void);
|
||||
void ep93xx_register_adc(void);
|
||||
|
||||
struct device *ep93xx_init_devices(void);
|
||||
extern void ep93xx_timer_init(void);
|
||||
|
||||
void ep93xx_restart(enum reboot_mode, const char *);
|
||||
|
||||
#endif
|
@ -1,212 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* arch/arm/mach-ep93xx/soc.h
|
||||
*
|
||||
* Copyright (C) 2012 Open Kernel Labs <www.ok-labs.com>
|
||||
* Copyright (C) 2012 Ryan Mallon <rmallon@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _EP93XX_SOC_H
|
||||
#define _EP93XX_SOC_H
|
||||
|
||||
#include "ep93xx-regs.h"
|
||||
#include "irqs.h"
|
||||
|
||||
/*
|
||||
* EP93xx Physical Memory Map:
|
||||
*
|
||||
* The ASDO pin is sampled at system reset to select a synchronous or
|
||||
* asynchronous boot configuration. When ASDO is "1" (i.e. pulled-up)
|
||||
* the synchronous boot mode is selected. When ASDO is "0" (i.e
|
||||
* pulled-down) the asynchronous boot mode is selected.
|
||||
*
|
||||
* In synchronous boot mode nSDCE3 is decoded starting at physical address
|
||||
* 0x00000000 and nCS0 is decoded starting at 0xf0000000. For asynchronous
|
||||
* boot mode they are swapped with nCS0 decoded at 0x00000000 ann nSDCE3
|
||||
* decoded at 0xf0000000.
|
||||
*
|
||||
* There is known errata for the EP93xx dealing with External Memory
|
||||
* Configurations. Please refer to "AN273: EP93xx Silicon Rev E Design
|
||||
* Guidelines" for more information. This document can be found at:
|
||||
*
|
||||
* http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
|
||||
*/
|
||||
|
||||
#define EP93XX_CS0_PHYS_BASE_ASYNC 0x00000000 /* ASDO Pin = 0 */
|
||||
#define EP93XX_SDCE3_PHYS_BASE_SYNC 0x00000000 /* ASDO Pin = 1 */
|
||||
#define EP93XX_CS1_PHYS_BASE 0x10000000
|
||||
#define EP93XX_CS2_PHYS_BASE 0x20000000
|
||||
#define EP93XX_CS3_PHYS_BASE 0x30000000
|
||||
#define EP93XX_PCMCIA_PHYS_BASE 0x40000000
|
||||
#define EP93XX_CS6_PHYS_BASE 0x60000000
|
||||
#define EP93XX_CS7_PHYS_BASE 0x70000000
|
||||
#define EP93XX_SDCE0_PHYS_BASE 0xc0000000
|
||||
#define EP93XX_SDCE1_PHYS_BASE 0xd0000000
|
||||
#define EP93XX_SDCE2_PHYS_BASE 0xe0000000
|
||||
#define EP93XX_SDCE3_PHYS_BASE_ASYNC 0xf0000000 /* ASDO Pin = 0 */
|
||||
#define EP93XX_CS0_PHYS_BASE_SYNC 0xf0000000 /* ASDO Pin = 1 */
|
||||
|
||||
/* AHB peripherals */
|
||||
#define EP93XX_DMA_BASE EP93XX_AHB_IOMEM(0x00000000)
|
||||
|
||||
#define EP93XX_ETHERNET_PHYS_BASE EP93XX_AHB_PHYS(0x00010000)
|
||||
#define EP93XX_ETHERNET_BASE EP93XX_AHB_IOMEM(0x00010000)
|
||||
|
||||
#define EP93XX_USB_PHYS_BASE EP93XX_AHB_PHYS(0x00020000)
|
||||
#define EP93XX_USB_BASE EP93XX_AHB_IOMEM(0x00020000)
|
||||
|
||||
#define EP93XX_RASTER_PHYS_BASE EP93XX_AHB_PHYS(0x00030000)
|
||||
#define EP93XX_RASTER_BASE EP93XX_AHB_IOMEM(0x00030000)
|
||||
|
||||
#define EP93XX_GRAPHICS_ACCEL_BASE EP93XX_AHB_IOMEM(0x00040000)
|
||||
|
||||
#define EP93XX_SDRAM_CONTROLLER_BASE EP93XX_AHB_IOMEM(0x00060000)
|
||||
|
||||
#define EP93XX_PCMCIA_CONTROLLER_BASE EP93XX_AHB_IOMEM(0x00080000)
|
||||
|
||||
#define EP93XX_BOOT_ROM_BASE EP93XX_AHB_IOMEM(0x00090000)
|
||||
|
||||
#define EP93XX_IDE_PHYS_BASE EP93XX_AHB_PHYS(0x000a0000)
|
||||
#define EP93XX_IDE_BASE EP93XX_AHB_IOMEM(0x000a0000)
|
||||
|
||||
#define EP93XX_VIC1_BASE EP93XX_AHB_IOMEM(0x000b0000)
|
||||
|
||||
#define EP93XX_VIC2_BASE EP93XX_AHB_IOMEM(0x000c0000)
|
||||
|
||||
/* APB peripherals */
|
||||
#define EP93XX_TIMER_BASE EP93XX_APB_IOMEM(0x00010000)
|
||||
|
||||
#define EP93XX_I2S_PHYS_BASE EP93XX_APB_PHYS(0x00020000)
|
||||
#define EP93XX_I2S_BASE EP93XX_APB_IOMEM(0x00020000)
|
||||
|
||||
#define EP93XX_SECURITY_BASE EP93XX_APB_IOMEM(0x00030000)
|
||||
|
||||
#define EP93XX_AAC_PHYS_BASE EP93XX_APB_PHYS(0x00080000)
|
||||
#define EP93XX_AAC_BASE EP93XX_APB_IOMEM(0x00080000)
|
||||
|
||||
#define EP93XX_SPI_PHYS_BASE EP93XX_APB_PHYS(0x000a0000)
|
||||
#define EP93XX_SPI_BASE EP93XX_APB_IOMEM(0x000a0000)
|
||||
|
||||
#define EP93XX_IRDA_BASE EP93XX_APB_IOMEM(0x000b0000)
|
||||
|
||||
#define EP93XX_KEY_MATRIX_PHYS_BASE EP93XX_APB_PHYS(0x000f0000)
|
||||
#define EP93XX_KEY_MATRIX_BASE EP93XX_APB_IOMEM(0x000f0000)
|
||||
|
||||
#define EP93XX_ADC_PHYS_BASE EP93XX_APB_PHYS(0x00100000)
|
||||
#define EP93XX_ADC_BASE EP93XX_APB_IOMEM(0x00100000)
|
||||
#define EP93XX_TOUCHSCREEN_BASE EP93XX_APB_IOMEM(0x00100000)
|
||||
|
||||
#define EP93XX_PWM_PHYS_BASE EP93XX_APB_PHYS(0x00110000)
|
||||
#define EP93XX_PWM_BASE EP93XX_APB_IOMEM(0x00110000)
|
||||
|
||||
#define EP93XX_RTC_PHYS_BASE EP93XX_APB_PHYS(0x00120000)
|
||||
#define EP93XX_RTC_BASE EP93XX_APB_IOMEM(0x00120000)
|
||||
|
||||
#define EP93XX_WATCHDOG_PHYS_BASE EP93XX_APB_PHYS(0x00140000)
|
||||
#define EP93XX_WATCHDOG_BASE EP93XX_APB_IOMEM(0x00140000)
|
||||
|
||||
/* System controller */
|
||||
#define EP93XX_SYSCON_BASE EP93XX_APB_IOMEM(0x00130000)
|
||||
#define EP93XX_SYSCON_REG(x) (EP93XX_SYSCON_BASE + (x))
|
||||
#define EP93XX_SYSCON_POWER_STATE EP93XX_SYSCON_REG(0x00)
|
||||
#define EP93XX_SYSCON_PWRCNT EP93XX_SYSCON_REG(0x04)
|
||||
#define EP93XX_SYSCON_PWRCNT_FIR_EN (1<<31)
|
||||
#define EP93XX_SYSCON_PWRCNT_UARTBAUD (1<<29)
|
||||
#define EP93XX_SYSCON_PWRCNT_USH_EN 28
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 27
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 26
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 25
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 24
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 23
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 22
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 21
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 20
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 19
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 18
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 17
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 16
|
||||
#define EP93XX_SYSCON_HALT EP93XX_SYSCON_REG(0x08)
|
||||
#define EP93XX_SYSCON_STANDBY EP93XX_SYSCON_REG(0x0c)
|
||||
#define EP93XX_SYSCON_CLKSET1 EP93XX_SYSCON_REG(0x20)
|
||||
#define EP93XX_SYSCON_CLKSET1_NBYP1 (1<<23)
|
||||
#define EP93XX_SYSCON_CLKSET2 EP93XX_SYSCON_REG(0x24)
|
||||
#define EP93XX_SYSCON_CLKSET2_NBYP2 (1<<19)
|
||||
#define EP93XX_SYSCON_CLKSET2_PLL2_EN (1<<18)
|
||||
#define EP93XX_SYSCON_DEVCFG EP93XX_SYSCON_REG(0x80)
|
||||
#define EP93XX_SYSCON_DEVCFG_SWRST (1<<31)
|
||||
#define EP93XX_SYSCON_DEVCFG_D1ONG (1<<30)
|
||||
#define EP93XX_SYSCON_DEVCFG_D0ONG (1<<29)
|
||||
#define EP93XX_SYSCON_DEVCFG_IONU2 (1<<28)
|
||||
#define EP93XX_SYSCON_DEVCFG_GONK (1<<27)
|
||||
#define EP93XX_SYSCON_DEVCFG_TONG (1<<26)
|
||||
#define EP93XX_SYSCON_DEVCFG_MONG (1<<25)
|
||||
#define EP93XX_SYSCON_DEVCFG_U3EN 24
|
||||
#define EP93XX_SYSCON_DEVCFG_CPENA (1<<23)
|
||||
#define EP93XX_SYSCON_DEVCFG_A2ONG (1<<22)
|
||||
#define EP93XX_SYSCON_DEVCFG_A1ONG (1<<21)
|
||||
#define EP93XX_SYSCON_DEVCFG_U2EN 20
|
||||
#define EP93XX_SYSCON_DEVCFG_EXVC (1<<19)
|
||||
#define EP93XX_SYSCON_DEVCFG_U1EN 18
|
||||
#define EP93XX_SYSCON_DEVCFG_TIN (1<<17)
|
||||
#define EP93XX_SYSCON_DEVCFG_HC3IN (1<<15)
|
||||
#define EP93XX_SYSCON_DEVCFG_HC3EN (1<<14)
|
||||
#define EP93XX_SYSCON_DEVCFG_HC1IN (1<<13)
|
||||
#define EP93XX_SYSCON_DEVCFG_HC1EN (1<<12)
|
||||
#define EP93XX_SYSCON_DEVCFG_HONIDE (1<<11)
|
||||
#define EP93XX_SYSCON_DEVCFG_GONIDE (1<<10)
|
||||
#define EP93XX_SYSCON_DEVCFG_PONG (1<<9)
|
||||
#define EP93XX_SYSCON_DEVCFG_EONIDE (1<<8)
|
||||
#define EP93XX_SYSCON_DEVCFG_I2SONSSP (1<<7)
|
||||
#define EP93XX_SYSCON_DEVCFG_I2SONAC97 (1<<6)
|
||||
#define EP93XX_SYSCON_DEVCFG_RASONP3 (1<<4)
|
||||
#define EP93XX_SYSCON_DEVCFG_RAS (1<<3)
|
||||
#define EP93XX_SYSCON_DEVCFG_ADCPD (1<<2)
|
||||
#define EP93XX_SYSCON_DEVCFG_KEYS (1<<1)
|
||||
#define EP93XX_SYSCON_DEVCFG_SHENA (1<<0)
|
||||
#define EP93XX_SYSCON_VIDCLKDIV EP93XX_SYSCON_REG(0x84)
|
||||
#define EP93XX_SYSCON_CLKDIV_ENABLE 15
|
||||
#define EP93XX_SYSCON_CLKDIV_ESEL (1<<14)
|
||||
#define EP93XX_SYSCON_CLKDIV_PSEL (1<<13)
|
||||
#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8
|
||||
#define EP93XX_SYSCON_I2SCLKDIV EP93XX_SYSCON_REG(0x8c)
|
||||
#define EP93XX_SYSCON_I2SCLKDIV_SENA 31
|
||||
#define EP93XX_SYSCON_I2SCLKDIV_ORIDE (1<<29)
|
||||
#define EP93XX_SYSCON_I2SCLKDIV_SPOL (1<<19)
|
||||
#define EP93XX_I2SCLKDIV_SDIV (1 << 16)
|
||||
#define EP93XX_I2SCLKDIV_LRDIV32 (0 << 17)
|
||||
#define EP93XX_I2SCLKDIV_LRDIV64 (1 << 17)
|
||||
#define EP93XX_I2SCLKDIV_LRDIV128 (2 << 17)
|
||||
#define EP93XX_I2SCLKDIV_LRDIV_MASK (3 << 17)
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV EP93XX_SYSCON_REG(0x90)
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN 31
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV 16
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN 15
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV (1<<0)
|
||||
#define EP93XX_SYSCON_SYSCFG EP93XX_SYSCON_REG(0x9c)
|
||||
#define EP93XX_SYSCON_SYSCFG_REV_MASK (0xf0000000)
|
||||
#define EP93XX_SYSCON_SYSCFG_REV_SHIFT (28)
|
||||
#define EP93XX_SYSCON_SYSCFG_SBOOT (1<<8)
|
||||
#define EP93XX_SYSCON_SYSCFG_LCSN7 (1<<7)
|
||||
#define EP93XX_SYSCON_SYSCFG_LCSN6 (1<<6)
|
||||
#define EP93XX_SYSCON_SYSCFG_LASDO (1<<5)
|
||||
#define EP93XX_SYSCON_SYSCFG_LEEDA (1<<4)
|
||||
#define EP93XX_SYSCON_SYSCFG_LEECLK (1<<3)
|
||||
#define EP93XX_SYSCON_SYSCFG_LCSN2 (1<<1)
|
||||
#define EP93XX_SYSCON_SYSCFG_LCSN1 (1<<0)
|
||||
#define EP93XX_SYSCON_SWLOCK EP93XX_SYSCON_REG(0xc0)
|
||||
|
||||
/* EP93xx System Controller software locked register write */
|
||||
void ep93xx_syscon_swlocked_write(unsigned int val, void __iomem *reg);
|
||||
void ep93xx_devcfg_set_clear(unsigned int set_bits, unsigned int clear_bits);
|
||||
|
||||
static inline void ep93xx_devcfg_set_bits(unsigned int bits)
|
||||
{
|
||||
ep93xx_devcfg_set_clear(bits, 0x00);
|
||||
}
|
||||
|
||||
static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
|
||||
{
|
||||
ep93xx_devcfg_set_clear(0x00, bits);
|
||||
}
|
||||
|
||||
#endif /* _EP93XX_SOC_H */
|
@ -1,143 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/sched_clock.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/mach/time.h>
|
||||
#include "soc.h"
|
||||
#include "platform.h"
|
||||
|
||||
/*************************************************************************
|
||||
* Timer handling for EP93xx
|
||||
*************************************************************************
|
||||
* The ep93xx has four internal timers. Timers 1, 2 (both 16 bit) and
|
||||
* 3 (32 bit) count down at 508 kHz, are self-reloading, and can generate
|
||||
* an interrupt on underflow. Timer 4 (40 bit) counts down at 983.04 kHz,
|
||||
* is free-running, and can't generate interrupts.
|
||||
*
|
||||
* The 508 kHz timers are ideal for use for the timer interrupt, as the
|
||||
* most common values of HZ divide 508 kHz nicely. We pick the 32 bit
|
||||
* timer (timer 3) to get as long sleep intervals as possible when using
|
||||
* CONFIG_NO_HZ.
|
||||
*
|
||||
* The higher clock rate of timer 4 makes it a better choice than the
|
||||
* other timers for use as clock source and for sched_clock(), providing
|
||||
* a stable 40 bit time base.
|
||||
*************************************************************************
|
||||
*/
|
||||
#define EP93XX_TIMER_REG(x) (EP93XX_TIMER_BASE + (x))
|
||||
#define EP93XX_TIMER1_LOAD EP93XX_TIMER_REG(0x00)
|
||||
#define EP93XX_TIMER1_VALUE EP93XX_TIMER_REG(0x04)
|
||||
#define EP93XX_TIMER1_CONTROL EP93XX_TIMER_REG(0x08)
|
||||
#define EP93XX_TIMER123_CONTROL_ENABLE (1 << 7)
|
||||
#define EP93XX_TIMER123_CONTROL_MODE (1 << 6)
|
||||
#define EP93XX_TIMER123_CONTROL_CLKSEL (1 << 3)
|
||||
#define EP93XX_TIMER1_CLEAR EP93XX_TIMER_REG(0x0c)
|
||||
#define EP93XX_TIMER2_LOAD EP93XX_TIMER_REG(0x20)
|
||||
#define EP93XX_TIMER2_VALUE EP93XX_TIMER_REG(0x24)
|
||||
#define EP93XX_TIMER2_CONTROL EP93XX_TIMER_REG(0x28)
|
||||
#define EP93XX_TIMER2_CLEAR EP93XX_TIMER_REG(0x2c)
|
||||
#define EP93XX_TIMER4_VALUE_LOW EP93XX_TIMER_REG(0x60)
|
||||
#define EP93XX_TIMER4_VALUE_HIGH EP93XX_TIMER_REG(0x64)
|
||||
#define EP93XX_TIMER4_VALUE_HIGH_ENABLE (1 << 8)
|
||||
#define EP93XX_TIMER3_LOAD EP93XX_TIMER_REG(0x80)
|
||||
#define EP93XX_TIMER3_VALUE EP93XX_TIMER_REG(0x84)
|
||||
#define EP93XX_TIMER3_CONTROL EP93XX_TIMER_REG(0x88)
|
||||
#define EP93XX_TIMER3_CLEAR EP93XX_TIMER_REG(0x8c)
|
||||
|
||||
#define EP93XX_TIMER123_RATE 508469
|
||||
#define EP93XX_TIMER4_RATE 983040
|
||||
|
||||
static u64 notrace ep93xx_read_sched_clock(void)
|
||||
{
|
||||
u64 ret;
|
||||
|
||||
ret = readl(EP93XX_TIMER4_VALUE_LOW);
|
||||
ret |= ((u64) (readl(EP93XX_TIMER4_VALUE_HIGH) & 0xff) << 32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u64 ep93xx_clocksource_read(struct clocksource *c)
|
||||
{
|
||||
u64 ret;
|
||||
|
||||
ret = readl(EP93XX_TIMER4_VALUE_LOW);
|
||||
ret |= ((u64) (readl(EP93XX_TIMER4_VALUE_HIGH) & 0xff) << 32);
|
||||
return (u64) ret;
|
||||
}
|
||||
|
||||
static int ep93xx_clkevt_set_next_event(unsigned long next,
|
||||
struct clock_event_device *evt)
|
||||
{
|
||||
/* Default mode: periodic, off, 508 kHz */
|
||||
u32 tmode = EP93XX_TIMER123_CONTROL_MODE |
|
||||
EP93XX_TIMER123_CONTROL_CLKSEL;
|
||||
|
||||
/* Clear timer */
|
||||
writel(tmode, EP93XX_TIMER3_CONTROL);
|
||||
|
||||
/* Set next event */
|
||||
writel(next, EP93XX_TIMER3_LOAD);
|
||||
writel(tmode | EP93XX_TIMER123_CONTROL_ENABLE,
|
||||
EP93XX_TIMER3_CONTROL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int ep93xx_clkevt_shutdown(struct clock_event_device *evt)
|
||||
{
|
||||
/* Disable timer */
|
||||
writel(0, EP93XX_TIMER3_CONTROL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clock_event_device ep93xx_clockevent = {
|
||||
.name = "timer1",
|
||||
.features = CLOCK_EVT_FEAT_ONESHOT,
|
||||
.set_state_shutdown = ep93xx_clkevt_shutdown,
|
||||
.set_state_oneshot = ep93xx_clkevt_shutdown,
|
||||
.tick_resume = ep93xx_clkevt_shutdown,
|
||||
.set_next_event = ep93xx_clkevt_set_next_event,
|
||||
.rating = 300,
|
||||
};
|
||||
|
||||
static irqreturn_t ep93xx_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct clock_event_device *evt = dev_id;
|
||||
|
||||
/* Writing any value clears the timer interrupt */
|
||||
writel(1, EP93XX_TIMER3_CLEAR);
|
||||
|
||||
evt->event_handler(evt);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void __init ep93xx_timer_init(void)
|
||||
{
|
||||
int irq = IRQ_EP93XX_TIMER3;
|
||||
unsigned long flags = IRQF_TIMER | IRQF_IRQPOLL;
|
||||
|
||||
/* Enable and register clocksource and sched_clock on timer 4 */
|
||||
writel(EP93XX_TIMER4_VALUE_HIGH_ENABLE,
|
||||
EP93XX_TIMER4_VALUE_HIGH);
|
||||
clocksource_mmio_init(NULL, "timer4",
|
||||
EP93XX_TIMER4_RATE, 200, 40,
|
||||
ep93xx_clocksource_read);
|
||||
sched_clock_register(ep93xx_read_sched_clock, 40,
|
||||
EP93XX_TIMER4_RATE);
|
||||
|
||||
/* Set up clockevent on timer 3 */
|
||||
if (request_irq(irq, ep93xx_timer_interrupt, flags, "ep93xx timer",
|
||||
&ep93xx_clockevent))
|
||||
pr_err("Failed to request irq %d (ep93xx timer)\n", irq);
|
||||
clockevents_config_and_register(&ep93xx_clockevent,
|
||||
EP93XX_TIMER123_RATE,
|
||||
1,
|
||||
0xffffffffU);
|
||||
}
|
@ -1,422 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* arch/arm/mach-ep93xx/ts72xx.c
|
||||
* Technologic Systems TS72xx SBC support.
|
||||
*
|
||||
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <linux/spi/mmc_spi.h>
|
||||
#include <linux/mmc/host.h>
|
||||
#include <linux/platform_data/spi-ep93xx.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
|
||||
#include "gpio-ep93xx.h"
|
||||
#include "hardware.h"
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
#include "soc.h"
|
||||
#include "ts72xx.h"
|
||||
|
||||
/*************************************************************************
|
||||
* IO map
|
||||
*************************************************************************/
|
||||
static struct map_desc ts72xx_io_desc[] __initdata = {
|
||||
{
|
||||
.virtual = (unsigned long)TS72XX_MODEL_VIRT_BASE,
|
||||
.pfn = __phys_to_pfn(TS72XX_MODEL_PHYS_BASE),
|
||||
.length = TS72XX_MODEL_SIZE,
|
||||
.type = MT_DEVICE,
|
||||
}, {
|
||||
.virtual = (unsigned long)TS72XX_OPTIONS_VIRT_BASE,
|
||||
.pfn = __phys_to_pfn(TS72XX_OPTIONS_PHYS_BASE),
|
||||
.length = TS72XX_OPTIONS_SIZE,
|
||||
.type = MT_DEVICE,
|
||||
}, {
|
||||
.virtual = (unsigned long)TS72XX_OPTIONS2_VIRT_BASE,
|
||||
.pfn = __phys_to_pfn(TS72XX_OPTIONS2_PHYS_BASE),
|
||||
.length = TS72XX_OPTIONS2_SIZE,
|
||||
.type = MT_DEVICE,
|
||||
}, {
|
||||
.virtual = (unsigned long)TS72XX_CPLDVER_VIRT_BASE,
|
||||
.pfn = __phys_to_pfn(TS72XX_CPLDVER_PHYS_BASE),
|
||||
.length = TS72XX_CPLDVER_SIZE,
|
||||
.type = MT_DEVICE,
|
||||
}
|
||||
};
|
||||
|
||||
static void __init ts72xx_map_io(void)
|
||||
{
|
||||
ep93xx_map_io();
|
||||
iotable_init(ts72xx_io_desc, ARRAY_SIZE(ts72xx_io_desc));
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* NAND flash
|
||||
*************************************************************************/
|
||||
#define TS72XX_NAND_CONTROL_ADDR_LINE 22 /* 0xN0400000 */
|
||||
#define TS72XX_NAND_BUSY_ADDR_LINE 23 /* 0xN0800000 */
|
||||
|
||||
static void ts72xx_nand_hwcontrol(struct nand_chip *chip,
|
||||
int cmd, unsigned int ctrl)
|
||||
{
|
||||
if (ctrl & NAND_CTRL_CHANGE) {
|
||||
void __iomem *addr = chip->legacy.IO_ADDR_R;
|
||||
unsigned char bits;
|
||||
|
||||
addr += (1 << TS72XX_NAND_CONTROL_ADDR_LINE);
|
||||
|
||||
bits = __raw_readb(addr) & ~0x07;
|
||||
bits |= (ctrl & NAND_NCE) << 2; /* bit 0 -> bit 2 */
|
||||
bits |= (ctrl & NAND_CLE); /* bit 1 -> bit 1 */
|
||||
bits |= (ctrl & NAND_ALE) >> 2; /* bit 2 -> bit 0 */
|
||||
|
||||
__raw_writeb(bits, addr);
|
||||
}
|
||||
|
||||
if (cmd != NAND_CMD_NONE)
|
||||
__raw_writeb(cmd, chip->legacy.IO_ADDR_W);
|
||||
}
|
||||
|
||||
static int ts72xx_nand_device_ready(struct nand_chip *chip)
|
||||
{
|
||||
void __iomem *addr = chip->legacy.IO_ADDR_R;
|
||||
|
||||
addr += (1 << TS72XX_NAND_BUSY_ADDR_LINE);
|
||||
|
||||
return !!(__raw_readb(addr) & 0x20);
|
||||
}
|
||||
|
||||
#define TS72XX_BOOTROM_PART_SIZE (SZ_16K)
|
||||
#define TS72XX_REDBOOT_PART_SIZE (SZ_2M + SZ_1M)
|
||||
|
||||
static struct mtd_partition ts72xx_nand_parts[] = {
|
||||
{
|
||||
.name = "TS-BOOTROM",
|
||||
.offset = 0,
|
||||
.size = TS72XX_BOOTROM_PART_SIZE,
|
||||
.mask_flags = MTD_WRITEABLE, /* force read-only */
|
||||
}, {
|
||||
.name = "Linux",
|
||||
.offset = MTDPART_OFS_RETAIN,
|
||||
.size = TS72XX_REDBOOT_PART_SIZE,
|
||||
/* leave so much for last partition */
|
||||
}, {
|
||||
.name = "RedBoot",
|
||||
.offset = MTDPART_OFS_APPEND,
|
||||
.size = MTDPART_SIZ_FULL,
|
||||
.mask_flags = MTD_WRITEABLE, /* force read-only */
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_nand_data ts72xx_nand_data = {
|
||||
.chip = {
|
||||
.nr_chips = 1,
|
||||
.chip_offset = 0,
|
||||
.chip_delay = 15,
|
||||
},
|
||||
.ctrl = {
|
||||
.cmd_ctrl = ts72xx_nand_hwcontrol,
|
||||
.dev_ready = ts72xx_nand_device_ready,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource ts72xx_nand_resource[] = {
|
||||
{
|
||||
.start = 0, /* filled in later */
|
||||
.end = 0, /* filled in later */
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device ts72xx_nand_flash = {
|
||||
.name = "gen_nand",
|
||||
.id = -1,
|
||||
.dev.platform_data = &ts72xx_nand_data,
|
||||
.resource = ts72xx_nand_resource,
|
||||
.num_resources = ARRAY_SIZE(ts72xx_nand_resource),
|
||||
};
|
||||
|
||||
static void __init ts72xx_register_flash(struct mtd_partition *parts, int n,
|
||||
resource_size_t start)
|
||||
{
|
||||
/*
|
||||
* TS7200 has NOR flash all other TS72xx board have NAND flash.
|
||||
*/
|
||||
if (board_is_ts7200()) {
|
||||
ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_16M);
|
||||
} else {
|
||||
ts72xx_nand_resource[0].start = start;
|
||||
ts72xx_nand_resource[0].end = start + SZ_16M - 1;
|
||||
|
||||
ts72xx_nand_data.chip.partitions = parts;
|
||||
ts72xx_nand_data.chip.nr_partitions = n;
|
||||
|
||||
platform_device_register(&ts72xx_nand_flash);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* RTC M48T86
|
||||
*************************************************************************/
|
||||
#define TS72XX_RTC_INDEX_PHYS_BASE (EP93XX_CS1_PHYS_BASE + 0x00800000)
|
||||
#define TS72XX_RTC_DATA_PHYS_BASE (EP93XX_CS1_PHYS_BASE + 0x01700000)
|
||||
|
||||
static struct resource ts72xx_rtc_resources[] = {
|
||||
DEFINE_RES_MEM(TS72XX_RTC_INDEX_PHYS_BASE, 0x01),
|
||||
DEFINE_RES_MEM(TS72XX_RTC_DATA_PHYS_BASE, 0x01),
|
||||
};
|
||||
|
||||
static struct platform_device ts72xx_rtc_device = {
|
||||
.name = "rtc-m48t86",
|
||||
.id = -1,
|
||||
.resource = ts72xx_rtc_resources,
|
||||
.num_resources = ARRAY_SIZE(ts72xx_rtc_resources),
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* Watchdog (in CPLD)
|
||||
*************************************************************************/
|
||||
#define TS72XX_WDT_CONTROL_PHYS_BASE (EP93XX_CS2_PHYS_BASE + 0x03800000)
|
||||
#define TS72XX_WDT_FEED_PHYS_BASE (EP93XX_CS2_PHYS_BASE + 0x03c00000)
|
||||
|
||||
static struct resource ts72xx_wdt_resources[] = {
|
||||
DEFINE_RES_MEM(TS72XX_WDT_CONTROL_PHYS_BASE, 0x01),
|
||||
DEFINE_RES_MEM(TS72XX_WDT_FEED_PHYS_BASE, 0x01),
|
||||
};
|
||||
|
||||
static struct platform_device ts72xx_wdt_device = {
|
||||
.name = "ts72xx-wdt",
|
||||
.id = -1,
|
||||
.resource = ts72xx_wdt_resources,
|
||||
.num_resources = ARRAY_SIZE(ts72xx_wdt_resources),
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* ETH
|
||||
*************************************************************************/
|
||||
static struct ep93xx_eth_data __initdata ts72xx_eth_data = {
|
||||
.phy_id = 1,
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* SPI SD/MMC host
|
||||
*************************************************************************/
|
||||
#define BK3_EN_SDCARD_PHYS_BASE 0x12400000
|
||||
#define BK3_EN_SDCARD_PWR 0x0
|
||||
#define BK3_DIS_SDCARD_PWR 0x0C
|
||||
static void bk3_mmc_spi_setpower(struct device *dev, unsigned int vdd)
|
||||
{
|
||||
void __iomem *pwr_sd = ioremap(BK3_EN_SDCARD_PHYS_BASE, SZ_4K);
|
||||
|
||||
if (!pwr_sd) {
|
||||
pr_err("Failed to enable SD card power!");
|
||||
return;
|
||||
}
|
||||
|
||||
pr_debug("%s: SD card pwr %s VDD:0x%x\n", __func__,
|
||||
!!vdd ? "ON" : "OFF", vdd);
|
||||
|
||||
if (!!vdd)
|
||||
__raw_writeb(BK3_EN_SDCARD_PWR, pwr_sd);
|
||||
else
|
||||
__raw_writeb(BK3_DIS_SDCARD_PWR, pwr_sd);
|
||||
|
||||
iounmap(pwr_sd);
|
||||
}
|
||||
|
||||
static struct mmc_spi_platform_data bk3_spi_mmc_data = {
|
||||
.detect_delay = 500,
|
||||
.powerup_msecs = 100,
|
||||
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
|
||||
.caps = MMC_CAP_NONREMOVABLE,
|
||||
.setpower = bk3_mmc_spi_setpower,
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* SPI Bus - SD card access
|
||||
*************************************************************************/
|
||||
static struct spi_board_info bk3_spi_board_info[] __initdata = {
|
||||
{
|
||||
.modalias = "mmc_spi",
|
||||
.platform_data = &bk3_spi_mmc_data,
|
||||
.max_speed_hz = 7.4E6,
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
.mode = SPI_MODE_0,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* This is a stub -> the FGPIO[3] pin is not connected on the schematic
|
||||
* The all work is performed automatically by !SPI_FRAME (SFRM1) and
|
||||
* goes through CPLD
|
||||
*/
|
||||
static struct gpiod_lookup_table bk3_spi_cs_gpio_table = {
|
||||
.dev_id = "spi0",
|
||||
.table = {
|
||||
GPIO_LOOKUP("F", 3, "cs", GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static struct ep93xx_spi_info bk3_spi_master __initdata = {
|
||||
.use_dma = 1,
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* TS72XX support code
|
||||
*************************************************************************/
|
||||
#if IS_ENABLED(CONFIG_FPGA_MGR_TS73XX)
|
||||
|
||||
/* Relative to EP93XX_CS1_PHYS_BASE */
|
||||
#define TS73XX_FPGA_LOADER_BASE 0x03c00000
|
||||
|
||||
static struct resource ts73xx_fpga_resources[] = {
|
||||
{
|
||||
.start = EP93XX_CS1_PHYS_BASE + TS73XX_FPGA_LOADER_BASE,
|
||||
.end = EP93XX_CS1_PHYS_BASE + TS73XX_FPGA_LOADER_BASE + 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device ts73xx_fpga_device = {
|
||||
.name = "ts73xx-fpga-mgr",
|
||||
.id = -1,
|
||||
.resource = ts73xx_fpga_resources,
|
||||
.num_resources = ARRAY_SIZE(ts73xx_fpga_resources),
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
* SPI Bus
|
||||
*************************************************************************/
|
||||
static struct spi_board_info ts72xx_spi_devices[] __initdata = {
|
||||
{
|
||||
.modalias = "tmp122",
|
||||
.max_speed_hz = 2 * 1000 * 1000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table ts72xx_spi_cs_gpio_table = {
|
||||
.dev_id = "spi0",
|
||||
.table = {
|
||||
/* DIO_17 */
|
||||
GPIO_LOOKUP("F", 2, "cs", GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static struct ep93xx_spi_info ts72xx_spi_info __initdata = {
|
||||
/* Intentionally left blank */
|
||||
};
|
||||
|
||||
static void __init ts72xx_init_machine(void)
|
||||
{
|
||||
ep93xx_init_devices();
|
||||
ts72xx_register_flash(ts72xx_nand_parts, ARRAY_SIZE(ts72xx_nand_parts),
|
||||
is_ts9420_installed() ?
|
||||
EP93XX_CS7_PHYS_BASE : EP93XX_CS6_PHYS_BASE);
|
||||
platform_device_register(&ts72xx_rtc_device);
|
||||
platform_device_register(&ts72xx_wdt_device);
|
||||
|
||||
ep93xx_register_eth(&ts72xx_eth_data, 1);
|
||||
#if IS_ENABLED(CONFIG_FPGA_MGR_TS73XX)
|
||||
if (board_is_ts7300())
|
||||
platform_device_register(&ts73xx_fpga_device);
|
||||
#endif
|
||||
gpiod_add_lookup_table(&ts72xx_spi_cs_gpio_table);
|
||||
ep93xx_register_spi(&ts72xx_spi_info, ts72xx_spi_devices,
|
||||
ARRAY_SIZE(ts72xx_spi_devices));
|
||||
}
|
||||
|
||||
MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC")
|
||||
/* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
|
||||
.atag_offset = 0x100,
|
||||
.nr_irqs = NR_EP93XX_IRQS,
|
||||
.map_io = ts72xx_map_io,
|
||||
.init_irq = ep93xx_init_irq,
|
||||
.init_time = ep93xx_timer_init,
|
||||
.init_machine = ts72xx_init_machine,
|
||||
.restart = ep93xx_restart,
|
||||
MACHINE_END
|
||||
|
||||
/*************************************************************************
|
||||
* EP93xx I2S audio peripheral handling
|
||||
*************************************************************************/
|
||||
static struct resource ep93xx_i2s_resource[] = {
|
||||
DEFINE_RES_MEM(EP93XX_I2S_PHYS_BASE, 0x100),
|
||||
DEFINE_RES_IRQ_NAMED(IRQ_EP93XX_SAI, "spilink i2s slave"),
|
||||
};
|
||||
|
||||
static struct platform_device ep93xx_i2s_device = {
|
||||
.name = "ep93xx-spilink-i2s",
|
||||
.id = -1,
|
||||
.num_resources = ARRAY_SIZE(ep93xx_i2s_resource),
|
||||
.resource = ep93xx_i2s_resource,
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* BK3 support code
|
||||
*************************************************************************/
|
||||
static struct mtd_partition bk3_nand_parts[] = {
|
||||
{
|
||||
.name = "System",
|
||||
.offset = 0x00000000,
|
||||
.size = 0x01e00000,
|
||||
}, {
|
||||
.name = "Data",
|
||||
.offset = 0x01e00000,
|
||||
.size = 0x05f20000
|
||||
}, {
|
||||
.name = "RedBoot",
|
||||
.offset = 0x07d20000,
|
||||
.size = 0x002e0000,
|
||||
.mask_flags = MTD_WRITEABLE, /* force RO */
|
||||
},
|
||||
};
|
||||
|
||||
static void __init bk3_init_machine(void)
|
||||
{
|
||||
ep93xx_init_devices();
|
||||
|
||||
ts72xx_register_flash(bk3_nand_parts, ARRAY_SIZE(bk3_nand_parts),
|
||||
EP93XX_CS6_PHYS_BASE);
|
||||
|
||||
ep93xx_register_eth(&ts72xx_eth_data, 1);
|
||||
|
||||
gpiod_add_lookup_table(&bk3_spi_cs_gpio_table);
|
||||
ep93xx_register_spi(&bk3_spi_master, bk3_spi_board_info,
|
||||
ARRAY_SIZE(bk3_spi_board_info));
|
||||
|
||||
/* Configure ep93xx's I2S to use AC97 pins */
|
||||
ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_I2SONAC97);
|
||||
platform_device_register(&ep93xx_i2s_device);
|
||||
}
|
||||
|
||||
MACHINE_START(BK3, "Liebherr controller BK3.1")
|
||||
/* Maintainer: Lukasz Majewski <lukma@denx.de> */
|
||||
.atag_offset = 0x100,
|
||||
.nr_irqs = NR_EP93XX_IRQS,
|
||||
.map_io = ts72xx_map_io,
|
||||
.init_irq = ep93xx_init_irq,
|
||||
.init_time = ep93xx_timer_init,
|
||||
.init_machine = bk3_init_machine,
|
||||
.restart = ep93xx_restart,
|
||||
MACHINE_END
|
@ -1,94 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* arch/arm/mach-ep93xx/include/mach/ts72xx.h
|
||||
*/
|
||||
|
||||
/*
|
||||
* TS72xx memory map:
|
||||
*
|
||||
* virt phys size
|
||||
* febff000 22000000 4K model number register (bits 0-2)
|
||||
* febfe000 22400000 4K options register
|
||||
* febfd000 22800000 4K options register #2
|
||||
* febfc000 23400000 4K CPLD version register
|
||||
*/
|
||||
|
||||
#ifndef __TS72XX_H_
|
||||
#define __TS72XX_H_
|
||||
|
||||
#define TS72XX_MODEL_PHYS_BASE 0x22000000
|
||||
#define TS72XX_MODEL_VIRT_BASE IOMEM(0xfebff000)
|
||||
#define TS72XX_MODEL_SIZE 0x00001000
|
||||
|
||||
#define TS72XX_MODEL_TS7200 0x00
|
||||
#define TS72XX_MODEL_TS7250 0x01
|
||||
#define TS72XX_MODEL_TS7260 0x02
|
||||
#define TS72XX_MODEL_TS7300 0x03
|
||||
#define TS72XX_MODEL_TS7400 0x04
|
||||
#define TS72XX_MODEL_MASK 0x07
|
||||
|
||||
|
||||
#define TS72XX_OPTIONS_PHYS_BASE 0x22400000
|
||||
#define TS72XX_OPTIONS_VIRT_BASE IOMEM(0xfebfe000)
|
||||
#define TS72XX_OPTIONS_SIZE 0x00001000
|
||||
|
||||
#define TS72XX_OPTIONS_COM2_RS485 0x02
|
||||
#define TS72XX_OPTIONS_MAX197 0x01
|
||||
|
||||
|
||||
#define TS72XX_OPTIONS2_PHYS_BASE 0x22800000
|
||||
#define TS72XX_OPTIONS2_VIRT_BASE IOMEM(0xfebfd000)
|
||||
#define TS72XX_OPTIONS2_SIZE 0x00001000
|
||||
|
||||
#define TS72XX_OPTIONS2_TS9420 0x04
|
||||
#define TS72XX_OPTIONS2_TS9420_BOOT 0x02
|
||||
|
||||
#define TS72XX_CPLDVER_PHYS_BASE 0x23400000
|
||||
#define TS72XX_CPLDVER_VIRT_BASE IOMEM(0xfebfc000)
|
||||
#define TS72XX_CPLDVER_SIZE 0x00001000
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
static inline int ts72xx_model(void)
|
||||
{
|
||||
return __raw_readb(TS72XX_MODEL_VIRT_BASE) & TS72XX_MODEL_MASK;
|
||||
}
|
||||
|
||||
static inline int board_is_ts7200(void)
|
||||
{
|
||||
return ts72xx_model() == TS72XX_MODEL_TS7200;
|
||||
}
|
||||
|
||||
static inline int board_is_ts7250(void)
|
||||
{
|
||||
return ts72xx_model() == TS72XX_MODEL_TS7250;
|
||||
}
|
||||
|
||||
static inline int board_is_ts7260(void)
|
||||
{
|
||||
return ts72xx_model() == TS72XX_MODEL_TS7260;
|
||||
}
|
||||
|
||||
static inline int board_is_ts7300(void)
|
||||
{
|
||||
return ts72xx_model() == TS72XX_MODEL_TS7300;
|
||||
}
|
||||
|
||||
static inline int board_is_ts7400(void)
|
||||
{
|
||||
return ts72xx_model() == TS72XX_MODEL_TS7400;
|
||||
}
|
||||
|
||||
static inline int is_max197_installed(void)
|
||||
{
|
||||
return !!(__raw_readb(TS72XX_OPTIONS_VIRT_BASE) &
|
||||
TS72XX_OPTIONS_MAX197);
|
||||
}
|
||||
|
||||
static inline int is_ts9420_installed(void)
|
||||
{
|
||||
return !!(__raw_readb(TS72XX_OPTIONS2_VIRT_BASE) &
|
||||
TS72XX_OPTIONS2_TS9420);
|
||||
}
|
||||
#endif
|
||||
#endif /* __TS72XX_H_ */
|
@ -1,319 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* arch/arm/mach-ep93xx/vision_ep9307.c
|
||||
* Vision Engraving Systems EP9307 SoM support.
|
||||
*
|
||||
* Copyright (C) 2008-2011 Vision Engraving Systems
|
||||
* H Hartley Sweeten <hsweeten@visionengravers.com>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_data/pca953x.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/flash.h>
|
||||
#include <linux/spi/mmc_spi.h>
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
#include <sound/cs4271.h>
|
||||
|
||||
#include "hardware.h"
|
||||
#include <linux/platform_data/video-ep93xx.h>
|
||||
#include <linux/platform_data/spi-ep93xx.h>
|
||||
#include "gpio-ep93xx.h"
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/mach/map.h>
|
||||
#include <asm/mach/arch.h>
|
||||
|
||||
#include "soc.h"
|
||||
|
||||
/*************************************************************************
|
||||
* Static I/O mappings for the FPGA
|
||||
*************************************************************************/
|
||||
#define VISION_PHYS_BASE EP93XX_CS7_PHYS_BASE
|
||||
#define VISION_VIRT_BASE 0xfebff000
|
||||
|
||||
static struct map_desc vision_io_desc[] __initdata = {
|
||||
{
|
||||
.virtual = VISION_VIRT_BASE,
|
||||
.pfn = __phys_to_pfn(VISION_PHYS_BASE),
|
||||
.length = SZ_4K,
|
||||
.type = MT_DEVICE,
|
||||
},
|
||||
};
|
||||
|
||||
static void __init vision_map_io(void)
|
||||
{
|
||||
ep93xx_map_io();
|
||||
|
||||
iotable_init(vision_io_desc, ARRAY_SIZE(vision_io_desc));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Ethernet
|
||||
*************************************************************************/
|
||||
static struct ep93xx_eth_data vision_eth_data __initdata = {
|
||||
.phy_id = 1,
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* Framebuffer
|
||||
*************************************************************************/
|
||||
#define VISION_LCD_ENABLE EP93XX_GPIO_LINE_EGPIO1
|
||||
|
||||
static int vision_lcd_setup(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = gpio_request_one(VISION_LCD_ENABLE, GPIOF_OUT_INIT_HIGH, dev_name(&pdev->dev));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_RAS |
|
||||
EP93XX_SYSCON_DEVCFG_RASONP3 |
|
||||
EP93XX_SYSCON_DEVCFG_EXVC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vision_lcd_teardown(struct platform_device *pdev)
|
||||
{
|
||||
gpio_free(VISION_LCD_ENABLE);
|
||||
}
|
||||
|
||||
static void vision_lcd_blank(int blank_mode, struct fb_info *info)
|
||||
{
|
||||
if (blank_mode)
|
||||
gpio_set_value(VISION_LCD_ENABLE, 0);
|
||||
else
|
||||
gpio_set_value(VISION_LCD_ENABLE, 1);
|
||||
}
|
||||
|
||||
static struct ep93xxfb_mach_info ep93xxfb_info __initdata = {
|
||||
.flags = EP93XXFB_USE_SDCSN0 | EP93XXFB_PCLK_FALLING,
|
||||
.setup = vision_lcd_setup,
|
||||
.teardown = vision_lcd_teardown,
|
||||
.blank = vision_lcd_blank,
|
||||
};
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* GPIO Expanders
|
||||
*************************************************************************/
|
||||
#define PCA9539_74_GPIO_BASE (EP93XX_GPIO_LINE_MAX + 1)
|
||||
#define PCA9539_75_GPIO_BASE (PCA9539_74_GPIO_BASE + 16)
|
||||
#define PCA9539_76_GPIO_BASE (PCA9539_75_GPIO_BASE + 16)
|
||||
#define PCA9539_77_GPIO_BASE (PCA9539_76_GPIO_BASE + 16)
|
||||
|
||||
static struct pca953x_platform_data pca953x_74_gpio_data = {
|
||||
.gpio_base = PCA9539_74_GPIO_BASE,
|
||||
.irq_base = EP93XX_BOARD_IRQ(0),
|
||||
};
|
||||
|
||||
static struct pca953x_platform_data pca953x_75_gpio_data = {
|
||||
.gpio_base = PCA9539_75_GPIO_BASE,
|
||||
.irq_base = -1,
|
||||
};
|
||||
|
||||
static struct pca953x_platform_data pca953x_76_gpio_data = {
|
||||
.gpio_base = PCA9539_76_GPIO_BASE,
|
||||
.irq_base = -1,
|
||||
};
|
||||
|
||||
static struct pca953x_platform_data pca953x_77_gpio_data = {
|
||||
.gpio_base = PCA9539_77_GPIO_BASE,
|
||||
.irq_base = -1,
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* I2C Bus
|
||||
*************************************************************************/
|
||||
|
||||
static struct i2c_board_info vision_i2c_info[] __initdata = {
|
||||
{
|
||||
I2C_BOARD_INFO("isl1208", 0x6f),
|
||||
.irq = IRQ_EP93XX_EXT1,
|
||||
}, {
|
||||
I2C_BOARD_INFO("pca9539", 0x74),
|
||||
.platform_data = &pca953x_74_gpio_data,
|
||||
}, {
|
||||
I2C_BOARD_INFO("pca9539", 0x75),
|
||||
.platform_data = &pca953x_75_gpio_data,
|
||||
}, {
|
||||
I2C_BOARD_INFO("pca9539", 0x76),
|
||||
.platform_data = &pca953x_76_gpio_data,
|
||||
}, {
|
||||
I2C_BOARD_INFO("pca9539", 0x77),
|
||||
.platform_data = &pca953x_77_gpio_data,
|
||||
},
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* SPI CS4271 Audio Codec
|
||||
*************************************************************************/
|
||||
static struct cs4271_platform_data vision_cs4271_data = {
|
||||
/* Intentionally left blank */
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* SPI Flash
|
||||
*************************************************************************/
|
||||
static struct mtd_partition vision_spi_flash_partitions[] = {
|
||||
{
|
||||
.name = "SPI bootstrap",
|
||||
.offset = 0,
|
||||
.size = SZ_4K,
|
||||
}, {
|
||||
.name = "Bootstrap config",
|
||||
.offset = MTDPART_OFS_APPEND,
|
||||
.size = SZ_4K,
|
||||
}, {
|
||||
.name = "System config",
|
||||
.offset = MTDPART_OFS_APPEND,
|
||||
.size = MTDPART_SIZ_FULL,
|
||||
},
|
||||
};
|
||||
|
||||
static struct flash_platform_data vision_spi_flash_data = {
|
||||
.name = "SPI Flash",
|
||||
.parts = vision_spi_flash_partitions,
|
||||
.nr_parts = ARRAY_SIZE(vision_spi_flash_partitions),
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* SPI SD/MMC host
|
||||
*************************************************************************/
|
||||
static struct mmc_spi_platform_data vision_spi_mmc_data = {
|
||||
.detect_delay = 100,
|
||||
.powerup_msecs = 100,
|
||||
.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
|
||||
.caps2 = MMC_CAP2_RO_ACTIVE_HIGH,
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table vision_spi_mmc_gpio_table = {
|
||||
.dev_id = "mmc_spi.2", /* "mmc_spi @ CS2 */
|
||||
.table = {
|
||||
/* Card detect */
|
||||
GPIO_LOOKUP_IDX("B", 7, NULL, 0, GPIO_ACTIVE_LOW),
|
||||
/* Write protect */
|
||||
GPIO_LOOKUP_IDX("F", 0, NULL, 1, GPIO_ACTIVE_HIGH),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* SPI Bus
|
||||
*************************************************************************/
|
||||
static struct spi_board_info vision_spi_board_info[] __initdata = {
|
||||
{
|
||||
.modalias = "cs4271",
|
||||
.platform_data = &vision_cs4271_data,
|
||||
.max_speed_hz = 6000000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 0,
|
||||
.mode = SPI_MODE_3,
|
||||
}, {
|
||||
.modalias = "sst25l",
|
||||
.platform_data = &vision_spi_flash_data,
|
||||
.max_speed_hz = 20000000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 1,
|
||||
.mode = SPI_MODE_3,
|
||||
}, {
|
||||
.modalias = "mmc_spi",
|
||||
.platform_data = &vision_spi_mmc_data,
|
||||
.max_speed_hz = 20000000,
|
||||
.bus_num = 0,
|
||||
.chip_select = 2,
|
||||
.mode = SPI_MODE_3,
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table vision_spi_cs4271_gpio_table = {
|
||||
.dev_id = "spi0.0", /* cs4271 @ CS0 */
|
||||
.table = {
|
||||
/* RESET */
|
||||
GPIO_LOOKUP_IDX("H", 2, NULL, 0, GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table vision_spi_cs_gpio_table = {
|
||||
.dev_id = "spi0",
|
||||
.table = {
|
||||
GPIO_LOOKUP_IDX("A", 6, "cs", 0, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("A", 7, "cs", 1, GPIO_ACTIVE_LOW),
|
||||
GPIO_LOOKUP_IDX("G", 2, "cs", 2, GPIO_ACTIVE_LOW),
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static struct ep93xx_spi_info vision_spi_master __initdata = {
|
||||
.use_dma = 1,
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* I2S Audio
|
||||
*************************************************************************/
|
||||
static struct platform_device vision_audio_device = {
|
||||
.name = "edb93xx-audio",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static void __init vision_register_i2s(void)
|
||||
{
|
||||
ep93xx_register_i2s();
|
||||
platform_device_register(&vision_audio_device);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Machine Initialization
|
||||
*************************************************************************/
|
||||
static void __init vision_init_machine(void)
|
||||
{
|
||||
ep93xx_init_devices();
|
||||
ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_64M);
|
||||
ep93xx_register_eth(&vision_eth_data, 1);
|
||||
ep93xx_register_fb(&ep93xxfb_info);
|
||||
ep93xx_register_pwm(1, 0);
|
||||
|
||||
/*
|
||||
* Request the gpio expander's interrupt gpio line now to prevent
|
||||
* the kernel from doing a WARN in gpiolib:gpio_ensure_requested().
|
||||
*/
|
||||
if (gpio_request_one(EP93XX_GPIO_LINE_F(7), GPIOF_IN, "pca9539:74"))
|
||||
pr_warn("cannot request interrupt gpio for pca9539:74\n");
|
||||
|
||||
vision_i2c_info[1].irq = gpio_to_irq(EP93XX_GPIO_LINE_F(7));
|
||||
|
||||
ep93xx_register_i2c(vision_i2c_info,
|
||||
ARRAY_SIZE(vision_i2c_info));
|
||||
gpiod_add_lookup_table(&vision_spi_cs4271_gpio_table);
|
||||
gpiod_add_lookup_table(&vision_spi_mmc_gpio_table);
|
||||
gpiod_add_lookup_table(&vision_spi_cs_gpio_table);
|
||||
ep93xx_register_spi(&vision_spi_master, vision_spi_board_info,
|
||||
ARRAY_SIZE(vision_spi_board_info));
|
||||
vision_register_i2s();
|
||||
}
|
||||
|
||||
MACHINE_START(VISION_EP9307, "Vision Engraving Systems EP9307")
|
||||
/* Maintainer: H Hartley Sweeten <hsweeten@visionengravers.com> */
|
||||
.atag_offset = 0x100,
|
||||
.nr_irqs = NR_EP93XX_IRQS + EP93XX_BOARD_IRQS,
|
||||
.map_io = vision_map_io,
|
||||
.init_irq = ep93xx_init_irq,
|
||||
.init_time = ep93xx_timer_init,
|
||||
.init_machine = vision_init_machine,
|
||||
.restart = ep93xx_restart,
|
||||
MACHINE_END
|
@ -44,8 +44,8 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
#include <linux/platform_data/dma-ep93xx.h>
|
||||
#include <linux/soc/cirrus/ep93xx.h>
|
||||
|
||||
#define DRV_NAME "ep93xx-ide"
|
||||
@ -126,7 +126,7 @@ enum {
|
||||
};
|
||||
|
||||
struct ep93xx_pata_data {
|
||||
const struct platform_device *pdev;
|
||||
struct platform_device *pdev;
|
||||
void __iomem *ide_base;
|
||||
struct ata_timing t;
|
||||
bool iordy;
|
||||
@ -135,9 +135,7 @@ struct ep93xx_pata_data {
|
||||
unsigned long udma_out_phys;
|
||||
|
||||
struct dma_chan *dma_rx_channel;
|
||||
struct ep93xx_dma_data dma_rx_data;
|
||||
struct dma_chan *dma_tx_channel;
|
||||
struct ep93xx_dma_data dma_tx_data;
|
||||
};
|
||||
|
||||
static void ep93xx_pata_clear_regs(void __iomem *base)
|
||||
@ -637,20 +635,13 @@ static void ep93xx_pata_release_dma(struct ep93xx_pata_data *drv_data)
|
||||
}
|
||||
}
|
||||
|
||||
static bool ep93xx_pata_dma_filter(struct dma_chan *chan, void *filter_param)
|
||||
static int ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
|
||||
{
|
||||
if (ep93xx_dma_chan_is_m2p(chan))
|
||||
return false;
|
||||
|
||||
chan->private = filter_param;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
|
||||
{
|
||||
const struct platform_device *pdev = drv_data->pdev;
|
||||
struct platform_device *pdev = drv_data->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
dma_cap_mask_t mask;
|
||||
struct dma_slave_config conf;
|
||||
int ret;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
@ -660,22 +651,16 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
|
||||
* to request only one channel, and reprogram it's direction at
|
||||
* start of new transfer.
|
||||
*/
|
||||
drv_data->dma_rx_data.port = EP93XX_DMA_IDE;
|
||||
drv_data->dma_rx_data.direction = DMA_DEV_TO_MEM;
|
||||
drv_data->dma_rx_data.name = "ep93xx-pata-rx";
|
||||
drv_data->dma_rx_channel = dma_request_channel(mask,
|
||||
ep93xx_pata_dma_filter, &drv_data->dma_rx_data);
|
||||
if (!drv_data->dma_rx_channel)
|
||||
return;
|
||||
drv_data->dma_rx_channel = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(drv_data->dma_rx_channel))
|
||||
return dev_err_probe(dev, PTR_ERR(drv_data->dma_rx_channel),
|
||||
"rx DMA setup failed\n");
|
||||
|
||||
drv_data->dma_tx_data.port = EP93XX_DMA_IDE;
|
||||
drv_data->dma_tx_data.direction = DMA_MEM_TO_DEV;
|
||||
drv_data->dma_tx_data.name = "ep93xx-pata-tx";
|
||||
drv_data->dma_tx_channel = dma_request_channel(mask,
|
||||
ep93xx_pata_dma_filter, &drv_data->dma_tx_data);
|
||||
if (!drv_data->dma_tx_channel) {
|
||||
dma_release_channel(drv_data->dma_rx_channel);
|
||||
return;
|
||||
drv_data->dma_tx_channel = dma_request_chan(&pdev->dev, "tx");
|
||||
if (IS_ERR(drv_data->dma_tx_channel)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(drv_data->dma_tx_channel),
|
||||
"tx DMA setup failed\n");
|
||||
goto fail_release_rx;
|
||||
}
|
||||
|
||||
/* Configure receive channel direction and source address */
|
||||
@ -683,10 +668,10 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
|
||||
conf.direction = DMA_DEV_TO_MEM;
|
||||
conf.src_addr = drv_data->udma_in_phys;
|
||||
conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
if (dmaengine_slave_config(drv_data->dma_rx_channel, &conf)) {
|
||||
dev_err(&pdev->dev, "failed to configure rx dma channel\n");
|
||||
ep93xx_pata_release_dma(drv_data);
|
||||
return;
|
||||
ret = dmaengine_slave_config(drv_data->dma_rx_channel, &conf);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "failed to configure rx dma channel");
|
||||
goto fail_release_dma;
|
||||
}
|
||||
|
||||
/* Configure transmit channel direction and destination address */
|
||||
@ -694,10 +679,20 @@ static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
|
||||
conf.direction = DMA_MEM_TO_DEV;
|
||||
conf.dst_addr = drv_data->udma_out_phys;
|
||||
conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
if (dmaengine_slave_config(drv_data->dma_tx_channel, &conf)) {
|
||||
dev_err(&pdev->dev, "failed to configure tx dma channel\n");
|
||||
ep93xx_pata_release_dma(drv_data);
|
||||
ret = dmaengine_slave_config(drv_data->dma_tx_channel, &conf);
|
||||
if (ret) {
|
||||
dev_err_probe(dev, ret, "failed to configure tx dma channel");
|
||||
goto fail_release_dma;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_release_rx:
|
||||
dma_release_channel(drv_data->dma_rx_channel);
|
||||
fail_release_dma:
|
||||
ep93xx_pata_release_dma(drv_data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ep93xx_pata_dma_start(struct ata_queued_cmd *qc)
|
||||
@ -925,34 +920,26 @@ static int ep93xx_pata_probe(struct platform_device *pdev)
|
||||
void __iomem *ide_base;
|
||||
int err;
|
||||
|
||||
err = ep93xx_ide_acquire_gpio(pdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* INT[3] (IRQ_EP93XX_EXT3) line connected as pull down */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
err = irq;
|
||||
goto err_rel_gpio;
|
||||
}
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
ide_base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);
|
||||
if (IS_ERR(ide_base)) {
|
||||
err = PTR_ERR(ide_base);
|
||||
goto err_rel_gpio;
|
||||
}
|
||||
if (IS_ERR(ide_base))
|
||||
return PTR_ERR(ide_base);
|
||||
|
||||
drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
|
||||
if (!drv_data) {
|
||||
err = -ENOMEM;
|
||||
goto err_rel_gpio;
|
||||
}
|
||||
if (!drv_data)
|
||||
return -ENOMEM;
|
||||
|
||||
drv_data->pdev = pdev;
|
||||
drv_data->ide_base = ide_base;
|
||||
drv_data->udma_in_phys = mem_res->start + IDEUDMADATAIN;
|
||||
drv_data->udma_out_phys = mem_res->start + IDEUDMADATAOUT;
|
||||
ep93xx_pata_dma_init(drv_data);
|
||||
err = ep93xx_pata_dma_init(drv_data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* allocate host */
|
||||
host = ata_host_alloc(&pdev->dev, 1);
|
||||
@ -1003,8 +990,6 @@ static int ep93xx_pata_probe(struct platform_device *pdev)
|
||||
|
||||
err_rel_dma:
|
||||
ep93xx_pata_release_dma(drv_data);
|
||||
err_rel_gpio:
|
||||
ep93xx_ide_release_gpio(pdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1016,12 +1001,18 @@ static void ep93xx_pata_remove(struct platform_device *pdev)
|
||||
ata_host_detach(host);
|
||||
ep93xx_pata_release_dma(drv_data);
|
||||
ep93xx_pata_clear_regs(drv_data->ide_base);
|
||||
ep93xx_ide_release_gpio(pdev);
|
||||
}
|
||||
|
||||
static const struct of_device_id ep93xx_pata_of_ids[] = {
|
||||
{ .compatible = "cirrus,ep9312-pata" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ep93xx_pata_of_ids);
|
||||
|
||||
static struct platform_driver ep93xx_pata_platform_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.of_match_table = ep93xx_pata_of_ids,
|
||||
},
|
||||
.probe = ep93xx_pata_probe,
|
||||
.remove_new = ep93xx_pata_remove,
|
||||
|
@ -218,6 +218,14 @@ config COMMON_CLK_EN7523
|
||||
This driver provides the fixed clocks and gates present on Airoha
|
||||
ARM silicon.
|
||||
|
||||
config COMMON_CLK_EP93XX
|
||||
tristate "Clock driver for Cirrus Logic ep93xx SoC"
|
||||
depends on ARCH_EP93XX || COMPILE_TEST
|
||||
select AUXILIARY_BUS
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
This driver supports the SoC clocks on the Cirrus Logic ep93xx.
|
||||
|
||||
config COMMON_CLK_FSL_FLEXSPI
|
||||
tristate "Clock driver for FlexSPI on Layerscape SoCs"
|
||||
depends on ARCH_LAYERSCAPE || COMPILE_TEST
|
||||
|
@ -39,6 +39,7 @@ obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
|
||||
obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
|
||||
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
|
||||
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
|
||||
obj-$(CONFIG_COMMON_CLK_EP93XX) += clk-ep93xx.o
|
||||
obj-$(CONFIG_ARCH_SPARX5) += clk-sparx5.o
|
||||
obj-$(CONFIG_COMMON_CLK_EN7523) += clk-en7523.o
|
||||
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
|
||||
|
850
drivers/clk/clk-ep93xx.c
Normal file
850
drivers/clk/clk-ep93xx.c
Normal file
@ -0,0 +1,850 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Clock control for Cirrus EP93xx chips.
|
||||
* Copyright (C) 2021 Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
*
|
||||
* Based on a rewrite of arch/arm/mach-ep93xx/clock.c:
|
||||
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
|
||||
*/
|
||||
#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <linux/soc/cirrus/ep93xx.h>
|
||||
#include <dt-bindings/clock/cirrus,ep9301-syscon.h>
|
||||
|
||||
#include <asm/div64.h>
|
||||
|
||||
#define EP93XX_EXT_CLK_RATE 14745600
|
||||
#define EP93XX_EXT_RTC_RATE 32768
|
||||
|
||||
#define EP93XX_SYSCON_POWER_STATE 0x00
|
||||
#define EP93XX_SYSCON_PWRCNT 0x04
|
||||
#define EP93XX_SYSCON_PWRCNT_UARTBAUD BIT(29)
|
||||
#define EP93XX_SYSCON_PWRCNT_USH_EN 28
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2M1 27
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2M0 26
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P8 25
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P9 24
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P6 23
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P7 22
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P4 21
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P5 20
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P2 19
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P3 18
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P0 17
|
||||
#define EP93XX_SYSCON_PWRCNT_DMA_M2P1 16
|
||||
#define EP93XX_SYSCON_CLKSET1 0x20
|
||||
#define EP93XX_SYSCON_CLKSET1_NBYP1 BIT(23)
|
||||
#define EP93XX_SYSCON_CLKSET2 0x24
|
||||
#define EP93XX_SYSCON_CLKSET2_NBYP2 BIT(19)
|
||||
#define EP93XX_SYSCON_CLKSET2_PLL2_EN BIT(18)
|
||||
#define EP93XX_SYSCON_DEVCFG 0x80
|
||||
#define EP93XX_SYSCON_DEVCFG_U3EN 24
|
||||
#define EP93XX_SYSCON_DEVCFG_U2EN 20
|
||||
#define EP93XX_SYSCON_DEVCFG_U1EN 18
|
||||
#define EP93XX_SYSCON_VIDCLKDIV 0x84
|
||||
#define EP93XX_SYSCON_CLKDIV_ENABLE 15
|
||||
#define EP93XX_SYSCON_CLKDIV_ESEL BIT(14)
|
||||
#define EP93XX_SYSCON_CLKDIV_PSEL BIT(13)
|
||||
#define EP93XX_SYSCON_CLKDIV_MASK GENMASK(14, 13)
|
||||
#define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT 8
|
||||
#define EP93XX_SYSCON_I2SCLKDIV 0x8c
|
||||
#define EP93XX_SYSCON_I2SCLKDIV_SENA 31
|
||||
#define EP93XX_SYSCON_I2SCLKDIV_ORIDE BIT(29)
|
||||
#define EP93XX_SYSCON_I2SCLKDIV_SPOL BIT(19)
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV 0x90
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN 31
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV 16
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN 15
|
||||
#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV 0
|
||||
#define EP93XX_SYSCON_CHIPID 0x94
|
||||
#define EP93XX_SYSCON_CHIPID_ID 0x9213
|
||||
|
||||
#define EP93XX_FIXED_CLK_COUNT 21
|
||||
|
||||
static const char ep93xx_adc_divisors[] = { 16, 4 };
|
||||
static const char ep93xx_sclk_divisors[] = { 2, 4 };
|
||||
static const char ep93xx_lrclk_divisors[] = { 32, 64, 128 };
|
||||
|
||||
struct ep93xx_clk {
|
||||
struct clk_hw hw;
|
||||
u16 idx;
|
||||
u16 reg;
|
||||
u32 mask;
|
||||
u8 bit_idx;
|
||||
u8 shift;
|
||||
u8 width;
|
||||
u8 num_div;
|
||||
const char *div;
|
||||
};
|
||||
|
||||
struct ep93xx_clk_priv {
|
||||
spinlock_t lock;
|
||||
struct ep93xx_regmap_adev *aux_dev;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct regmap *map;
|
||||
struct clk_hw *fixed[EP93XX_FIXED_CLK_COUNT];
|
||||
struct ep93xx_clk reg[];
|
||||
};
|
||||
|
||||
static struct ep93xx_clk *ep93xx_clk_from(struct clk_hw *hw)
|
||||
{
|
||||
return container_of(hw, struct ep93xx_clk, hw);
|
||||
}
|
||||
|
||||
static struct ep93xx_clk_priv *ep93xx_priv_from(struct ep93xx_clk *clk)
|
||||
{
|
||||
return container_of(clk, struct ep93xx_clk_priv, reg[clk->idx]);
|
||||
}
|
||||
|
||||
static void ep93xx_clk_write(struct ep93xx_clk_priv *priv, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct ep93xx_regmap_adev *aux = priv->aux_dev;
|
||||
|
||||
aux->write(aux->map, aux->lock, reg, val);
|
||||
}
|
||||
|
||||
static int ep93xx_clk_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct ep93xx_clk *clk = ep93xx_clk_from(hw);
|
||||
struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk);
|
||||
u32 val;
|
||||
|
||||
regmap_read(priv->map, clk->reg, &val);
|
||||
|
||||
return !!(val & BIT(clk->bit_idx));
|
||||
}
|
||||
|
||||
static int ep93xx_clk_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct ep93xx_clk *clk = ep93xx_clk_from(hw);
|
||||
struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk);
|
||||
u32 val;
|
||||
|
||||
guard(spinlock_irqsave)(&priv->lock);
|
||||
|
||||
regmap_read(priv->map, clk->reg, &val);
|
||||
val |= BIT(clk->bit_idx);
|
||||
|
||||
ep93xx_clk_write(priv, clk->reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ep93xx_clk_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct ep93xx_clk *clk = ep93xx_clk_from(hw);
|
||||
struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk);
|
||||
u32 val;
|
||||
|
||||
guard(spinlock_irqsave)(&priv->lock);
|
||||
|
||||
regmap_read(priv->map, clk->reg, &val);
|
||||
val &= ~BIT(clk->bit_idx);
|
||||
|
||||
ep93xx_clk_write(priv, clk->reg, val);
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_ep93xx_gate_ops = {
|
||||
.enable = ep93xx_clk_enable,
|
||||
.disable = ep93xx_clk_disable,
|
||||
.is_enabled = ep93xx_clk_is_enabled,
|
||||
};
|
||||
|
||||
static int ep93xx_clk_register_gate(struct ep93xx_clk *clk,
|
||||
const char *name,
|
||||
struct clk_parent_data *parent_data,
|
||||
unsigned long flags,
|
||||
unsigned int reg,
|
||||
u8 bit_idx)
|
||||
{
|
||||
struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk);
|
||||
struct clk_init_data init = { };
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_ep93xx_gate_ops;
|
||||
init.flags = flags;
|
||||
init.parent_data = parent_data;
|
||||
init.num_parents = 1;
|
||||
|
||||
clk->reg = reg;
|
||||
clk->bit_idx = bit_idx;
|
||||
clk->hw.init = &init;
|
||||
|
||||
return devm_clk_hw_register(priv->dev, &clk->hw);
|
||||
}
|
||||
|
||||
static u8 ep93xx_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct ep93xx_clk *clk = ep93xx_clk_from(hw);
|
||||
struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk);
|
||||
u32 val;
|
||||
|
||||
regmap_read(priv->map, clk->reg, &val);
|
||||
|
||||
val &= EP93XX_SYSCON_CLKDIV_MASK;
|
||||
|
||||
switch (val) {
|
||||
case EP93XX_SYSCON_CLKDIV_ESEL:
|
||||
return 1; /* PLL1 */
|
||||
case EP93XX_SYSCON_CLKDIV_MASK:
|
||||
return 2; /* PLL2 */
|
||||
default:
|
||||
return 0; /* XTALI */
|
||||
};
|
||||
}
|
||||
|
||||
static int ep93xx_mux_set_parent_lock(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct ep93xx_clk *clk = ep93xx_clk_from(hw);
|
||||
struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk);
|
||||
u32 val;
|
||||
|
||||
if (index >= 3)
|
||||
return -EINVAL;
|
||||
|
||||
guard(spinlock_irqsave)(&priv->lock);
|
||||
|
||||
regmap_read(priv->map, clk->reg, &val);
|
||||
val &= ~(EP93XX_SYSCON_CLKDIV_MASK);
|
||||
val |= index > 0 ? EP93XX_SYSCON_CLKDIV_ESEL : 0;
|
||||
val |= index > 1 ? EP93XX_SYSCON_CLKDIV_PSEL : 0;
|
||||
|
||||
ep93xx_clk_write(priv, clk->reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_best(unsigned long rate, unsigned long now,
|
||||
unsigned long best)
|
||||
{
|
||||
return abs_diff(rate, now) < abs_diff(rate, best);
|
||||
}
|
||||
|
||||
static int ep93xx_mux_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
unsigned long best_rate = 0, actual_rate, mclk_rate;
|
||||
unsigned long rate = req->rate;
|
||||
struct clk_hw *parent_best = NULL;
|
||||
unsigned long parent_rate_best;
|
||||
unsigned long parent_rate;
|
||||
int div, pdiv;
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* Try the two pll's and the external clock,
|
||||
* because the valid predividers are 2, 2.5 and 3, we multiply
|
||||
* all the clocks by 2 to avoid floating point math.
|
||||
*
|
||||
* This is based on the algorithm in the ep93xx raster guide:
|
||||
* http://be-a-maverick.com/en/pubs/appNote/AN269REV1.pdf
|
||||
*
|
||||
*/
|
||||
for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
|
||||
struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
|
||||
|
||||
parent_rate = clk_hw_get_rate(parent);
|
||||
mclk_rate = parent_rate * 2;
|
||||
|
||||
/* Try each predivider value */
|
||||
for (pdiv = 4; pdiv <= 6; pdiv++) {
|
||||
div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv);
|
||||
if (!in_range(div, 1, 127))
|
||||
continue;
|
||||
|
||||
actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div);
|
||||
if (is_best(rate, actual_rate, best_rate)) {
|
||||
best_rate = actual_rate;
|
||||
parent_rate_best = parent_rate;
|
||||
parent_best = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!parent_best)
|
||||
return -EINVAL;
|
||||
|
||||
req->best_parent_rate = parent_rate_best;
|
||||
req->best_parent_hw = parent_best;
|
||||
req->rate = best_rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long ep93xx_ddiv_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct ep93xx_clk *clk = ep93xx_clk_from(hw);
|
||||
struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk);
|
||||
unsigned int pdiv, div;
|
||||
u32 val;
|
||||
|
||||
regmap_read(priv->map, clk->reg, &val);
|
||||
pdiv = (val >> EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) & GENMASK(1, 0);
|
||||
div = val & GENMASK(6, 0);
|
||||
if (!div)
|
||||
return 0;
|
||||
|
||||
return DIV_ROUND_CLOSEST(parent_rate * 2, (pdiv + 3) * div);
|
||||
}
|
||||
|
||||
static int ep93xx_ddiv_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct ep93xx_clk *clk = ep93xx_clk_from(hw);
|
||||
struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk);
|
||||
int pdiv, div, npdiv, ndiv;
|
||||
unsigned long actual_rate, mclk_rate, rate_err = ULONG_MAX;
|
||||
u32 val;
|
||||
|
||||
regmap_read(priv->map, clk->reg, &val);
|
||||
mclk_rate = parent_rate * 2;
|
||||
|
||||
for (pdiv = 4; pdiv <= 6; pdiv++) {
|
||||
div = DIV_ROUND_CLOSEST(mclk_rate, rate * pdiv);
|
||||
if (!in_range(div, 1, 127))
|
||||
continue;
|
||||
|
||||
actual_rate = DIV_ROUND_CLOSEST(mclk_rate, pdiv * div);
|
||||
if (abs(actual_rate - rate) < rate_err) {
|
||||
npdiv = pdiv - 3;
|
||||
ndiv = div;
|
||||
rate_err = abs(actual_rate - rate);
|
||||
}
|
||||
}
|
||||
|
||||
if (rate_err == ULONG_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Clear old dividers.
|
||||
* Bit 7 is reserved bit in all ClkDiv registers.
|
||||
*/
|
||||
val &= ~(GENMASK(9, 0) & ~BIT(7));
|
||||
|
||||
/* Set the new pdiv and div bits for the new clock rate */
|
||||
val |= (npdiv << EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | ndiv;
|
||||
|
||||
ep93xx_clk_write(priv, clk->reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops clk_ddiv_ops = {
|
||||
.enable = ep93xx_clk_enable,
|
||||
.disable = ep93xx_clk_disable,
|
||||
.is_enabled = ep93xx_clk_is_enabled,
|
||||
.get_parent = ep93xx_mux_get_parent,
|
||||
.set_parent = ep93xx_mux_set_parent_lock,
|
||||
.determine_rate = ep93xx_mux_determine_rate,
|
||||
.recalc_rate = ep93xx_ddiv_recalc_rate,
|
||||
.set_rate = ep93xx_ddiv_set_rate,
|
||||
};
|
||||
|
||||
static int ep93xx_clk_register_ddiv(struct ep93xx_clk *clk,
|
||||
const char *name,
|
||||
struct clk_parent_data *parent_data,
|
||||
u8 num_parents,
|
||||
unsigned int reg,
|
||||
u8 bit_idx)
|
||||
{
|
||||
struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk);
|
||||
struct clk_init_data init = { };
|
||||
|
||||
init.name = name;
|
||||
init.ops = &clk_ddiv_ops;
|
||||
init.flags = 0;
|
||||
init.parent_data = parent_data;
|
||||
init.num_parents = num_parents;
|
||||
|
||||
clk->reg = reg;
|
||||
clk->bit_idx = bit_idx;
|
||||
clk->hw.init = &init;
|
||||
|
||||
return devm_clk_hw_register(priv->dev, &clk->hw);
|
||||
}
|
||||
|
||||
static unsigned long ep93xx_div_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct ep93xx_clk *clk = ep93xx_clk_from(hw);
|
||||
struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk);
|
||||
u32 val;
|
||||
u8 index;
|
||||
|
||||
regmap_read(priv->map, clk->reg, &val);
|
||||
index = (val & clk->mask) >> clk->shift;
|
||||
if (index >= clk->num_div)
|
||||
return 0;
|
||||
|
||||
return DIV_ROUND_CLOSEST(parent_rate, clk->div[index]);
|
||||
}
|
||||
|
||||
static long ep93xx_div_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
struct ep93xx_clk *clk = ep93xx_clk_from(hw);
|
||||
unsigned long best = 0, now;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < clk->num_div; i++) {
|
||||
if ((rate * clk->div[i]) == *parent_rate)
|
||||
return rate;
|
||||
|
||||
now = DIV_ROUND_CLOSEST(*parent_rate, clk->div[i]);
|
||||
if (!best || is_best(rate, now, best))
|
||||
best = now;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
static int ep93xx_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct ep93xx_clk *clk = ep93xx_clk_from(hw);
|
||||
struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk);
|
||||
unsigned int i;
|
||||
u32 val;
|
||||
|
||||
regmap_read(priv->map, clk->reg, &val);
|
||||
val &= ~clk->mask;
|
||||
for (i = 0; i < clk->num_div; i++)
|
||||
if (rate == DIV_ROUND_CLOSEST(parent_rate, clk->div[i]))
|
||||
break;
|
||||
|
||||
if (i == clk->num_div)
|
||||
return -EINVAL;
|
||||
|
||||
val |= i << clk->shift;
|
||||
|
||||
ep93xx_clk_write(priv, clk->reg, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct clk_ops ep93xx_div_ops = {
|
||||
.enable = ep93xx_clk_enable,
|
||||
.disable = ep93xx_clk_disable,
|
||||
.is_enabled = ep93xx_clk_is_enabled,
|
||||
.recalc_rate = ep93xx_div_recalc_rate,
|
||||
.round_rate = ep93xx_div_round_rate,
|
||||
.set_rate = ep93xx_div_set_rate,
|
||||
};
|
||||
|
||||
static int ep93xx_register_div(struct ep93xx_clk *clk,
|
||||
const char *name,
|
||||
const struct clk_parent_data *parent_data,
|
||||
unsigned int reg,
|
||||
u8 enable_bit,
|
||||
u8 shift,
|
||||
u8 width,
|
||||
const char *clk_divisors,
|
||||
u8 num_div)
|
||||
{
|
||||
struct ep93xx_clk_priv *priv = ep93xx_priv_from(clk);
|
||||
struct clk_init_data init = { };
|
||||
|
||||
init.name = name;
|
||||
init.ops = &ep93xx_div_ops;
|
||||
init.flags = 0;
|
||||
init.parent_data = parent_data;
|
||||
init.num_parents = 1;
|
||||
|
||||
clk->reg = reg;
|
||||
clk->bit_idx = enable_bit;
|
||||
clk->mask = GENMASK(shift + width - 1, shift);
|
||||
clk->shift = shift;
|
||||
clk->div = clk_divisors;
|
||||
clk->num_div = num_div;
|
||||
clk->hw.init = &init;
|
||||
|
||||
return devm_clk_hw_register(priv->dev, &clk->hw);
|
||||
}
|
||||
|
||||
struct ep93xx_gate {
|
||||
unsigned int idx;
|
||||
unsigned int bit;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static const struct ep93xx_gate ep93xx_uarts[] = {
|
||||
{ EP93XX_CLK_UART1, EP93XX_SYSCON_DEVCFG_U1EN, "uart1" },
|
||||
{ EP93XX_CLK_UART2, EP93XX_SYSCON_DEVCFG_U2EN, "uart2" },
|
||||
{ EP93XX_CLK_UART3, EP93XX_SYSCON_DEVCFG_U3EN, "uart3" },
|
||||
};
|
||||
|
||||
static int ep93xx_uart_clock_init(struct ep93xx_clk_priv *priv)
|
||||
{
|
||||
struct clk_parent_data parent_data = { };
|
||||
unsigned int i, idx, ret, clk_uart_div;
|
||||
struct ep93xx_clk *clk;
|
||||
u32 val;
|
||||
|
||||
regmap_read(priv->map, EP93XX_SYSCON_PWRCNT, &val);
|
||||
if (val & EP93XX_SYSCON_PWRCNT_UARTBAUD)
|
||||
clk_uart_div = 1;
|
||||
else
|
||||
clk_uart_div = 2;
|
||||
|
||||
priv->fixed[EP93XX_CLK_UART] =
|
||||
devm_clk_hw_register_fixed_factor_index(priv->dev, "uart",
|
||||
0, /* XTALI external clock */
|
||||
0, 1, clk_uart_div);
|
||||
parent_data.hw = priv->fixed[EP93XX_CLK_UART];
|
||||
|
||||
/* parenting uart gate clocks to uart clock */
|
||||
for (i = 0; i < ARRAY_SIZE(ep93xx_uarts); i++) {
|
||||
idx = ep93xx_uarts[i].idx - EP93XX_CLK_UART1;
|
||||
clk = &priv->reg[idx];
|
||||
clk->idx = idx;
|
||||
ret = ep93xx_clk_register_gate(clk,
|
||||
ep93xx_uarts[i].name,
|
||||
&parent_data, CLK_SET_RATE_PARENT,
|
||||
EP93XX_SYSCON_DEVCFG,
|
||||
ep93xx_uarts[i].bit);
|
||||
if (ret)
|
||||
return dev_err_probe(priv->dev, ret,
|
||||
"failed to register uart[%d] clock\n", i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ep93xx_gate ep93xx_dmas[] = {
|
||||
{ EP93XX_CLK_M2M0, EP93XX_SYSCON_PWRCNT_DMA_M2M0, "m2m0" },
|
||||
{ EP93XX_CLK_M2M1, EP93XX_SYSCON_PWRCNT_DMA_M2M1, "m2m1" },
|
||||
{ EP93XX_CLK_M2P0, EP93XX_SYSCON_PWRCNT_DMA_M2P0, "m2p0" },
|
||||
{ EP93XX_CLK_M2P1, EP93XX_SYSCON_PWRCNT_DMA_M2P1, "m2p1" },
|
||||
{ EP93XX_CLK_M2P2, EP93XX_SYSCON_PWRCNT_DMA_M2P2, "m2p2" },
|
||||
{ EP93XX_CLK_M2P3, EP93XX_SYSCON_PWRCNT_DMA_M2P3, "m2p3" },
|
||||
{ EP93XX_CLK_M2P4, EP93XX_SYSCON_PWRCNT_DMA_M2P4, "m2p4" },
|
||||
{ EP93XX_CLK_M2P5, EP93XX_SYSCON_PWRCNT_DMA_M2P5, "m2p5" },
|
||||
{ EP93XX_CLK_M2P6, EP93XX_SYSCON_PWRCNT_DMA_M2P6, "m2p6" },
|
||||
{ EP93XX_CLK_M2P7, EP93XX_SYSCON_PWRCNT_DMA_M2P7, "m2p7" },
|
||||
{ EP93XX_CLK_M2P8, EP93XX_SYSCON_PWRCNT_DMA_M2P8, "m2p8" },
|
||||
{ EP93XX_CLK_M2P9, EP93XX_SYSCON_PWRCNT_DMA_M2P9, "m2p9" },
|
||||
};
|
||||
|
||||
static int ep93xx_dma_clock_init(struct ep93xx_clk_priv *priv)
|
||||
{
|
||||
struct clk_parent_data parent_data = { };
|
||||
unsigned int i, idx;
|
||||
|
||||
parent_data.hw = priv->fixed[EP93XX_CLK_HCLK];
|
||||
for (i = 0; i < ARRAY_SIZE(ep93xx_dmas); i++) {
|
||||
idx = ep93xx_dmas[i].idx;
|
||||
priv->fixed[idx] = devm_clk_hw_register_gate_parent_data(priv->dev,
|
||||
ep93xx_dmas[i].name,
|
||||
&parent_data, 0,
|
||||
priv->base + EP93XX_SYSCON_PWRCNT,
|
||||
ep93xx_dmas[i].bit,
|
||||
0,
|
||||
&priv->lock);
|
||||
if (IS_ERR(priv->fixed[idx]))
|
||||
return PTR_ERR(priv->fixed[idx]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clk_hw *of_clk_ep93xx_get(struct of_phandle_args *clkspec, void *data)
|
||||
{
|
||||
struct ep93xx_clk_priv *priv = data;
|
||||
unsigned int idx = clkspec->args[0];
|
||||
|
||||
if (idx < EP93XX_CLK_UART1)
|
||||
return priv->fixed[idx];
|
||||
|
||||
if (idx <= EP93XX_CLK_I2S_LRCLK)
|
||||
return &priv->reg[idx - EP93XX_CLK_UART1].hw;
|
||||
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* PLL rate = 14.7456 MHz * (X1FBD + 1) * (X2FBD + 1) / (X2IPD + 1) / 2^PS
|
||||
*/
|
||||
static unsigned long calc_pll_rate(u64 rate, u32 config_word)
|
||||
{
|
||||
rate *= ((config_word >> 11) & GENMASK(4, 0)) + 1; /* X1FBD */
|
||||
rate *= ((config_word >> 5) & GENMASK(5, 0)) + 1; /* X2FBD */
|
||||
do_div(rate, (config_word & GENMASK(4, 0)) + 1); /* X2IPD */
|
||||
rate >>= (config_word >> 16) & GENMASK(1, 0); /* PS */
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
static int ep93xx_plls_init(struct ep93xx_clk_priv *priv)
|
||||
{
|
||||
const char fclk_divisors[] = { 1, 2, 4, 8, 16, 1, 1, 1 };
|
||||
const char hclk_divisors[] = { 1, 2, 4, 5, 6, 8, 16, 32 };
|
||||
const char pclk_divisors[] = { 1, 2, 4, 8 };
|
||||
struct clk_parent_data xtali = { .index = 0 };
|
||||
unsigned int clk_f_div, clk_h_div, clk_p_div;
|
||||
unsigned long clk_pll1_rate, clk_pll2_rate;
|
||||
struct device *dev = priv->dev;
|
||||
struct clk_hw *hw, *pll1;
|
||||
u32 value;
|
||||
|
||||
/* Determine the bootloader configured pll1 rate */
|
||||
regmap_read(priv->map, EP93XX_SYSCON_CLKSET1, &value);
|
||||
|
||||
if (value & EP93XX_SYSCON_CLKSET1_NBYP1)
|
||||
clk_pll1_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value);
|
||||
else
|
||||
clk_pll1_rate = EP93XX_EXT_CLK_RATE;
|
||||
|
||||
pll1 = devm_clk_hw_register_fixed_rate_parent_data(dev, "pll1", &xtali,
|
||||
0, clk_pll1_rate);
|
||||
if (IS_ERR(pll1))
|
||||
return PTR_ERR(pll1);
|
||||
|
||||
priv->fixed[EP93XX_CLK_PLL1] = pll1;
|
||||
|
||||
/* Initialize the pll1 derived clocks */
|
||||
clk_f_div = fclk_divisors[(value >> 25) & GENMASK(2, 0)];
|
||||
clk_h_div = hclk_divisors[(value >> 20) & GENMASK(2, 0)];
|
||||
clk_p_div = pclk_divisors[(value >> 18) & GENMASK(1, 0)];
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, "fclk", pll1, 0, 1, clk_f_div);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
||||
priv->fixed[EP93XX_CLK_FCLK] = hw;
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, "hclk", pll1, 0, 1, clk_h_div);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
||||
priv->fixed[EP93XX_CLK_HCLK] = hw;
|
||||
|
||||
hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, "pclk", hw, 0, 1, clk_p_div);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
||||
priv->fixed[EP93XX_CLK_PCLK] = hw;
|
||||
|
||||
/* Determine the bootloader configured pll2 rate */
|
||||
regmap_read(priv->map, EP93XX_SYSCON_CLKSET2, &value);
|
||||
if (!(value & EP93XX_SYSCON_CLKSET2_NBYP2))
|
||||
clk_pll2_rate = EP93XX_EXT_CLK_RATE;
|
||||
else if (value & EP93XX_SYSCON_CLKSET2_PLL2_EN)
|
||||
clk_pll2_rate = calc_pll_rate(EP93XX_EXT_CLK_RATE, value);
|
||||
else
|
||||
clk_pll2_rate = 0;
|
||||
|
||||
hw = devm_clk_hw_register_fixed_rate_parent_data(dev, "pll2", &xtali,
|
||||
0, clk_pll2_rate);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
||||
priv->fixed[EP93XX_CLK_PLL2] = hw;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ep93xx_clk_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct ep93xx_regmap_adev *rdev = to_ep93xx_regmap_adev(adev);
|
||||
struct clk_parent_data xtali = { .index = 0 };
|
||||
struct clk_parent_data ddiv_pdata[3] = { };
|
||||
unsigned int clk_spi_div, clk_usb_div;
|
||||
struct clk_parent_data pdata = {};
|
||||
struct device *dev = &adev->dev;
|
||||
struct ep93xx_clk_priv *priv;
|
||||
struct ep93xx_clk *clk;
|
||||
struct clk_hw *hw;
|
||||
unsigned int idx;
|
||||
int ret;
|
||||
u32 value;
|
||||
|
||||
priv = devm_kzalloc(dev, struct_size(priv, reg, 10), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&priv->lock);
|
||||
priv->dev = dev;
|
||||
priv->aux_dev = rdev;
|
||||
priv->map = rdev->map;
|
||||
priv->base = rdev->base;
|
||||
|
||||
ret = ep93xx_plls_init(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap_read(priv->map, EP93XX_SYSCON_CLKSET2, &value);
|
||||
clk_usb_div = (value >> 28 & GENMASK(3, 0)) + 1;
|
||||
hw = devm_clk_hw_register_fixed_factor_parent_hw(dev, "usb_clk",
|
||||
priv->fixed[EP93XX_CLK_PLL2], 0, 1,
|
||||
clk_usb_div);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
||||
priv->fixed[EP93XX_CLK_USB] = hw;
|
||||
|
||||
ret = ep93xx_uart_clock_init(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ep93xx_dma_clock_init(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_spi_div = id->driver_data;
|
||||
hw = devm_clk_hw_register_fixed_factor_index(dev, "ep93xx-spi.0",
|
||||
0, /* XTALI external clock */
|
||||
0, 1, clk_spi_div);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
||||
priv->fixed[EP93XX_CLK_SPI] = hw;
|
||||
|
||||
/* PWM clock */
|
||||
hw = devm_clk_hw_register_fixed_factor_index(dev, "pwm_clk", 0, /* XTALI external clock */
|
||||
0, 1, 1);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
||||
priv->fixed[EP93XX_CLK_PWM] = hw;
|
||||
|
||||
/* USB clock */
|
||||
pdata.hw = priv->fixed[EP93XX_CLK_USB];
|
||||
hw = devm_clk_hw_register_gate_parent_data(priv->dev, "ohci-platform", &pdata,
|
||||
0, priv->base + EP93XX_SYSCON_PWRCNT,
|
||||
EP93XX_SYSCON_PWRCNT_USH_EN, 0,
|
||||
&priv->lock);
|
||||
if (IS_ERR(hw))
|
||||
return PTR_ERR(hw);
|
||||
|
||||
priv->fixed[EP93XX_CLK_USB] = hw;
|
||||
|
||||
ddiv_pdata[0].index = 0; /* XTALI external clock */
|
||||
ddiv_pdata[1].hw = priv->fixed[EP93XX_CLK_PLL1];
|
||||
ddiv_pdata[2].hw = priv->fixed[EP93XX_CLK_PLL2];
|
||||
|
||||
/* touchscreen/ADC clock */
|
||||
idx = EP93XX_CLK_ADC - EP93XX_CLK_UART1;
|
||||
clk = &priv->reg[idx];
|
||||
clk->idx = idx;
|
||||
ret = ep93xx_register_div(clk, "ep93xx-adc", &xtali,
|
||||
EP93XX_SYSCON_KEYTCHCLKDIV,
|
||||
EP93XX_SYSCON_KEYTCHCLKDIV_TSEN,
|
||||
EP93XX_SYSCON_KEYTCHCLKDIV_ADIV,
|
||||
1,
|
||||
ep93xx_adc_divisors,
|
||||
ARRAY_SIZE(ep93xx_adc_divisors));
|
||||
|
||||
|
||||
/* keypad clock */
|
||||
idx = EP93XX_CLK_KEYPAD - EP93XX_CLK_UART1;
|
||||
clk = &priv->reg[idx];
|
||||
clk->idx = idx;
|
||||
ret = ep93xx_register_div(clk, "ep93xx-keypad", &xtali,
|
||||
EP93XX_SYSCON_KEYTCHCLKDIV,
|
||||
EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
|
||||
EP93XX_SYSCON_KEYTCHCLKDIV_KDIV,
|
||||
1,
|
||||
ep93xx_adc_divisors,
|
||||
ARRAY_SIZE(ep93xx_adc_divisors));
|
||||
|
||||
/*
|
||||
* On reset PDIV and VDIV is set to zero, while PDIV zero
|
||||
* means clock disable, VDIV shouldn't be zero.
|
||||
* So we set both video and i2s dividers to minimum.
|
||||
* ENA - Enable CLK divider.
|
||||
* PDIV - 00 - Disable clock
|
||||
* VDIV - at least 2
|
||||
*/
|
||||
|
||||
/* Check and enable video clk registers */
|
||||
regmap_read(priv->map, EP93XX_SYSCON_VIDCLKDIV, &value);
|
||||
value |= BIT(EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
|
||||
ep93xx_clk_write(priv, EP93XX_SYSCON_VIDCLKDIV, value);
|
||||
|
||||
/* Check and enable i2s clk registers */
|
||||
regmap_read(priv->map, EP93XX_SYSCON_I2SCLKDIV, &value);
|
||||
value |= BIT(EP93XX_SYSCON_CLKDIV_PDIV_SHIFT) | 2;
|
||||
|
||||
/*
|
||||
* Override the SAI_MSTR_CLK_CFG from the I2S block and use the
|
||||
* I2SClkDiv Register settings. LRCLK transitions on the falling SCLK
|
||||
* edge.
|
||||
*/
|
||||
value |= EP93XX_SYSCON_I2SCLKDIV_ORIDE | EP93XX_SYSCON_I2SCLKDIV_SPOL;
|
||||
ep93xx_clk_write(priv, EP93XX_SYSCON_I2SCLKDIV, value);
|
||||
|
||||
/* video clk */
|
||||
idx = EP93XX_CLK_VIDEO - EP93XX_CLK_UART1;
|
||||
clk = &priv->reg[idx];
|
||||
clk->idx = idx;
|
||||
ret = ep93xx_clk_register_ddiv(clk, "ep93xx-fb",
|
||||
ddiv_pdata, ARRAY_SIZE(ddiv_pdata),
|
||||
EP93XX_SYSCON_VIDCLKDIV,
|
||||
EP93XX_SYSCON_CLKDIV_ENABLE);
|
||||
|
||||
/* i2s clk */
|
||||
idx = EP93XX_CLK_I2S_MCLK - EP93XX_CLK_UART1;
|
||||
clk = &priv->reg[idx];
|
||||
clk->idx = idx;
|
||||
ret = ep93xx_clk_register_ddiv(clk, "mclk",
|
||||
ddiv_pdata, ARRAY_SIZE(ddiv_pdata),
|
||||
EP93XX_SYSCON_I2SCLKDIV,
|
||||
EP93XX_SYSCON_CLKDIV_ENABLE);
|
||||
|
||||
/* i2s sclk */
|
||||
idx = EP93XX_CLK_I2S_SCLK - EP93XX_CLK_UART1;
|
||||
clk = &priv->reg[idx];
|
||||
clk->idx = idx;
|
||||
pdata.hw = &priv->reg[EP93XX_CLK_I2S_MCLK - EP93XX_CLK_UART1].hw;
|
||||
ret = ep93xx_register_div(clk, "sclk", &pdata,
|
||||
EP93XX_SYSCON_I2SCLKDIV,
|
||||
EP93XX_SYSCON_I2SCLKDIV_SENA,
|
||||
16, /* EP93XX_I2SCLKDIV_SDIV_SHIFT */
|
||||
1, /* EP93XX_I2SCLKDIV_SDIV_WIDTH */
|
||||
ep93xx_sclk_divisors,
|
||||
ARRAY_SIZE(ep93xx_sclk_divisors));
|
||||
|
||||
/* i2s lrclk */
|
||||
idx = EP93XX_CLK_I2S_LRCLK - EP93XX_CLK_UART1;
|
||||
clk = &priv->reg[idx];
|
||||
clk->idx = idx;
|
||||
pdata.hw = &priv->reg[EP93XX_CLK_I2S_SCLK - EP93XX_CLK_UART1].hw;
|
||||
ret = ep93xx_register_div(clk, "lrclk", &pdata,
|
||||
EP93XX_SYSCON_I2SCLKDIV,
|
||||
EP93XX_SYSCON_I2SCLKDIV_SENA,
|
||||
17, /* EP93XX_I2SCLKDIV_LRDIV32_SHIFT */
|
||||
2, /* EP93XX_I2SCLKDIV_LRDIV32_WIDTH */
|
||||
ep93xx_lrclk_divisors,
|
||||
ARRAY_SIZE(ep93xx_lrclk_divisors));
|
||||
|
||||
/* IrDa clk uses same pattern but no init code presents in original clock driver */
|
||||
return devm_of_clk_add_hw_provider(priv->dev, of_clk_ep93xx_get, priv);
|
||||
}
|
||||
|
||||
static const struct auxiliary_device_id ep93xx_clk_ids[] = {
|
||||
{ .name = "soc_ep93xx.clk-ep93xx", .driver_data = 2, },
|
||||
{ .name = "soc_ep93xx.clk-ep93xx.e2", .driver_data = 1, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(auxiliary, ep93xx_clk_ids);
|
||||
|
||||
static struct auxiliary_driver ep93xx_clk_driver = {
|
||||
.probe = ep93xx_clk_probe,
|
||||
.id_table = ep93xx_clk_ids,
|
||||
};
|
||||
module_auxiliary_driver(ep93xx_clk_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Nikita Shubin <nikita.shubin@maquefel.me>");
|
||||
MODULE_DESCRIPTION("Clock control for Cirrus EP93xx chips");
|
@ -17,14 +17,15 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/of_dma.h>
|
||||
#include <linux/overflow.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/platform_data/dma-ep93xx.h>
|
||||
|
||||
#include "dmaengine.h"
|
||||
|
||||
/* M2P registers */
|
||||
@ -104,6 +105,31 @@
|
||||
#define DMA_MAX_CHAN_BYTES 0xffff
|
||||
#define DMA_MAX_CHAN_DESCRIPTORS 32
|
||||
|
||||
/*
|
||||
* M2P channels.
|
||||
*
|
||||
* Note that these values are also directly used for setting the PPALLOC
|
||||
* register.
|
||||
*/
|
||||
#define EP93XX_DMA_I2S1 0
|
||||
#define EP93XX_DMA_I2S2 1
|
||||
#define EP93XX_DMA_AAC1 2
|
||||
#define EP93XX_DMA_AAC2 3
|
||||
#define EP93XX_DMA_AAC3 4
|
||||
#define EP93XX_DMA_I2S3 5
|
||||
#define EP93XX_DMA_UART1 6
|
||||
#define EP93XX_DMA_UART2 7
|
||||
#define EP93XX_DMA_UART3 8
|
||||
#define EP93XX_DMA_IRDA 9
|
||||
/* M2M channels */
|
||||
#define EP93XX_DMA_SSP 10
|
||||
#define EP93XX_DMA_IDE 11
|
||||
|
||||
enum ep93xx_dma_type {
|
||||
M2P_DMA,
|
||||
M2M_DMA,
|
||||
};
|
||||
|
||||
struct ep93xx_dma_engine;
|
||||
static int ep93xx_dma_slave_config_write(struct dma_chan *chan,
|
||||
enum dma_transfer_direction dir,
|
||||
@ -129,11 +155,17 @@ struct ep93xx_dma_desc {
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
struct ep93xx_dma_chan_cfg {
|
||||
u8 port;
|
||||
enum dma_transfer_direction dir;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ep93xx_dma_chan - an EP93xx DMA M2P/M2M channel
|
||||
* @chan: dmaengine API channel
|
||||
* @edma: pointer to the engine device
|
||||
* @regs: memory mapped registers
|
||||
* @dma_cfg: channel number, direction
|
||||
* @irq: interrupt number of the channel
|
||||
* @clk: clock used by this channel
|
||||
* @tasklet: channel specific tasklet used for callbacks
|
||||
@ -157,14 +189,12 @@ struct ep93xx_dma_desc {
|
||||
* descriptor in the chain. When a descriptor is moved to the @active queue,
|
||||
* the first and chained descriptors are flattened into a single list.
|
||||
*
|
||||
* @chan.private holds pointer to &struct ep93xx_dma_data which contains
|
||||
* necessary channel configuration information. For memcpy channels this must
|
||||
* be %NULL.
|
||||
*/
|
||||
struct ep93xx_dma_chan {
|
||||
struct dma_chan chan;
|
||||
const struct ep93xx_dma_engine *edma;
|
||||
void __iomem *regs;
|
||||
struct ep93xx_dma_chan_cfg dma_cfg;
|
||||
int irq;
|
||||
struct clk *clk;
|
||||
struct tasklet_struct tasklet;
|
||||
@ -216,6 +246,11 @@ struct ep93xx_dma_engine {
|
||||
struct ep93xx_dma_chan channels[] __counted_by(num_channels);
|
||||
};
|
||||
|
||||
struct ep93xx_edma_data {
|
||||
u32 id;
|
||||
size_t num_channels;
|
||||
};
|
||||
|
||||
static inline struct device *chan2dev(struct ep93xx_dma_chan *edmac)
|
||||
{
|
||||
return &edmac->chan.dev->device;
|
||||
@ -226,6 +261,31 @@ static struct ep93xx_dma_chan *to_ep93xx_dma_chan(struct dma_chan *chan)
|
||||
return container_of(chan, struct ep93xx_dma_chan, chan);
|
||||
}
|
||||
|
||||
static inline bool ep93xx_dma_chan_is_m2p(struct dma_chan *chan)
|
||||
{
|
||||
if (device_is_compatible(chan->device->dev, "cirrus,ep9301-dma-m2p"))
|
||||
return true;
|
||||
|
||||
return !strcmp(dev_name(chan->device->dev), "ep93xx-dma-m2p");
|
||||
}
|
||||
|
||||
/*
|
||||
* ep93xx_dma_chan_direction - returns direction the channel can be used
|
||||
*
|
||||
* This function can be used in filter functions to find out whether the
|
||||
* channel supports given DMA direction. Only M2P channels have such
|
||||
* limitation, for M2M channels the direction is configurable.
|
||||
*/
|
||||
static inline enum dma_transfer_direction
|
||||
ep93xx_dma_chan_direction(struct dma_chan *chan)
|
||||
{
|
||||
if (!ep93xx_dma_chan_is_m2p(chan))
|
||||
return DMA_TRANS_NONE;
|
||||
|
||||
/* even channels are for TX, odd for RX */
|
||||
return (chan->chan_id % 2 == 0) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* ep93xx_dma_set_active - set new active descriptor chain
|
||||
* @edmac: channel
|
||||
@ -318,10 +378,9 @@ static void m2p_set_control(struct ep93xx_dma_chan *edmac, u32 control)
|
||||
|
||||
static int m2p_hw_setup(struct ep93xx_dma_chan *edmac)
|
||||
{
|
||||
struct ep93xx_dma_data *data = edmac->chan.private;
|
||||
u32 control;
|
||||
|
||||
writel(data->port & 0xf, edmac->regs + M2P_PPALLOC);
|
||||
writel(edmac->dma_cfg.port & 0xf, edmac->regs + M2P_PPALLOC);
|
||||
|
||||
control = M2P_CONTROL_CH_ERROR_INT | M2P_CONTROL_ICE
|
||||
| M2P_CONTROL_ENABLE;
|
||||
@ -458,16 +517,15 @@ static int m2p_hw_interrupt(struct ep93xx_dma_chan *edmac)
|
||||
|
||||
static int m2m_hw_setup(struct ep93xx_dma_chan *edmac)
|
||||
{
|
||||
const struct ep93xx_dma_data *data = edmac->chan.private;
|
||||
u32 control = 0;
|
||||
|
||||
if (!data) {
|
||||
if (edmac->dma_cfg.dir == DMA_MEM_TO_MEM) {
|
||||
/* This is memcpy channel, nothing to configure */
|
||||
writel(control, edmac->regs + M2M_CONTROL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (data->port) {
|
||||
switch (edmac->dma_cfg.port) {
|
||||
case EP93XX_DMA_SSP:
|
||||
/*
|
||||
* This was found via experimenting - anything less than 5
|
||||
@ -477,7 +535,7 @@ static int m2m_hw_setup(struct ep93xx_dma_chan *edmac)
|
||||
control = (5 << M2M_CONTROL_PWSC_SHIFT);
|
||||
control |= M2M_CONTROL_NO_HDSK;
|
||||
|
||||
if (data->direction == DMA_MEM_TO_DEV) {
|
||||
if (edmac->dma_cfg.dir == DMA_MEM_TO_DEV) {
|
||||
control |= M2M_CONTROL_DAH;
|
||||
control |= M2M_CONTROL_TM_TX;
|
||||
control |= M2M_CONTROL_RSS_SSPTX;
|
||||
@ -493,7 +551,7 @@ static int m2m_hw_setup(struct ep93xx_dma_chan *edmac)
|
||||
* This IDE part is totally untested. Values below are taken
|
||||
* from the EP93xx Users's Guide and might not be correct.
|
||||
*/
|
||||
if (data->direction == DMA_MEM_TO_DEV) {
|
||||
if (edmac->dma_cfg.dir == DMA_MEM_TO_DEV) {
|
||||
/* Worst case from the UG */
|
||||
control = (3 << M2M_CONTROL_PWSC_SHIFT);
|
||||
control |= M2M_CONTROL_DAH;
|
||||
@ -548,7 +606,6 @@ static void m2m_fill_desc(struct ep93xx_dma_chan *edmac)
|
||||
|
||||
static void m2m_hw_submit(struct ep93xx_dma_chan *edmac)
|
||||
{
|
||||
struct ep93xx_dma_data *data = edmac->chan.private;
|
||||
u32 control = readl(edmac->regs + M2M_CONTROL);
|
||||
|
||||
/*
|
||||
@ -574,7 +631,7 @@ static void m2m_hw_submit(struct ep93xx_dma_chan *edmac)
|
||||
control |= M2M_CONTROL_ENABLE;
|
||||
writel(control, edmac->regs + M2M_CONTROL);
|
||||
|
||||
if (!data) {
|
||||
if (edmac->dma_cfg.dir == DMA_MEM_TO_MEM) {
|
||||
/*
|
||||
* For memcpy channels the software trigger must be asserted
|
||||
* in order to start the memcpy operation.
|
||||
@ -636,7 +693,7 @@ static int m2m_hw_interrupt(struct ep93xx_dma_chan *edmac)
|
||||
*/
|
||||
if (ep93xx_dma_advance_active(edmac)) {
|
||||
m2m_fill_desc(edmac);
|
||||
if (done && !edmac->chan.private) {
|
||||
if (done && edmac->dma_cfg.dir == DMA_MEM_TO_MEM) {
|
||||
/* Software trigger for memcpy channel */
|
||||
control = readl(edmac->regs + M2M_CONTROL);
|
||||
control |= M2M_CONTROL_START;
|
||||
@ -867,25 +924,22 @@ static dma_cookie_t ep93xx_dma_tx_submit(struct dma_async_tx_descriptor *tx)
|
||||
static int ep93xx_dma_alloc_chan_resources(struct dma_chan *chan)
|
||||
{
|
||||
struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
|
||||
struct ep93xx_dma_data *data = chan->private;
|
||||
const char *name = dma_chan_name(chan);
|
||||
int ret, i;
|
||||
|
||||
/* Sanity check the channel parameters */
|
||||
if (!edmac->edma->m2m) {
|
||||
if (!data)
|
||||
if (edmac->dma_cfg.port < EP93XX_DMA_I2S1 ||
|
||||
edmac->dma_cfg.port > EP93XX_DMA_IRDA)
|
||||
return -EINVAL;
|
||||
if (data->port < EP93XX_DMA_I2S1 ||
|
||||
data->port > EP93XX_DMA_IRDA)
|
||||
return -EINVAL;
|
||||
if (data->direction != ep93xx_dma_chan_direction(chan))
|
||||
if (edmac->dma_cfg.dir != ep93xx_dma_chan_direction(chan))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (data) {
|
||||
switch (data->port) {
|
||||
if (edmac->dma_cfg.dir != DMA_MEM_TO_MEM) {
|
||||
switch (edmac->dma_cfg.port) {
|
||||
case EP93XX_DMA_SSP:
|
||||
case EP93XX_DMA_IDE:
|
||||
if (!is_slave_direction(data->direction))
|
||||
if (!is_slave_direction(edmac->dma_cfg.dir))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
@ -894,9 +948,6 @@ static int ep93xx_dma_alloc_chan_resources(struct dma_chan *chan)
|
||||
}
|
||||
}
|
||||
|
||||
if (data && data->name)
|
||||
name = data->name;
|
||||
|
||||
ret = clk_prepare_enable(edmac->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -1315,36 +1366,53 @@ static void ep93xx_dma_issue_pending(struct dma_chan *chan)
|
||||
ep93xx_dma_advance_work(to_ep93xx_dma_chan(chan));
|
||||
}
|
||||
|
||||
static int __init ep93xx_dma_probe(struct platform_device *pdev)
|
||||
static struct ep93xx_dma_engine *ep93xx_dma_of_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_dma_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
const struct ep93xx_edma_data *data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ep93xx_dma_engine *edma;
|
||||
struct dma_device *dma_dev;
|
||||
int ret, i;
|
||||
char dma_clk_name[5];
|
||||
int i;
|
||||
|
||||
edma = kzalloc(struct_size(edma, channels, pdata->num_channels), GFP_KERNEL);
|
||||
data = device_get_match_data(dev);
|
||||
if (!data)
|
||||
return ERR_PTR(dev_err_probe(dev, -ENODEV, "No device match found\n"));
|
||||
|
||||
edma = devm_kzalloc(dev, struct_size(edma, channels, data->num_channels),
|
||||
GFP_KERNEL);
|
||||
if (!edma)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
edma->m2m = data->id;
|
||||
edma->num_channels = data->num_channels;
|
||||
dma_dev = &edma->dma_dev;
|
||||
edma->m2m = platform_get_device_id(pdev)->driver_data;
|
||||
edma->num_channels = pdata->num_channels;
|
||||
|
||||
INIT_LIST_HEAD(&dma_dev->channels);
|
||||
for (i = 0; i < pdata->num_channels; i++) {
|
||||
const struct ep93xx_dma_chan_data *cdata = &pdata->channels[i];
|
||||
for (i = 0; i < edma->num_channels; i++) {
|
||||
struct ep93xx_dma_chan *edmac = &edma->channels[i];
|
||||
|
||||
edmac->chan.device = dma_dev;
|
||||
edmac->regs = cdata->base;
|
||||
edmac->irq = cdata->irq;
|
||||
edmac->regs = devm_platform_ioremap_resource(pdev, i);
|
||||
if (IS_ERR(edmac->regs))
|
||||
return edmac->regs;
|
||||
|
||||
edmac->irq = fwnode_irq_get(dev_fwnode(dev), i);
|
||||
if (edmac->irq < 0)
|
||||
return ERR_PTR(edmac->irq);
|
||||
|
||||
edmac->edma = edma;
|
||||
|
||||
edmac->clk = clk_get(NULL, cdata->name);
|
||||
if (edma->m2m)
|
||||
snprintf(dma_clk_name, sizeof(dma_clk_name), "m2m%u", i);
|
||||
else
|
||||
snprintf(dma_clk_name, sizeof(dma_clk_name), "m2p%u", i);
|
||||
|
||||
edmac->clk = devm_clk_get(dev, dma_clk_name);
|
||||
if (IS_ERR(edmac->clk)) {
|
||||
dev_warn(&pdev->dev, "failed to get clock for %s\n",
|
||||
cdata->name);
|
||||
continue;
|
||||
dev_err_probe(dev, PTR_ERR(edmac->clk),
|
||||
"no %s clock found\n", dma_clk_name);
|
||||
return ERR_CAST(edmac->clk);
|
||||
}
|
||||
|
||||
spin_lock_init(&edmac->lock);
|
||||
@ -1357,6 +1425,90 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev)
|
||||
&dma_dev->channels);
|
||||
}
|
||||
|
||||
return edma;
|
||||
}
|
||||
|
||||
static bool ep93xx_m2p_dma_filter(struct dma_chan *chan, void *filter_param)
|
||||
{
|
||||
struct ep93xx_dma_chan *echan = to_ep93xx_dma_chan(chan);
|
||||
struct ep93xx_dma_chan_cfg *cfg = filter_param;
|
||||
|
||||
if (cfg->dir != ep93xx_dma_chan_direction(chan))
|
||||
return false;
|
||||
|
||||
echan->dma_cfg = *cfg;
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct dma_chan *ep93xx_m2p_dma_of_xlate(struct of_phandle_args *dma_spec,
|
||||
struct of_dma *ofdma)
|
||||
{
|
||||
struct ep93xx_dma_engine *edma = ofdma->of_dma_data;
|
||||
dma_cap_mask_t mask = edma->dma_dev.cap_mask;
|
||||
struct ep93xx_dma_chan_cfg dma_cfg;
|
||||
u8 port = dma_spec->args[0];
|
||||
u8 direction = dma_spec->args[1];
|
||||
|
||||
if (port > EP93XX_DMA_IRDA)
|
||||
return NULL;
|
||||
|
||||
if (!is_slave_direction(direction))
|
||||
return NULL;
|
||||
|
||||
dma_cfg.port = port;
|
||||
dma_cfg.dir = direction;
|
||||
|
||||
return __dma_request_channel(&mask, ep93xx_m2p_dma_filter, &dma_cfg, ofdma->of_node);
|
||||
}
|
||||
|
||||
static bool ep93xx_m2m_dma_filter(struct dma_chan *chan, void *filter_param)
|
||||
{
|
||||
struct ep93xx_dma_chan *echan = to_ep93xx_dma_chan(chan);
|
||||
struct ep93xx_dma_chan_cfg *cfg = filter_param;
|
||||
|
||||
echan->dma_cfg = *cfg;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct dma_chan *ep93xx_m2m_dma_of_xlate(struct of_phandle_args *dma_spec,
|
||||
struct of_dma *ofdma)
|
||||
{
|
||||
struct ep93xx_dma_engine *edma = ofdma->of_dma_data;
|
||||
dma_cap_mask_t mask = edma->dma_dev.cap_mask;
|
||||
struct ep93xx_dma_chan_cfg dma_cfg;
|
||||
u8 port = dma_spec->args[0];
|
||||
u8 direction = dma_spec->args[1];
|
||||
|
||||
if (!is_slave_direction(direction))
|
||||
return NULL;
|
||||
|
||||
switch (port) {
|
||||
case EP93XX_DMA_SSP:
|
||||
case EP93XX_DMA_IDE:
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dma_cfg.port = port;
|
||||
dma_cfg.dir = direction;
|
||||
|
||||
return __dma_request_channel(&mask, ep93xx_m2m_dma_filter, &dma_cfg, ofdma->of_node);
|
||||
}
|
||||
|
||||
static int ep93xx_dma_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_dma_engine *edma;
|
||||
struct dma_device *dma_dev;
|
||||
int ret;
|
||||
|
||||
edma = ep93xx_dma_of_probe(pdev);
|
||||
if (IS_ERR(edma))
|
||||
return PTR_ERR(edma);
|
||||
|
||||
dma_dev = &edma->dma_dev;
|
||||
|
||||
dma_cap_zero(dma_dev->cap_mask);
|
||||
dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
|
||||
dma_cap_set(DMA_CYCLIC, dma_dev->cap_mask);
|
||||
@ -1393,21 +1545,46 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
ret = dma_async_device_register(dma_dev);
|
||||
if (unlikely(ret)) {
|
||||
for (i = 0; i < edma->num_channels; i++) {
|
||||
struct ep93xx_dma_chan *edmac = &edma->channels[i];
|
||||
if (!IS_ERR_OR_NULL(edmac->clk))
|
||||
clk_put(edmac->clk);
|
||||
}
|
||||
kfree(edma);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (edma->m2m) {
|
||||
ret = of_dma_controller_register(pdev->dev.of_node, ep93xx_m2m_dma_of_xlate,
|
||||
edma);
|
||||
} else {
|
||||
dev_info(dma_dev->dev, "EP93xx M2%s DMA ready\n",
|
||||
edma->m2m ? "M" : "P");
|
||||
ret = of_dma_controller_register(pdev->dev.of_node, ep93xx_m2p_dma_of_xlate,
|
||||
edma);
|
||||
}
|
||||
if (ret)
|
||||
goto err_dma_unregister;
|
||||
|
||||
dev_info(dma_dev->dev, "EP93xx M2%s DMA ready\n", edma->m2m ? "M" : "P");
|
||||
|
||||
return 0;
|
||||
|
||||
err_dma_unregister:
|
||||
dma_async_device_unregister(dma_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct ep93xx_edma_data edma_m2p = {
|
||||
.id = M2P_DMA,
|
||||
.num_channels = 10,
|
||||
};
|
||||
|
||||
static const struct ep93xx_edma_data edma_m2m = {
|
||||
.id = M2M_DMA,
|
||||
.num_channels = 2,
|
||||
};
|
||||
|
||||
static const struct of_device_id ep93xx_dma_of_ids[] = {
|
||||
{ .compatible = "cirrus,ep9301-dma-m2p", .data = &edma_m2p },
|
||||
{ .compatible = "cirrus,ep9301-dma-m2m", .data = &edma_m2m },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ep93xx_dma_of_ids);
|
||||
|
||||
static const struct platform_device_id ep93xx_dma_driver_ids[] = {
|
||||
{ "ep93xx-dma-m2p", 0 },
|
||||
{ "ep93xx-dma-m2m", 1 },
|
||||
@ -1417,15 +1594,13 @@ static const struct platform_device_id ep93xx_dma_driver_ids[] = {
|
||||
static struct platform_driver ep93xx_dma_driver = {
|
||||
.driver = {
|
||||
.name = "ep93xx-dma",
|
||||
.of_match_table = ep93xx_dma_of_ids,
|
||||
},
|
||||
.id_table = ep93xx_dma_driver_ids,
|
||||
.probe = ep93xx_dma_probe,
|
||||
};
|
||||
|
||||
static int __init ep93xx_dma_module_init(void)
|
||||
{
|
||||
return platform_driver_probe(&ep93xx_dma_driver, ep93xx_dma_probe);
|
||||
}
|
||||
subsys_initcall(ep93xx_dma_module_init);
|
||||
module_platform_driver(ep93xx_dma_driver);
|
||||
|
||||
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
|
||||
MODULE_DESCRIPTION("EP93xx DMA driver");
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/slab.h>
|
||||
@ -19,29 +20,8 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#define EP93XX_GPIO_F_INT_STATUS 0x5c
|
||||
#define EP93XX_GPIO_A_INT_STATUS 0xa0
|
||||
#define EP93XX_GPIO_B_INT_STATUS 0xbc
|
||||
|
||||
/* Maximum value for gpio line identifiers */
|
||||
#define EP93XX_GPIO_LINE_MAX 63
|
||||
|
||||
/* Number of GPIO chips in EP93XX */
|
||||
#define EP93XX_GPIO_CHIP_NUM 8
|
||||
|
||||
/* Maximum value for irq capable line identifiers */
|
||||
#define EP93XX_GPIO_LINE_MAX_IRQ 23
|
||||
|
||||
#define EP93XX_GPIO_A_IRQ_BASE 64
|
||||
#define EP93XX_GPIO_B_IRQ_BASE 72
|
||||
/*
|
||||
* Static mapping of GPIO bank F IRQS:
|
||||
* F0..F7 (16..24) to irq 80..87.
|
||||
*/
|
||||
#define EP93XX_GPIO_F_IRQ_BASE 80
|
||||
|
||||
struct ep93xx_gpio_irq_chip {
|
||||
u8 irq_offset;
|
||||
void __iomem *base;
|
||||
u8 int_unmasked;
|
||||
u8 int_enabled;
|
||||
u8 int_type1;
|
||||
@ -50,15 +30,11 @@ struct ep93xx_gpio_irq_chip {
|
||||
};
|
||||
|
||||
struct ep93xx_gpio_chip {
|
||||
void __iomem *base;
|
||||
struct gpio_chip gc;
|
||||
struct ep93xx_gpio_irq_chip *eic;
|
||||
};
|
||||
|
||||
struct ep93xx_gpio {
|
||||
void __iomem *base;
|
||||
struct ep93xx_gpio_chip gc[EP93XX_GPIO_CHIP_NUM];
|
||||
};
|
||||
|
||||
#define to_ep93xx_gpio_chip(x) container_of(x, struct ep93xx_gpio_chip, gc)
|
||||
|
||||
static struct ep93xx_gpio_irq_chip *to_ep93xx_gpio_irq_chip(struct gpio_chip *gc)
|
||||
@ -79,25 +55,23 @@ static struct ep93xx_gpio_irq_chip *to_ep93xx_gpio_irq_chip(struct gpio_chip *gc
|
||||
#define EP93XX_INT_RAW_STATUS_OFFSET 0x14
|
||||
#define EP93XX_INT_DEBOUNCE_OFFSET 0x18
|
||||
|
||||
static void ep93xx_gpio_update_int_params(struct ep93xx_gpio *epg,
|
||||
struct ep93xx_gpio_irq_chip *eic)
|
||||
static void ep93xx_gpio_update_int_params(struct ep93xx_gpio_irq_chip *eic)
|
||||
{
|
||||
writeb_relaxed(0, epg->base + eic->irq_offset + EP93XX_INT_EN_OFFSET);
|
||||
writeb_relaxed(0, eic->base + EP93XX_INT_EN_OFFSET);
|
||||
|
||||
writeb_relaxed(eic->int_type2,
|
||||
epg->base + eic->irq_offset + EP93XX_INT_TYPE2_OFFSET);
|
||||
eic->base + EP93XX_INT_TYPE2_OFFSET);
|
||||
|
||||
writeb_relaxed(eic->int_type1,
|
||||
epg->base + eic->irq_offset + EP93XX_INT_TYPE1_OFFSET);
|
||||
eic->base + EP93XX_INT_TYPE1_OFFSET);
|
||||
|
||||
writeb_relaxed(eic->int_unmasked & eic->int_enabled,
|
||||
epg->base + eic->irq_offset + EP93XX_INT_EN_OFFSET);
|
||||
eic->base + EP93XX_INT_EN_OFFSET);
|
||||
}
|
||||
|
||||
static void ep93xx_gpio_int_debounce(struct gpio_chip *gc,
|
||||
unsigned int offset, bool enable)
|
||||
{
|
||||
struct ep93xx_gpio *epg = gpiochip_get_data(gc);
|
||||
struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
|
||||
int port_mask = BIT(offset);
|
||||
|
||||
@ -106,53 +80,43 @@ static void ep93xx_gpio_int_debounce(struct gpio_chip *gc,
|
||||
else
|
||||
eic->int_debounce &= ~port_mask;
|
||||
|
||||
writeb(eic->int_debounce,
|
||||
epg->base + eic->irq_offset + EP93XX_INT_DEBOUNCE_OFFSET);
|
||||
writeb(eic->int_debounce, eic->base + EP93XX_INT_DEBOUNCE_OFFSET);
|
||||
}
|
||||
|
||||
static void ep93xx_gpio_ab_irq_handler(struct irq_desc *desc)
|
||||
static u32 ep93xx_gpio_ab_irq_handler(struct gpio_chip *gc)
|
||||
{
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct ep93xx_gpio *epg = gpiochip_get_data(gc);
|
||||
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||
struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
|
||||
unsigned long stat;
|
||||
int offset;
|
||||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
|
||||
/*
|
||||
* Dispatch the IRQs to the irqdomain of each A and B
|
||||
* gpiochip irqdomains depending on what has fired.
|
||||
* The tricky part is that the IRQ line is shared
|
||||
* between bank A and B and each has their own gpiochip.
|
||||
*/
|
||||
stat = readb(epg->base + EP93XX_GPIO_A_INT_STATUS);
|
||||
stat = readb(eic->base + EP93XX_INT_STATUS_OFFSET);
|
||||
for_each_set_bit(offset, &stat, 8)
|
||||
generic_handle_domain_irq(epg->gc[0].gc.irq.domain,
|
||||
offset);
|
||||
generic_handle_domain_irq(gc->irq.domain, offset);
|
||||
|
||||
stat = readb(epg->base + EP93XX_GPIO_B_INT_STATUS);
|
||||
for_each_set_bit(offset, &stat, 8)
|
||||
generic_handle_domain_irq(epg->gc[1].gc.irq.domain,
|
||||
offset);
|
||||
return stat;
|
||||
}
|
||||
|
||||
chained_irq_exit(irqchip, desc);
|
||||
static irqreturn_t ep93xx_ab_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
return IRQ_RETVAL(ep93xx_gpio_ab_irq_handler(dev_id));
|
||||
}
|
||||
|
||||
static void ep93xx_gpio_f_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
/*
|
||||
* map discontiguous hw irq range to continuous sw irq range:
|
||||
*
|
||||
* IRQ_EP93XX_GPIO{0..7}MUX -> EP93XX_GPIO_LINE_F{0..7}
|
||||
*/
|
||||
struct irq_chip *irqchip = irq_desc_get_chip(desc);
|
||||
unsigned int irq = irq_desc_get_irq(desc);
|
||||
int port_f_idx = (irq & 7) ^ 4; /* {20..23,48..51} -> {0..7} */
|
||||
int gpio_irq = EP93XX_GPIO_F_IRQ_BASE + port_f_idx;
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct gpio_irq_chip *gic = &gc->irq;
|
||||
unsigned int parent = irq_desc_get_irq(desc);
|
||||
unsigned int i;
|
||||
|
||||
chained_irq_enter(irqchip, desc);
|
||||
generic_handle_irq(gpio_irq);
|
||||
for (i = 0; i < gic->num_parents; i++)
|
||||
if (gic->parents[i] == parent)
|
||||
break;
|
||||
|
||||
if (i < gic->num_parents)
|
||||
generic_handle_domain_irq(gc->irq.domain, i);
|
||||
|
||||
chained_irq_exit(irqchip, desc);
|
||||
}
|
||||
|
||||
@ -160,54 +124,53 @@ static void ep93xx_gpio_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
|
||||
struct ep93xx_gpio *epg = gpiochip_get_data(gc);
|
||||
int port_mask = BIT(d->irq & 7);
|
||||
int port_mask = BIT(irqd_to_hwirq(d));
|
||||
|
||||
if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH) {
|
||||
eic->int_type2 ^= port_mask; /* switch edge direction */
|
||||
ep93xx_gpio_update_int_params(epg, eic);
|
||||
ep93xx_gpio_update_int_params(eic);
|
||||
}
|
||||
|
||||
writeb(port_mask, epg->base + eic->irq_offset + EP93XX_INT_EOI_OFFSET);
|
||||
writeb(port_mask, eic->base + EP93XX_INT_EOI_OFFSET);
|
||||
}
|
||||
|
||||
static void ep93xx_gpio_irq_mask_ack(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
|
||||
struct ep93xx_gpio *epg = gpiochip_get_data(gc);
|
||||
int port_mask = BIT(d->irq & 7);
|
||||
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||
int port_mask = BIT(hwirq);
|
||||
|
||||
if (irqd_get_trigger_type(d) == IRQ_TYPE_EDGE_BOTH)
|
||||
eic->int_type2 ^= port_mask; /* switch edge direction */
|
||||
|
||||
eic->int_unmasked &= ~port_mask;
|
||||
ep93xx_gpio_update_int_params(epg, eic);
|
||||
ep93xx_gpio_update_int_params(eic);
|
||||
|
||||
writeb(port_mask, epg->base + eic->irq_offset + EP93XX_INT_EOI_OFFSET);
|
||||
gpiochip_disable_irq(gc, irqd_to_hwirq(d));
|
||||
writeb(port_mask, eic->base + EP93XX_INT_EOI_OFFSET);
|
||||
gpiochip_disable_irq(gc, hwirq);
|
||||
}
|
||||
|
||||
static void ep93xx_gpio_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
|
||||
struct ep93xx_gpio *epg = gpiochip_get_data(gc);
|
||||
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||
|
||||
eic->int_unmasked &= ~BIT(d->irq & 7);
|
||||
ep93xx_gpio_update_int_params(epg, eic);
|
||||
gpiochip_disable_irq(gc, irqd_to_hwirq(d));
|
||||
eic->int_unmasked &= ~BIT(hwirq);
|
||||
ep93xx_gpio_update_int_params(eic);
|
||||
gpiochip_disable_irq(gc, hwirq);
|
||||
}
|
||||
|
||||
static void ep93xx_gpio_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
|
||||
struct ep93xx_gpio *epg = gpiochip_get_data(gc);
|
||||
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||
|
||||
gpiochip_enable_irq(gc, irqd_to_hwirq(d));
|
||||
eic->int_unmasked |= BIT(d->irq & 7);
|
||||
ep93xx_gpio_update_int_params(epg, eic);
|
||||
gpiochip_enable_irq(gc, hwirq);
|
||||
eic->int_unmasked |= BIT(hwirq);
|
||||
ep93xx_gpio_update_int_params(eic);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -219,12 +182,11 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct ep93xx_gpio_irq_chip *eic = to_ep93xx_gpio_irq_chip(gc);
|
||||
struct ep93xx_gpio *epg = gpiochip_get_data(gc);
|
||||
int offset = d->irq & 7;
|
||||
int port_mask = BIT(offset);
|
||||
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||
int port_mask = BIT(hwirq);
|
||||
irq_flow_handler_t handler;
|
||||
|
||||
gc->direction_input(gc, offset);
|
||||
gc->direction_input(gc, hwirq);
|
||||
|
||||
switch (type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
@ -250,7 +212,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
eic->int_type1 |= port_mask;
|
||||
/* set initial polarity based on current input level */
|
||||
if (gc->get(gc, offset))
|
||||
if (gc->get(gc, hwirq))
|
||||
eic->int_type2 &= ~port_mask; /* falling */
|
||||
else
|
||||
eic->int_type2 |= port_mask; /* rising */
|
||||
@ -264,51 +226,11 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type)
|
||||
|
||||
eic->int_enabled |= port_mask;
|
||||
|
||||
ep93xx_gpio_update_int_params(epg, eic);
|
||||
ep93xx_gpio_update_int_params(eic);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* gpiolib interface for EP93xx on-chip GPIOs
|
||||
*************************************************************************/
|
||||
struct ep93xx_gpio_bank {
|
||||
const char *label;
|
||||
int data;
|
||||
int dir;
|
||||
int irq;
|
||||
int base;
|
||||
bool has_irq;
|
||||
bool has_hierarchical_irq;
|
||||
unsigned int irq_base;
|
||||
};
|
||||
|
||||
#define EP93XX_GPIO_BANK(_label, _data, _dir, _irq, _base, _has_irq, _has_hier, _irq_base) \
|
||||
{ \
|
||||
.label = _label, \
|
||||
.data = _data, \
|
||||
.dir = _dir, \
|
||||
.irq = _irq, \
|
||||
.base = _base, \
|
||||
.has_irq = _has_irq, \
|
||||
.has_hierarchical_irq = _has_hier, \
|
||||
.irq_base = _irq_base, \
|
||||
}
|
||||
|
||||
static struct ep93xx_gpio_bank ep93xx_gpio_banks[] = {
|
||||
/* Bank A has 8 IRQs */
|
||||
EP93XX_GPIO_BANK("A", 0x00, 0x10, 0x90, 0, true, false, EP93XX_GPIO_A_IRQ_BASE),
|
||||
/* Bank B has 8 IRQs */
|
||||
EP93XX_GPIO_BANK("B", 0x04, 0x14, 0xac, 8, true, false, EP93XX_GPIO_B_IRQ_BASE),
|
||||
EP93XX_GPIO_BANK("C", 0x08, 0x18, 0x00, 40, false, false, 0),
|
||||
EP93XX_GPIO_BANK("D", 0x0c, 0x1c, 0x00, 24, false, false, 0),
|
||||
EP93XX_GPIO_BANK("E", 0x20, 0x24, 0x00, 32, false, false, 0),
|
||||
/* Bank F has 8 IRQs */
|
||||
EP93XX_GPIO_BANK("F", 0x30, 0x34, 0x4c, 16, false, true, EP93XX_GPIO_F_IRQ_BASE),
|
||||
EP93XX_GPIO_BANK("G", 0x38, 0x3c, 0x00, 48, false, false, 0),
|
||||
EP93XX_GPIO_BANK("H", 0x40, 0x44, 0x00, 56, false, false, 0),
|
||||
};
|
||||
|
||||
static int ep93xx_gpio_set_config(struct gpio_chip *gc, unsigned offset,
|
||||
unsigned long config)
|
||||
{
|
||||
@ -342,115 +264,112 @@ static const struct irq_chip gpio_eic_irq_chip = {
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int ep93xx_gpio_add_bank(struct ep93xx_gpio_chip *egc,
|
||||
struct platform_device *pdev,
|
||||
struct ep93xx_gpio *epg,
|
||||
struct ep93xx_gpio_bank *bank)
|
||||
static int ep93xx_setup_irqs(struct platform_device *pdev,
|
||||
struct ep93xx_gpio_chip *egc)
|
||||
{
|
||||
void __iomem *data = epg->base + bank->data;
|
||||
void __iomem *dir = epg->base + bank->dir;
|
||||
struct gpio_chip *gc = &egc->gc;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct gpio_irq_chip *girq;
|
||||
int err;
|
||||
struct gpio_irq_chip *girq = &gc->irq;
|
||||
int ret, irq, i;
|
||||
void __iomem *intr;
|
||||
|
||||
err = bgpio_init(gc, dev, 1, data, NULL, NULL, dir, NULL, 0);
|
||||
if (err)
|
||||
return err;
|
||||
intr = devm_platform_ioremap_resource_byname(pdev, "intr");
|
||||
if (IS_ERR(intr))
|
||||
return PTR_ERR(intr);
|
||||
|
||||
gc->label = bank->label;
|
||||
gc->base = bank->base;
|
||||
|
||||
girq = &gc->irq;
|
||||
if (bank->has_irq || bank->has_hierarchical_irq) {
|
||||
gc->set_config = ep93xx_gpio_set_config;
|
||||
egc->eic = devm_kcalloc(dev, 1,
|
||||
sizeof(*egc->eic),
|
||||
GFP_KERNEL);
|
||||
if (!egc->eic)
|
||||
return -ENOMEM;
|
||||
egc->eic->irq_offset = bank->irq;
|
||||
gpio_irq_chip_set_chip(girq, &gpio_eic_irq_chip);
|
||||
}
|
||||
|
||||
if (bank->has_irq) {
|
||||
int ab_parent_irq = platform_get_irq(pdev, 0);
|
||||
|
||||
girq->parent_handler = ep93xx_gpio_ab_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(dev, girq->num_parents,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_level_irq;
|
||||
girq->parents[0] = ab_parent_irq;
|
||||
girq->first = bank->irq_base;
|
||||
}
|
||||
|
||||
/* Only bank F has especially funky IRQ handling */
|
||||
if (bank->has_hierarchical_irq) {
|
||||
int gpio_irq;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* FIXME: convert this to use hierarchical IRQ support!
|
||||
* this requires fixing the root irqchip to be hierarchical.
|
||||
*/
|
||||
girq->parent_handler = ep93xx_gpio_f_irq_handler;
|
||||
girq->num_parents = 8;
|
||||
girq->parents = devm_kcalloc(dev, girq->num_parents,
|
||||
sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
/* Pick resources 1..8 for these IRQs */
|
||||
for (i = 0; i < girq->num_parents; i++) {
|
||||
girq->parents[i] = platform_get_irq(pdev, i + 1);
|
||||
gpio_irq = bank->irq_base + i;
|
||||
irq_set_chip_data(gpio_irq, &epg->gc[5]);
|
||||
irq_set_chip_and_handler(gpio_irq,
|
||||
girq->chip,
|
||||
handle_level_irq);
|
||||
irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST);
|
||||
}
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_level_irq;
|
||||
girq->first = bank->irq_base;
|
||||
}
|
||||
|
||||
return devm_gpiochip_add_data(dev, gc, epg);
|
||||
}
|
||||
|
||||
static int ep93xx_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_gpio *epg;
|
||||
int i;
|
||||
|
||||
epg = devm_kzalloc(&pdev->dev, sizeof(*epg), GFP_KERNEL);
|
||||
if (!epg)
|
||||
gc->set_config = ep93xx_gpio_set_config;
|
||||
egc->eic = devm_kzalloc(dev, sizeof(*egc->eic), GFP_KERNEL);
|
||||
if (!egc->eic)
|
||||
return -ENOMEM;
|
||||
|
||||
epg->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(epg->base))
|
||||
return PTR_ERR(epg->base);
|
||||
egc->eic->base = intr;
|
||||
gpio_irq_chip_set_chip(girq, &gpio_eic_irq_chip);
|
||||
girq->num_parents = platform_irq_count(pdev);
|
||||
if (girq->num_parents == 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ep93xx_gpio_banks); i++) {
|
||||
struct ep93xx_gpio_chip *gc = &epg->gc[i];
|
||||
struct ep93xx_gpio_bank *bank = &ep93xx_gpio_banks[i];
|
||||
girq->parents = devm_kcalloc(dev, girq->num_parents, sizeof(*girq->parents),
|
||||
GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ep93xx_gpio_add_bank(gc, pdev, epg, bank))
|
||||
dev_warn(&pdev->dev, "Unable to add gpio bank %s\n",
|
||||
bank->label);
|
||||
if (girq->num_parents == 1) { /* A/B irqchips */
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
ret = devm_request_irq(dev, irq, ep93xx_ab_irq_handler,
|
||||
IRQF_SHARED, gc->label, gc);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "requesting IRQ: %d\n", irq);
|
||||
|
||||
girq->parents[0] = irq;
|
||||
} else { /* F irqchip */
|
||||
girq->parent_handler = ep93xx_gpio_f_irq_handler;
|
||||
|
||||
for (i = 0; i < girq->num_parents; i++) {
|
||||
irq = platform_get_irq_optional(pdev, i);
|
||||
if (irq < 0)
|
||||
continue;
|
||||
|
||||
girq->parents[i] = irq;
|
||||
}
|
||||
|
||||
girq->map = girq->parents;
|
||||
}
|
||||
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
/* TODO: replace with handle_bad_irq() once we are fully hierarchical */
|
||||
girq->handler = handle_simple_irq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ep93xx_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_gpio_chip *egc;
|
||||
struct gpio_chip *gc;
|
||||
void __iomem *data;
|
||||
void __iomem *dir;
|
||||
int ret;
|
||||
|
||||
egc = devm_kzalloc(&pdev->dev, sizeof(*egc), GFP_KERNEL);
|
||||
if (!egc)
|
||||
return -ENOMEM;
|
||||
|
||||
data = devm_platform_ioremap_resource_byname(pdev, "data");
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
dir = devm_platform_ioremap_resource_byname(pdev, "dir");
|
||||
if (IS_ERR(dir))
|
||||
return PTR_ERR(dir);
|
||||
|
||||
gc = &egc->gc;
|
||||
ret = bgpio_init(gc, &pdev->dev, 1, data, NULL, NULL, dir, NULL, 0);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "unable to init generic GPIO\n");
|
||||
|
||||
gc->label = dev_name(&pdev->dev);
|
||||
if (platform_irq_count(pdev) > 0) {
|
||||
dev_dbg(&pdev->dev, "setting up irqs for %s\n", dev_name(&pdev->dev));
|
||||
ret = ep93xx_setup_irqs(pdev, egc);
|
||||
if (ret)
|
||||
dev_err_probe(&pdev->dev, ret, "setup irqs failed");
|
||||
}
|
||||
|
||||
return devm_gpiochip_add_data(&pdev->dev, gc, egc);
|
||||
}
|
||||
|
||||
static const struct of_device_id ep93xx_gpio_match[] = {
|
||||
{ .compatible = "cirrus,ep9301-gpio" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver ep93xx_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "gpio-ep93xx",
|
||||
.of_match_table = ep93xx_gpio_match,
|
||||
},
|
||||
.probe = ep93xx_gpio_probe,
|
||||
};
|
||||
|
@ -6,20 +6,13 @@
|
||||
*
|
||||
* Based on the pxa27x matrix keypad controller by Rodolfo Giometti.
|
||||
*
|
||||
* NOTE:
|
||||
*
|
||||
* The 3-key reset is triggered by pressing the 3 keys in
|
||||
* Row 0, Columns 2, 4, and 7 at the same time. This action can
|
||||
* be disabled by setting the EP93XX_KEYPAD_DISABLE_3_KEY flag.
|
||||
*
|
||||
* Normal operation for the matrix does not autorepeat the key press.
|
||||
* This action can be enabled by setting the EP93XX_KEYPAD_AUTOREPEAT
|
||||
* flag.
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
@ -27,7 +20,6 @@
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/soc/cirrus/ep93xx.h>
|
||||
#include <linux/platform_data/keypad-ep93xx.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
|
||||
/*
|
||||
@ -61,12 +53,16 @@
|
||||
#define KEY_REG_KEY1_MASK GENMASK(5, 0)
|
||||
#define KEY_REG_KEY1_SHIFT 0
|
||||
|
||||
#define EP93XX_MATRIX_ROWS (8)
|
||||
#define EP93XX_MATRIX_COLS (8)
|
||||
|
||||
#define EP93XX_MATRIX_SIZE (EP93XX_MATRIX_ROWS * EP93XX_MATRIX_COLS)
|
||||
|
||||
struct ep93xx_keypad {
|
||||
struct ep93xx_keypad_platform_data *pdata;
|
||||
struct input_dev *input_dev;
|
||||
struct clk *clk;
|
||||
unsigned int debounce;
|
||||
u16 prescale;
|
||||
|
||||
void __iomem *mmio_base;
|
||||
|
||||
@ -133,23 +129,11 @@ static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id)
|
||||
|
||||
static void ep93xx_keypad_config(struct ep93xx_keypad *keypad)
|
||||
{
|
||||
struct ep93xx_keypad_platform_data *pdata = keypad->pdata;
|
||||
unsigned int val = 0;
|
||||
|
||||
clk_set_rate(keypad->clk, pdata->clk_rate);
|
||||
val |= (keypad->debounce << KEY_INIT_DBNC_SHIFT) & KEY_INIT_DBNC_MASK;
|
||||
|
||||
if (pdata->flags & EP93XX_KEYPAD_DISABLE_3_KEY)
|
||||
val |= KEY_INIT_DIS3KY;
|
||||
if (pdata->flags & EP93XX_KEYPAD_DIAG_MODE)
|
||||
val |= KEY_INIT_DIAG;
|
||||
if (pdata->flags & EP93XX_KEYPAD_BACK_DRIVE)
|
||||
val |= KEY_INIT_BACK;
|
||||
if (pdata->flags & EP93XX_KEYPAD_TEST_MODE)
|
||||
val |= KEY_INIT_T2;
|
||||
|
||||
val |= ((pdata->debounce << KEY_INIT_DBNC_SHIFT) & KEY_INIT_DBNC_MASK);
|
||||
|
||||
val |= ((pdata->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK);
|
||||
val |= (keypad->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK;
|
||||
|
||||
__raw_writel(val, keypad->mmio_base + KEY_INIT);
|
||||
}
|
||||
@ -220,17 +204,10 @@ static int ep93xx_keypad_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(ep93xx_keypad_pm_ops,
|
||||
ep93xx_keypad_suspend, ep93xx_keypad_resume);
|
||||
|
||||
static void ep93xx_keypad_release_gpio_action(void *_pdev)
|
||||
{
|
||||
struct platform_device *pdev = _pdev;
|
||||
|
||||
ep93xx_keypad_release_gpio(pdev);
|
||||
}
|
||||
|
||||
static int ep93xx_keypad_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ep93xx_keypad *keypad;
|
||||
const struct matrix_keymap_data *keymap_data;
|
||||
struct input_dev *input_dev;
|
||||
int err;
|
||||
|
||||
@ -238,14 +215,6 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
|
||||
if (!keypad)
|
||||
return -ENOMEM;
|
||||
|
||||
keypad->pdata = dev_get_platdata(&pdev->dev);
|
||||
if (!keypad->pdata)
|
||||
return -EINVAL;
|
||||
|
||||
keymap_data = keypad->pdata->keymap_data;
|
||||
if (!keymap_data)
|
||||
return -EINVAL;
|
||||
|
||||
keypad->irq = platform_get_irq(pdev, 0);
|
||||
if (keypad->irq < 0)
|
||||
return keypad->irq;
|
||||
@ -254,19 +223,13 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(keypad->mmio_base))
|
||||
return PTR_ERR(keypad->mmio_base);
|
||||
|
||||
err = ep93xx_keypad_acquire_gpio(pdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_add_action_or_reset(&pdev->dev,
|
||||
ep93xx_keypad_release_gpio_action, pdev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
keypad->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(keypad->clk))
|
||||
return PTR_ERR(keypad->clk);
|
||||
|
||||
device_property_read_u32(dev, "debounce-delay-ms", &keypad->debounce);
|
||||
device_property_read_u16(dev, "cirrus,prescale", &keypad->prescale);
|
||||
|
||||
input_dev = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
@ -278,13 +241,13 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
|
||||
input_dev->open = ep93xx_keypad_open;
|
||||
input_dev->close = ep93xx_keypad_close;
|
||||
|
||||
err = matrix_keypad_build_keymap(keymap_data, NULL,
|
||||
err = matrix_keypad_build_keymap(NULL, NULL,
|
||||
EP93XX_MATRIX_ROWS, EP93XX_MATRIX_COLS,
|
||||
keypad->keycodes, input_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT)
|
||||
if (device_property_read_bool(&pdev->dev, "autorepeat"))
|
||||
__set_bit(EV_REP, input_dev->evbit);
|
||||
input_set_drvdata(input_dev, keypad);
|
||||
|
||||
@ -313,10 +276,17 @@ static void ep93xx_keypad_remove(struct platform_device *pdev)
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id ep93xx_keypad_of_ids[] = {
|
||||
{ .compatible = "cirrus,ep9307-keypad" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ep93xx_keypad_of_ids);
|
||||
|
||||
static struct platform_driver ep93xx_keypad_driver = {
|
||||
.driver = {
|
||||
.name = "ep93xx-keypad",
|
||||
.pm = pm_sleep_ptr(&ep93xx_keypad_pm_ops),
|
||||
.of_match_table = ep93xx_keypad_of_ids,
|
||||
},
|
||||
.probe = ep93xx_keypad_probe,
|
||||
.remove_new = ep93xx_keypad_remove,
|
||||
|
@ -448,6 +448,12 @@ config MTD_NAND_RENESAS
|
||||
Enables support for the NAND controller found on Renesas R-Car
|
||||
Gen3 and RZ/N1 SoC families.
|
||||
|
||||
config MTD_NAND_TS72XX
|
||||
tristate "ts72xx NAND controller"
|
||||
depends on ARCH_EP93XX && HAS_IOMEM
|
||||
help
|
||||
Enables support for NAND controller on ts72xx SBCs.
|
||||
|
||||
comment "Misc"
|
||||
|
||||
config MTD_SM_COMMON
|
||||
|
@ -34,6 +34,7 @@ obj-$(CONFIG_MTD_NAND_MLC_LPC32XX) += lpc32xx_mlc.o
|
||||
obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o
|
||||
obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_SOCRATES) += socrates_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_TS72XX) += technologic-nand-controller.o
|
||||
obj-$(CONFIG_MTD_NAND_TXX9NDFMC) += txx9ndfmc.o
|
||||
obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o
|
||||
obj-$(CONFIG_MTD_NAND_VF610_NFC) += vf610_nfc.o
|
||||
|
222
drivers/mtd/nand/raw/technologic-nand-controller.c
Normal file
222
drivers/mtd/nand/raw/technologic-nand-controller.c
Normal file
@ -0,0 +1,222 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Technologic Systems TS72xx NAND controller driver
|
||||
*
|
||||
* Copyright (C) 2023 Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
*
|
||||
* Derived from: plat_nand.c
|
||||
* Author: Vitaly Wool <vitalywool@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/platnand.h>
|
||||
|
||||
#define TS72XX_NAND_CONTROL_ADDR_LINE BIT(22) /* 0xN0400000 */
|
||||
#define TS72XX_NAND_BUSY_ADDR_LINE BIT(23) /* 0xN0800000 */
|
||||
|
||||
#define TS72XX_NAND_ALE BIT(0)
|
||||
#define TS72XX_NAND_CLE BIT(1)
|
||||
#define TS72XX_NAND_NCE BIT(2)
|
||||
|
||||
#define TS72XX_NAND_CTRL_CLE (TS72XX_NAND_NCE | TS72XX_NAND_CLE)
|
||||
#define TS72XX_NAND_CTRL_ALE (TS72XX_NAND_NCE | TS72XX_NAND_ALE)
|
||||
|
||||
struct ts72xx_nand_data {
|
||||
struct nand_controller controller;
|
||||
struct nand_chip chip;
|
||||
void __iomem *base;
|
||||
void __iomem *ctrl;
|
||||
void __iomem *busy;
|
||||
};
|
||||
|
||||
static inline struct ts72xx_nand_data *chip_to_ts72xx(struct nand_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct ts72xx_nand_data, chip);
|
||||
}
|
||||
|
||||
static int ts72xx_nand_attach_chip(struct nand_chip *chip)
|
||||
{
|
||||
switch (chip->ecc.engine_type) {
|
||||
case NAND_ECC_ENGINE_TYPE_ON_HOST:
|
||||
return -EINVAL;
|
||||
case NAND_ECC_ENGINE_TYPE_SOFT:
|
||||
if (chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)
|
||||
chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
|
||||
chip->ecc.algo = NAND_ECC_ALGO_HAMMING;
|
||||
fallthrough;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void ts72xx_nand_ctrl(struct nand_chip *chip, u8 value)
|
||||
{
|
||||
struct ts72xx_nand_data *data = chip_to_ts72xx(chip);
|
||||
unsigned char bits = ioread8(data->ctrl) & ~GENMASK(2, 0);
|
||||
|
||||
iowrite8(bits | value, data->ctrl);
|
||||
}
|
||||
|
||||
static int ts72xx_nand_exec_instr(struct nand_chip *chip,
|
||||
const struct nand_op_instr *instr)
|
||||
{
|
||||
struct ts72xx_nand_data *data = chip_to_ts72xx(chip);
|
||||
unsigned int timeout_us;
|
||||
u32 status;
|
||||
int ret;
|
||||
|
||||
switch (instr->type) {
|
||||
case NAND_OP_CMD_INSTR:
|
||||
ts72xx_nand_ctrl(chip, TS72XX_NAND_CTRL_CLE);
|
||||
iowrite8(instr->ctx.cmd.opcode, data->base);
|
||||
ts72xx_nand_ctrl(chip, TS72XX_NAND_NCE);
|
||||
break;
|
||||
|
||||
case NAND_OP_ADDR_INSTR:
|
||||
ts72xx_nand_ctrl(chip, TS72XX_NAND_CTRL_ALE);
|
||||
iowrite8_rep(data->base, instr->ctx.addr.addrs, instr->ctx.addr.naddrs);
|
||||
ts72xx_nand_ctrl(chip, TS72XX_NAND_NCE);
|
||||
break;
|
||||
|
||||
case NAND_OP_DATA_IN_INSTR:
|
||||
ioread8_rep(data->base, instr->ctx.data.buf.in, instr->ctx.data.len);
|
||||
break;
|
||||
|
||||
case NAND_OP_DATA_OUT_INSTR:
|
||||
iowrite8_rep(data->base, instr->ctx.data.buf.in, instr->ctx.data.len);
|
||||
break;
|
||||
|
||||
case NAND_OP_WAITRDY_INSTR:
|
||||
timeout_us = instr->ctx.waitrdy.timeout_ms * 1000;
|
||||
ret = readb_poll_timeout(data->busy, status, status & BIT(5), 0, timeout_us);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (instr->delay_ns)
|
||||
ndelay(instr->delay_ns);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ts72xx_nand_exec_op(struct nand_chip *chip,
|
||||
const struct nand_operation *op, bool check_only)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (check_only)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < op->ninstrs; i++) {
|
||||
ret = ts72xx_nand_exec_instr(chip, &op->instrs[i]);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct nand_controller_ops ts72xx_nand_ops = {
|
||||
.attach_chip = ts72xx_nand_attach_chip,
|
||||
.exec_op = ts72xx_nand_exec_op,
|
||||
};
|
||||
|
||||
static int ts72xx_nand_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ts72xx_nand_data *data;
|
||||
struct fwnode_handle *child;
|
||||
struct mtd_info *mtd;
|
||||
int err;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
nand_controller_init(&data->controller);
|
||||
data->controller.ops = &ts72xx_nand_ops;
|
||||
data->chip.controller = &data->controller;
|
||||
|
||||
data->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(data->base))
|
||||
return PTR_ERR(data->base);
|
||||
data->ctrl = data->base + TS72XX_NAND_CONTROL_ADDR_LINE;
|
||||
data->busy = data->base + TS72XX_NAND_BUSY_ADDR_LINE;
|
||||
|
||||
child = fwnode_get_next_child_node(dev_fwnode(&pdev->dev), NULL);
|
||||
if (!child)
|
||||
return dev_err_probe(&pdev->dev, -ENXIO,
|
||||
"ts72xx controller node should have exactly one child\n");
|
||||
|
||||
nand_set_flash_node(&data->chip, to_of_node(child));
|
||||
mtd = nand_to_mtd(&data->chip);
|
||||
mtd->dev.parent = &pdev->dev;
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
/*
|
||||
* This driver assumes that the default ECC engine should be TYPE_SOFT.
|
||||
* Set ->engine_type before registering the NAND devices in order to
|
||||
* provide a driver specific default value.
|
||||
*/
|
||||
data->chip.ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
|
||||
|
||||
/* Scan to find existence of the device */
|
||||
err = nand_scan(&data->chip, 1);
|
||||
if (err)
|
||||
goto err_handle_put;
|
||||
|
||||
err = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
|
||||
if (err)
|
||||
goto err_clean_nand;
|
||||
|
||||
return 0;
|
||||
|
||||
err_clean_nand:
|
||||
nand_cleanup(&data->chip);
|
||||
err_handle_put:
|
||||
fwnode_handle_put(child);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void ts72xx_nand_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ts72xx_nand_data *data = platform_get_drvdata(pdev);
|
||||
struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev);
|
||||
struct nand_chip *chip = &data->chip;
|
||||
int ret;
|
||||
|
||||
ret = mtd_device_unregister(nand_to_mtd(chip));
|
||||
WARN_ON(ret);
|
||||
nand_cleanup(chip);
|
||||
fwnode_handle_put(fwnode);
|
||||
}
|
||||
|
||||
static const struct of_device_id ts72xx_id_table[] = {
|
||||
{ .compatible = "technologic,ts7200-nand" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ts72xx_id_table);
|
||||
|
||||
static struct platform_driver ts72xx_nand_driver = {
|
||||
.driver = {
|
||||
.name = "ts72xx-nand",
|
||||
.of_match_table = ts72xx_id_table,
|
||||
},
|
||||
.probe = ts72xx_nand_probe,
|
||||
.remove_new = ts72xx_nand_remove,
|
||||
};
|
||||
module_platform_driver(ts72xx_nand_driver);
|
||||
|
||||
MODULE_AUTHOR("Nikita Shubin <nikita.shubin@maquefel.me>");
|
||||
MODULE_DESCRIPTION("Technologic Systems TS72xx NAND controller driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -16,13 +16,12 @@
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/platform_data/eth-ep93xx.h>
|
||||
|
||||
#define DRV_MODULE_NAME "ep93xx-eth"
|
||||
|
||||
#define RX_QUEUE_ENTRIES 64
|
||||
@ -738,25 +737,6 @@ static const struct net_device_ops ep93xx_netdev_ops = {
|
||||
.ndo_set_mac_address = eth_mac_addr,
|
||||
};
|
||||
|
||||
static struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data)
|
||||
{
|
||||
struct net_device *dev;
|
||||
|
||||
dev = alloc_etherdev(sizeof(struct ep93xx_priv));
|
||||
if (dev == NULL)
|
||||
return NULL;
|
||||
|
||||
eth_hw_addr_set(dev, data->dev_addr);
|
||||
|
||||
dev->ethtool_ops = &ep93xx_ethtool_ops;
|
||||
dev->netdev_ops = &ep93xx_netdev_ops;
|
||||
|
||||
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
static void ep93xx_eth_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct net_device *dev;
|
||||
@ -786,27 +766,49 @@ static void ep93xx_eth_remove(struct platform_device *pdev)
|
||||
|
||||
static int ep93xx_eth_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ep93xx_eth_data *data;
|
||||
struct net_device *dev;
|
||||
struct ep93xx_priv *ep;
|
||||
struct resource *mem;
|
||||
void __iomem *base_addr;
|
||||
struct device_node *np;
|
||||
u8 addr[ETH_ALEN];
|
||||
u32 phy_id;
|
||||
int irq;
|
||||
int err;
|
||||
|
||||
if (pdev == NULL)
|
||||
return -ENODEV;
|
||||
data = dev_get_platdata(&pdev->dev);
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (!mem || irq < 0)
|
||||
return -ENXIO;
|
||||
|
||||
dev = ep93xx_dev_alloc(data);
|
||||
base_addr = ioremap(mem->start, resource_size(mem));
|
||||
if (!base_addr)
|
||||
return dev_err_probe(&pdev->dev, -EIO, "Failed to ioremap ethernet registers\n");
|
||||
|
||||
np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
|
||||
if (!np)
|
||||
return dev_err_probe(&pdev->dev, -ENODEV, "Please provide \"phy-handle\"\n");
|
||||
|
||||
err = of_property_read_u32(np, "reg", &phy_id);
|
||||
of_node_put(np);
|
||||
if (err)
|
||||
return dev_err_probe(&pdev->dev, -ENOENT, "Failed to locate \"phy_id\"\n");
|
||||
|
||||
dev = alloc_etherdev(sizeof(struct ep93xx_priv));
|
||||
if (dev == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
memcpy_fromio(addr, base_addr + 0x50, ETH_ALEN);
|
||||
eth_hw_addr_set(dev, addr);
|
||||
dev->ethtool_ops = &ep93xx_ethtool_ops;
|
||||
dev->netdev_ops = &ep93xx_netdev_ops;
|
||||
dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
|
||||
|
||||
ep = netdev_priv(dev);
|
||||
ep->dev = dev;
|
||||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
@ -822,15 +824,10 @@ static int ep93xx_eth_probe(struct platform_device *pdev)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
ep->base_addr = ioremap(mem->start, resource_size(mem));
|
||||
if (ep->base_addr == NULL) {
|
||||
dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
|
||||
err = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
ep->base_addr = base_addr;
|
||||
ep->irq = irq;
|
||||
|
||||
ep->mii.phy_id = data->phy_id;
|
||||
ep->mii.phy_id = phy_id;
|
||||
ep->mii.phy_id_mask = 0x1f;
|
||||
ep->mii.reg_num_mask = 0x1f;
|
||||
ep->mii.dev = dev;
|
||||
@ -857,12 +854,18 @@ err_out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct of_device_id ep93xx_eth_of_ids[] = {
|
||||
{ .compatible = "cirrus,ep9301-eth" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ep93xx_eth_of_ids);
|
||||
|
||||
static struct platform_driver ep93xx_eth_driver = {
|
||||
.probe = ep93xx_eth_probe,
|
||||
.remove_new = ep93xx_eth_remove,
|
||||
.driver = {
|
||||
.name = "ep93xx-eth",
|
||||
.of_match_table = ep93xx_eth_of_ids,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -194,6 +194,13 @@ config PINCTRL_DIGICOLOR
|
||||
select PINMUX
|
||||
select GENERIC_PINCONF
|
||||
|
||||
config PINCTRL_EP93XX
|
||||
bool
|
||||
depends on ARCH_EP93XX || COMPILE_TEST
|
||||
select PINMUX
|
||||
select GENERIC_PINCONF
|
||||
select MFD_SYSCON
|
||||
|
||||
config PINCTRL_EQUILIBRIUM
|
||||
tristate "Generic pinctrl and GPIO driver for Intel Lightning Mountain SoC"
|
||||
depends on OF && HAS_IOMEM
|
||||
|
@ -23,6 +23,7 @@ obj-$(CONFIG_PINCTRL_DA850_PUPD) += pinctrl-da850-pupd.o
|
||||
obj-$(CONFIG_PINCTRL_DA9062) += pinctrl-da9062.o
|
||||
obj-$(CONFIG_PINCTRL_DIGICOLOR) += pinctrl-digicolor.o
|
||||
obj-$(CONFIG_PINCTRL_EQUILIBRIUM) += pinctrl-equilibrium.o
|
||||
obj-$(CONFIG_PINCTRL_EP93XX) += pinctrl-ep93xx.o
|
||||
obj-$(CONFIG_PINCTRL_EYEQ5) += pinctrl-eyeq5.o
|
||||
obj-$(CONFIG_PINCTRL_GEMINI) += pinctrl-gemini.o
|
||||
obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o
|
||||
|
1434
drivers/pinctrl/pinctrl-ep93xx.c
Normal file
1434
drivers/pinctrl/pinctrl-ep93xx.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -75,6 +75,16 @@ config POWER_RESET_BRCMSTB
|
||||
Say Y here if you have a Broadcom STB board and you wish
|
||||
to have restart support.
|
||||
|
||||
config POWER_RESET_EP93XX
|
||||
bool "Cirrus EP93XX reset driver" if COMPILE_TEST
|
||||
depends on MFD_SYSCON
|
||||
default ARCH_EP93XX
|
||||
help
|
||||
This driver provides restart support for Cirrus EP93XX SoC.
|
||||
|
||||
Say Y here if you have a Cirrus EP93XX SoC and you wish
|
||||
to have restart support.
|
||||
|
||||
config POWER_RESET_GEMINI_POWEROFF
|
||||
bool "Cortina Gemini power-off driver"
|
||||
depends on ARCH_GEMINI || COMPILE_TEST
|
||||
|
@ -7,6 +7,7 @@ obj-$(CONFIG_POWER_RESET_ATC260X) += atc260x-poweroff.o
|
||||
obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o
|
||||
obj-$(CONFIG_POWER_RESET_BRCMKONA) += brcm-kona-reset.o
|
||||
obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o
|
||||
obj-$(CONFIG_POWER_RESET_EP93XX) += ep93xx-restart.o
|
||||
obj-$(CONFIG_POWER_RESET_GEMINI_POWEROFF) += gemini-poweroff.o
|
||||
obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
|
||||
obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
|
||||
|
84
drivers/power/reset/ep93xx-restart.c
Normal file
84
drivers/power/reset/ep93xx-restart.c
Normal file
@ -0,0 +1,84 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Cirrus EP93xx SoC reset driver
|
||||
*
|
||||
* Copyright (C) 2021 Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/soc/cirrus/ep93xx.h>
|
||||
|
||||
#define EP93XX_SYSCON_DEVCFG 0x80
|
||||
#define EP93XX_SYSCON_DEVCFG_SWRST BIT(31)
|
||||
|
||||
struct ep93xx_restart {
|
||||
struct ep93xx_regmap_adev *aux_dev;
|
||||
struct notifier_block restart_handler;
|
||||
};
|
||||
|
||||
static int ep93xx_restart_handle(struct notifier_block *this,
|
||||
unsigned long mode, void *cmd)
|
||||
{
|
||||
struct ep93xx_restart *priv =
|
||||
container_of(this, struct ep93xx_restart, restart_handler);
|
||||
struct ep93xx_regmap_adev *aux = priv->aux_dev;
|
||||
|
||||
/* Issue the reboot */
|
||||
aux->update_bits(aux->map, aux->lock, EP93XX_SYSCON_DEVCFG,
|
||||
EP93XX_SYSCON_DEVCFG_SWRST, EP93XX_SYSCON_DEVCFG_SWRST);
|
||||
aux->update_bits(aux->map, aux->lock, EP93XX_SYSCON_DEVCFG,
|
||||
EP93XX_SYSCON_DEVCFG_SWRST, 0);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int ep93xx_reboot_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct ep93xx_regmap_adev *rdev = to_ep93xx_regmap_adev(adev);
|
||||
struct device *dev = &adev->dev;
|
||||
struct ep93xx_restart *priv;
|
||||
int err;
|
||||
|
||||
if (!rdev->update_bits)
|
||||
return -ENODEV;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->aux_dev = rdev;
|
||||
|
||||
priv->restart_handler.notifier_call = ep93xx_restart_handle;
|
||||
priv->restart_handler.priority = 128;
|
||||
|
||||
err = register_restart_handler(&priv->restart_handler);
|
||||
if (err)
|
||||
return dev_err_probe(dev, err, "can't register restart notifier\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct auxiliary_device_id ep93xx_reboot_ids[] = {
|
||||
{
|
||||
.name = "soc_ep93xx.reset-ep93xx",
|
||||
},
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(auxiliary, ep93xx_reboot_ids);
|
||||
|
||||
static struct auxiliary_driver ep93xx_reboot_driver = {
|
||||
.probe = ep93xx_reboot_probe,
|
||||
.id_table = ep93xx_reboot_ids,
|
||||
};
|
||||
module_auxiliary_driver(ep93xx_reboot_driver);
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/clk.h>
|
||||
@ -26,8 +27,6 @@
|
||||
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include <linux/soc/cirrus/ep93xx.h> /* for ep93xx_pwm_{acquire,release}_gpio() */
|
||||
|
||||
#define EP93XX_PWMx_TERM_COUNT 0x00
|
||||
#define EP93XX_PWMx_DUTY_CYCLE 0x04
|
||||
#define EP93XX_PWMx_ENABLE 0x08
|
||||
@ -43,20 +42,6 @@ static inline struct ep93xx_pwm *to_ep93xx_pwm(struct pwm_chip *chip)
|
||||
return pwmchip_get_drvdata(chip);
|
||||
}
|
||||
|
||||
static int ep93xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(pwmchip_parent(chip));
|
||||
|
||||
return ep93xx_pwm_acquire_gpio(pdev);
|
||||
}
|
||||
|
||||
static void ep93xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(pwmchip_parent(chip));
|
||||
|
||||
ep93xx_pwm_release_gpio(pdev);
|
||||
}
|
||||
|
||||
static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
const struct pwm_state *state)
|
||||
{
|
||||
@ -155,8 +140,6 @@ static int ep93xx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||
}
|
||||
|
||||
static const struct pwm_ops ep93xx_pwm_ops = {
|
||||
.request = ep93xx_pwm_request,
|
||||
.free = ep93xx_pwm_free,
|
||||
.apply = ep93xx_pwm_apply,
|
||||
};
|
||||
|
||||
@ -188,9 +171,16 @@ static int ep93xx_pwm_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ep93xx_pwm_of_ids[] = {
|
||||
{ .compatible = "cirrus,ep9301-pwm" },
|
||||
{ /* sentinel */}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ep93xx_pwm_of_ids);
|
||||
|
||||
static struct platform_driver ep93xx_pwm_driver = {
|
||||
.driver = {
|
||||
.name = "ep93xx-pwm",
|
||||
.of_match_table = ep93xx_pwm_of_ids,
|
||||
},
|
||||
.probe = ep93xx_pwm_probe,
|
||||
};
|
||||
|
@ -7,6 +7,7 @@ source "drivers/soc/aspeed/Kconfig"
|
||||
source "drivers/soc/atmel/Kconfig"
|
||||
source "drivers/soc/bcm/Kconfig"
|
||||
source "drivers/soc/canaan/Kconfig"
|
||||
source "drivers/soc/cirrus/Kconfig"
|
||||
source "drivers/soc/fsl/Kconfig"
|
||||
source "drivers/soc/fujitsu/Kconfig"
|
||||
source "drivers/soc/hisilicon/Kconfig"
|
||||
|
@ -8,6 +8,7 @@ obj-y += aspeed/
|
||||
obj-$(CONFIG_ARCH_AT91) += atmel/
|
||||
obj-y += bcm/
|
||||
obj-$(CONFIG_ARCH_CANAAN) += canaan/
|
||||
obj-$(CONFIG_EP93XX_SOC) += cirrus/
|
||||
obj-$(CONFIG_ARCH_DOVE) += dove/
|
||||
obj-$(CONFIG_MACH_DOVE) += dove/
|
||||
obj-y += fsl/
|
||||
|
17
drivers/soc/cirrus/Kconfig
Normal file
17
drivers/soc/cirrus/Kconfig
Normal file
@ -0,0 +1,17 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
if ARCH_EP93XX
|
||||
|
||||
config EP93XX_SOC
|
||||
bool "Cirrus EP93xx chips SoC"
|
||||
select SOC_BUS
|
||||
select AUXILIARY_BUS
|
||||
default y
|
||||
help
|
||||
Enable support SoC for Cirrus EP93xx chips.
|
||||
|
||||
Cirrus EP93xx chips have several swlocked registers,
|
||||
this driver provides locked access for reset, pinctrl
|
||||
and clk devices implemented as auxiliary devices.
|
||||
|
||||
endif
|
2
drivers/soc/cirrus/Makefile
Normal file
2
drivers/soc/cirrus/Makefile
Normal file
@ -0,0 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-y += soc-ep93xx.o
|
252
drivers/soc/cirrus/soc-ep93xx.c
Normal file
252
drivers/soc/cirrus/soc-ep93xx.c
Normal file
@ -0,0 +1,252 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* SoC driver for Cirrus EP93xx chips.
|
||||
* Copyright (C) 2022 Nikita Shubin <nikita.shubin@maquefel.me>
|
||||
*
|
||||
* Based on a rewrite of arch/arm/mach-ep93xx/core.c
|
||||
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
|
||||
* Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
|
||||
*
|
||||
* Thanks go to Michael Burian and Ray Lehtiniemi for their key
|
||||
* role in the ep93xx Linux community.
|
||||
*/
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sys_soc.h>
|
||||
|
||||
#include <linux/soc/cirrus/ep93xx.h>
|
||||
|
||||
#define EP93XX_SYSCON_DEVCFG 0x80
|
||||
|
||||
#define EP93XX_SWLOCK_MAGICK 0xaa
|
||||
#define EP93XX_SYSCON_SWLOCK 0xc0
|
||||
#define EP93XX_SYSCON_SYSCFG 0x9c
|
||||
#define EP93XX_SYSCON_SYSCFG_REV_MASK GENMASK(31, 28)
|
||||
#define EP93XX_SYSCON_SYSCFG_REV_SHIFT 28
|
||||
|
||||
struct ep93xx_map_info {
|
||||
spinlock_t lock;
|
||||
void __iomem *base;
|
||||
struct regmap *map;
|
||||
};
|
||||
|
||||
/*
|
||||
* EP93xx System Controller software locked register write
|
||||
*
|
||||
* Logic safeguards are included to condition the control signals for
|
||||
* power connection to the matrix to prevent part damage. In addition, a
|
||||
* software lock register is included that must be written with 0xAA
|
||||
* before each register write to change the values of the four switch
|
||||
* matrix control registers.
|
||||
*/
|
||||
static void ep93xx_regmap_write(struct regmap *map, spinlock_t *lock,
|
||||
unsigned int reg, unsigned int val)
|
||||
{
|
||||
guard(spinlock_irqsave)(lock);
|
||||
|
||||
regmap_write(map, EP93XX_SYSCON_SWLOCK, EP93XX_SWLOCK_MAGICK);
|
||||
regmap_write(map, reg, val);
|
||||
}
|
||||
|
||||
static void ep93xx_regmap_update_bits(struct regmap *map, spinlock_t *lock,
|
||||
unsigned int reg, unsigned int mask,
|
||||
unsigned int val)
|
||||
{
|
||||
guard(spinlock_irqsave)(lock);
|
||||
|
||||
regmap_write(map, EP93XX_SYSCON_SWLOCK, EP93XX_SWLOCK_MAGICK);
|
||||
/* force write is required to clear swlock if no changes are made */
|
||||
regmap_update_bits_base(map, reg, mask, val, NULL, false, true);
|
||||
}
|
||||
|
||||
static void ep93xx_unregister_adev(void *_adev)
|
||||
{
|
||||
struct auxiliary_device *adev = _adev;
|
||||
|
||||
auxiliary_device_delete(adev);
|
||||
auxiliary_device_uninit(adev);
|
||||
}
|
||||
|
||||
static void ep93xx_adev_release(struct device *dev)
|
||||
{
|
||||
struct auxiliary_device *adev = to_auxiliary_dev(dev);
|
||||
struct ep93xx_regmap_adev *rdev = to_ep93xx_regmap_adev(adev);
|
||||
|
||||
kfree(rdev);
|
||||
}
|
||||
|
||||
static struct auxiliary_device __init *ep93xx_adev_alloc(struct device *parent,
|
||||
const char *name,
|
||||
struct ep93xx_map_info *info)
|
||||
{
|
||||
struct ep93xx_regmap_adev *rdev __free(kfree) = NULL;
|
||||
struct auxiliary_device *adev;
|
||||
int ret;
|
||||
|
||||
rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
|
||||
if (!rdev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
rdev->map = info->map;
|
||||
rdev->base = info->base;
|
||||
rdev->lock = &info->lock;
|
||||
rdev->write = ep93xx_regmap_write;
|
||||
rdev->update_bits = ep93xx_regmap_update_bits;
|
||||
|
||||
adev = &rdev->adev;
|
||||
adev->name = name;
|
||||
adev->dev.parent = parent;
|
||||
adev->dev.release = ep93xx_adev_release;
|
||||
|
||||
ret = auxiliary_device_init(adev);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return &no_free_ptr(rdev)->adev;
|
||||
}
|
||||
|
||||
static int __init ep93xx_controller_register(struct device *parent, const char *name,
|
||||
struct ep93xx_map_info *info)
|
||||
{
|
||||
struct auxiliary_device *adev;
|
||||
int ret;
|
||||
|
||||
adev = ep93xx_adev_alloc(parent, name, info);
|
||||
if (IS_ERR(adev))
|
||||
return PTR_ERR(adev);
|
||||
|
||||
ret = auxiliary_device_add(adev);
|
||||
if (ret) {
|
||||
auxiliary_device_uninit(adev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return devm_add_action_or_reset(parent, ep93xx_unregister_adev, adev);
|
||||
}
|
||||
|
||||
static unsigned int __init ep93xx_soc_revision(struct regmap *map)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(map, EP93XX_SYSCON_SYSCFG, &val);
|
||||
val &= EP93XX_SYSCON_SYSCFG_REV_MASK;
|
||||
val >>= EP93XX_SYSCON_SYSCFG_REV_SHIFT;
|
||||
return val;
|
||||
}
|
||||
|
||||
static const char __init *ep93xx_get_soc_rev(unsigned int rev)
|
||||
{
|
||||
switch (rev) {
|
||||
case EP93XX_CHIP_REV_D0:
|
||||
return "D0";
|
||||
case EP93XX_CHIP_REV_D1:
|
||||
return "D1";
|
||||
case EP93XX_CHIP_REV_E0:
|
||||
return "E0";
|
||||
case EP93XX_CHIP_REV_E1:
|
||||
return "E1";
|
||||
case EP93XX_CHIP_REV_E2:
|
||||
return "E2";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *pinctrl_names[] __initconst = {
|
||||
"pinctrl-ep9301", /* EP93XX_9301_SOC */
|
||||
"pinctrl-ep9307", /* EP93XX_9307_SOC */
|
||||
"pinctrl-ep9312", /* EP93XX_9312_SOC */
|
||||
};
|
||||
|
||||
static int __init ep93xx_syscon_probe(struct platform_device *pdev)
|
||||
{
|
||||
enum ep93xx_soc_model model;
|
||||
struct ep93xx_map_info *map_info;
|
||||
struct soc_device_attribute *attrs;
|
||||
struct soc_device *soc_dev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct regmap *map;
|
||||
void __iomem *base;
|
||||
unsigned int rev;
|
||||
int ret;
|
||||
|
||||
model = (enum ep93xx_soc_model)(uintptr_t)device_get_match_data(dev);
|
||||
|
||||
map = device_node_to_regmap(dev->of_node);
|
||||
if (IS_ERR(map))
|
||||
return PTR_ERR(map);
|
||||
|
||||
base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
attrs = devm_kzalloc(dev, sizeof(*attrs), GFP_KERNEL);
|
||||
if (!attrs)
|
||||
return -ENOMEM;
|
||||
|
||||
rev = ep93xx_soc_revision(map);
|
||||
|
||||
attrs->machine = of_flat_dt_get_machine_name();
|
||||
attrs->family = "Cirrus Logic EP93xx";
|
||||
attrs->revision = ep93xx_get_soc_rev(rev);
|
||||
|
||||
soc_dev = soc_device_register(attrs);
|
||||
if (IS_ERR(soc_dev))
|
||||
return PTR_ERR(soc_dev);
|
||||
|
||||
map_info = devm_kzalloc(dev, sizeof(*map_info), GFP_KERNEL);
|
||||
if (!map_info)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&map_info->lock);
|
||||
map_info->map = map;
|
||||
map_info->base = base;
|
||||
|
||||
ret = ep93xx_controller_register(dev, pinctrl_names[model], map_info);
|
||||
if (ret)
|
||||
dev_err(dev, "registering pinctrl controller failed\n");
|
||||
|
||||
/*
|
||||
* EP93xx SSP clock rate was doubled in version E2. For more information
|
||||
* see section 6 "2x SSP (Synchronous Serial Port) Clock – Revision E2 only":
|
||||
* http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
|
||||
*/
|
||||
if (rev == EP93XX_CHIP_REV_E2)
|
||||
ret = ep93xx_controller_register(dev, "clk-ep93xx.e2", map_info);
|
||||
else
|
||||
ret = ep93xx_controller_register(dev, "clk-ep93xx", map_info);
|
||||
if (ret)
|
||||
dev_err(dev, "registering clock controller failed\n");
|
||||
|
||||
ret = ep93xx_controller_register(dev, "reset-ep93xx", map_info);
|
||||
if (ret)
|
||||
dev_err(dev, "registering reset controller failed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ep9301_syscon_of_device_ids[] = {
|
||||
{ .compatible = "cirrus,ep9301-syscon", .data = (void *)EP93XX_9301_SOC },
|
||||
{ .compatible = "cirrus,ep9302-syscon", .data = (void *)EP93XX_9301_SOC },
|
||||
{ .compatible = "cirrus,ep9307-syscon", .data = (void *)EP93XX_9307_SOC },
|
||||
{ .compatible = "cirrus,ep9312-syscon", .data = (void *)EP93XX_9312_SOC },
|
||||
{ .compatible = "cirrus,ep9315-syscon", .data = (void *)EP93XX_9312_SOC },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static struct platform_driver ep9301_syscon_driver = {
|
||||
.driver = {
|
||||
.name = "ep9301-syscon",
|
||||
.of_match_table = ep9301_syscon_of_device_ids,
|
||||
},
|
||||
};
|
||||
builtin_platform_driver_probe(ep9301_syscon_driver, ep93xx_syscon_probe);
|
@ -18,18 +18,18 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-direction.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#include <linux/platform_data/dma-ep93xx.h>
|
||||
#include <linux/platform_data/spi-ep93xx.h>
|
||||
|
||||
#define SSPCR0 0x0000
|
||||
#define SSPCR0_SPO BIT(6)
|
||||
#define SSPCR0_SPH BIT(7)
|
||||
@ -76,8 +76,6 @@
|
||||
* frame decreases this level and sending one frame increases it.
|
||||
* @dma_rx: RX DMA channel
|
||||
* @dma_tx: TX DMA channel
|
||||
* @dma_rx_data: RX parameters passed to the DMA engine
|
||||
* @dma_tx_data: TX parameters passed to the DMA engine
|
||||
* @rx_sgt: sg table for RX transfers
|
||||
* @tx_sgt: sg table for TX transfers
|
||||
* @zeropage: dummy page used as RX buffer when only TX buffer is passed in by
|
||||
@ -92,8 +90,6 @@ struct ep93xx_spi {
|
||||
size_t fifo_level;
|
||||
struct dma_chan *dma_rx;
|
||||
struct dma_chan *dma_tx;
|
||||
struct ep93xx_dma_data dma_rx_data;
|
||||
struct ep93xx_dma_data dma_tx_data;
|
||||
struct sg_table rx_sgt;
|
||||
struct sg_table tx_sgt;
|
||||
void *zeropage;
|
||||
@ -575,46 +571,23 @@ static int ep93xx_spi_unprepare_hardware(struct spi_controller *host)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool ep93xx_spi_dma_filter(struct dma_chan *chan, void *filter_param)
|
||||
static int ep93xx_spi_setup_dma(struct device *dev, struct ep93xx_spi *espi)
|
||||
{
|
||||
if (ep93xx_dma_chan_is_m2p(chan))
|
||||
return false;
|
||||
|
||||
chan->private = filter_param;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ep93xx_spi_setup_dma(struct ep93xx_spi *espi)
|
||||
{
|
||||
dma_cap_mask_t mask;
|
||||
int ret;
|
||||
|
||||
espi->zeropage = (void *)get_zeroed_page(GFP_KERNEL);
|
||||
if (!espi->zeropage)
|
||||
return -ENOMEM;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
espi->dma_rx_data.port = EP93XX_DMA_SSP;
|
||||
espi->dma_rx_data.direction = DMA_DEV_TO_MEM;
|
||||
espi->dma_rx_data.name = "ep93xx-spi-rx";
|
||||
|
||||
espi->dma_rx = dma_request_channel(mask, ep93xx_spi_dma_filter,
|
||||
&espi->dma_rx_data);
|
||||
if (!espi->dma_rx) {
|
||||
ret = -ENODEV;
|
||||
espi->dma_rx = dma_request_chan(dev, "rx");
|
||||
if (IS_ERR(espi->dma_rx)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(espi->dma_rx), "rx DMA setup failed");
|
||||
goto fail_free_page;
|
||||
}
|
||||
|
||||
espi->dma_tx_data.port = EP93XX_DMA_SSP;
|
||||
espi->dma_tx_data.direction = DMA_MEM_TO_DEV;
|
||||
espi->dma_tx_data.name = "ep93xx-spi-tx";
|
||||
|
||||
espi->dma_tx = dma_request_channel(mask, ep93xx_spi_dma_filter,
|
||||
&espi->dma_tx_data);
|
||||
if (!espi->dma_tx) {
|
||||
ret = -ENODEV;
|
||||
espi->dma_tx = dma_request_chan(dev, "tx");
|
||||
if (IS_ERR(espi->dma_tx)) {
|
||||
ret = dev_err_probe(dev, PTR_ERR(espi->dma_tx), "tx DMA setup failed");
|
||||
goto fail_release_rx;
|
||||
}
|
||||
|
||||
@ -647,18 +620,11 @@ static void ep93xx_spi_release_dma(struct ep93xx_spi *espi)
|
||||
static int ep93xx_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_controller *host;
|
||||
struct ep93xx_spi_info *info;
|
||||
struct ep93xx_spi *espi;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int error;
|
||||
|
||||
info = dev_get_platdata(&pdev->dev);
|
||||
if (!info) {
|
||||
dev_err(&pdev->dev, "missing platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
@ -713,12 +679,17 @@ static int ep93xx_spi_probe(struct platform_device *pdev)
|
||||
goto fail_release_host;
|
||||
}
|
||||
|
||||
if (info->use_dma && ep93xx_spi_setup_dma(espi))
|
||||
error = ep93xx_spi_setup_dma(&pdev->dev, espi);
|
||||
if (error == -EPROBE_DEFER)
|
||||
goto fail_release_host;
|
||||
|
||||
if (error)
|
||||
dev_warn(&pdev->dev, "DMA setup failed. Falling back to PIO\n");
|
||||
|
||||
/* make sure that the hardware is disabled */
|
||||
writel(0, espi->mmio + SSPCR1);
|
||||
|
||||
device_set_node(&host->dev, dev_fwnode(&pdev->dev));
|
||||
error = devm_spi_register_controller(&pdev->dev, host);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to register SPI host\n");
|
||||
@ -746,9 +717,16 @@ static void ep93xx_spi_remove(struct platform_device *pdev)
|
||||
ep93xx_spi_release_dma(espi);
|
||||
}
|
||||
|
||||
static const struct of_device_id ep93xx_spi_of_ids[] = {
|
||||
{ .compatible = "cirrus,ep9301-spi" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ep93xx_spi_of_ids);
|
||||
|
||||
static struct platform_driver ep93xx_spi_driver = {
|
||||
.driver = {
|
||||
.name = "ep93xx-spi",
|
||||
.of_match_table = ep93xx_spi_of_ids,
|
||||
},
|
||||
.probe = ep93xx_spi_probe,
|
||||
.remove_new = ep93xx_spi_remove,
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/io.h>
|
||||
@ -160,10 +161,17 @@ static int ts72xx_wdt_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ts72xx_wdt_of_ids[] = {
|
||||
{ .compatible = "technologic,ts7200-wdt" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ts72xx_wdt_of_ids);
|
||||
|
||||
static struct platform_driver ts72xx_wdt_driver = {
|
||||
.probe = ts72xx_wdt_probe,
|
||||
.driver = {
|
||||
.name = "ts72xx-wdt",
|
||||
.of_match_table = ts72xx_wdt_of_ids,
|
||||
},
|
||||
};
|
||||
|
||||
|
46
include/dt-bindings/clock/cirrus,ep9301-syscon.h
Normal file
46
include/dt-bindings/clock/cirrus,ep9301-syscon.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
|
||||
#ifndef DT_BINDINGS_CIRRUS_EP93XX_CLOCK_H
|
||||
#define DT_BINDINGS_CIRRUS_EP93XX_CLOCK_H
|
||||
|
||||
#define EP93XX_CLK_PLL1 0
|
||||
#define EP93XX_CLK_PLL2 1
|
||||
|
||||
#define EP93XX_CLK_FCLK 2
|
||||
#define EP93XX_CLK_HCLK 3
|
||||
#define EP93XX_CLK_PCLK 4
|
||||
|
||||
#define EP93XX_CLK_UART 5
|
||||
#define EP93XX_CLK_SPI 6
|
||||
#define EP93XX_CLK_PWM 7
|
||||
#define EP93XX_CLK_USB 8
|
||||
|
||||
#define EP93XX_CLK_M2M0 9
|
||||
#define EP93XX_CLK_M2M1 10
|
||||
|
||||
#define EP93XX_CLK_M2P0 11
|
||||
#define EP93XX_CLK_M2P1 12
|
||||
#define EP93XX_CLK_M2P2 13
|
||||
#define EP93XX_CLK_M2P3 14
|
||||
#define EP93XX_CLK_M2P4 15
|
||||
#define EP93XX_CLK_M2P5 16
|
||||
#define EP93XX_CLK_M2P6 17
|
||||
#define EP93XX_CLK_M2P7 18
|
||||
#define EP93XX_CLK_M2P8 19
|
||||
#define EP93XX_CLK_M2P9 20
|
||||
|
||||
#define EP93XX_CLK_UART1 21
|
||||
#define EP93XX_CLK_UART2 22
|
||||
#define EP93XX_CLK_UART3 23
|
||||
|
||||
#define EP93XX_CLK_ADC 24
|
||||
#define EP93XX_CLK_ADC_EN 25
|
||||
|
||||
#define EP93XX_CLK_KEYPAD 26
|
||||
|
||||
#define EP93XX_CLK_VIDEO 27
|
||||
|
||||
#define EP93XX_CLK_I2S_MCLK 28
|
||||
#define EP93XX_CLK_I2S_SCLK 29
|
||||
#define EP93XX_CLK_I2S_LRCLK 30
|
||||
|
||||
#endif /* DT_BINDINGS_CIRRUS_EP93XX_CLOCK_H */
|
@ -1,94 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __ASM_ARCH_DMA_H
|
||||
#define __ASM_ARCH_DMA_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
/*
|
||||
* M2P channels.
|
||||
*
|
||||
* Note that these values are also directly used for setting the PPALLOC
|
||||
* register.
|
||||
*/
|
||||
#define EP93XX_DMA_I2S1 0
|
||||
#define EP93XX_DMA_I2S2 1
|
||||
#define EP93XX_DMA_AAC1 2
|
||||
#define EP93XX_DMA_AAC2 3
|
||||
#define EP93XX_DMA_AAC3 4
|
||||
#define EP93XX_DMA_I2S3 5
|
||||
#define EP93XX_DMA_UART1 6
|
||||
#define EP93XX_DMA_UART2 7
|
||||
#define EP93XX_DMA_UART3 8
|
||||
#define EP93XX_DMA_IRDA 9
|
||||
/* M2M channels */
|
||||
#define EP93XX_DMA_SSP 10
|
||||
#define EP93XX_DMA_IDE 11
|
||||
|
||||
/**
|
||||
* struct ep93xx_dma_data - configuration data for the EP93xx dmaengine
|
||||
* @port: peripheral which is requesting the channel
|
||||
* @direction: TX/RX channel
|
||||
* @name: optional name for the channel, this is displayed in /proc/interrupts
|
||||
*
|
||||
* This information is passed as private channel parameter in a filter
|
||||
* function. Note that this is only needed for slave/cyclic channels. For
|
||||
* memcpy channels %NULL data should be passed.
|
||||
*/
|
||||
struct ep93xx_dma_data {
|
||||
int port;
|
||||
enum dma_transfer_direction direction;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ep93xx_dma_chan_data - platform specific data for a DMA channel
|
||||
* @name: name of the channel, used for getting the right clock for the channel
|
||||
* @base: mapped registers
|
||||
* @irq: interrupt number used by this channel
|
||||
*/
|
||||
struct ep93xx_dma_chan_data {
|
||||
const char *name;
|
||||
void __iomem *base;
|
||||
int irq;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ep93xx_dma_platform_data - platform data for the dmaengine driver
|
||||
* @channels: array of channels which are passed to the driver
|
||||
* @num_channels: number of channels in the array
|
||||
*
|
||||
* This structure is passed to the DMA engine driver via platform data. For
|
||||
* M2P channels, contract is that even channels are for TX and odd for RX.
|
||||
* There is no requirement for the M2M channels.
|
||||
*/
|
||||
struct ep93xx_dma_platform_data {
|
||||
struct ep93xx_dma_chan_data *channels;
|
||||
size_t num_channels;
|
||||
};
|
||||
|
||||
static inline bool ep93xx_dma_chan_is_m2p(struct dma_chan *chan)
|
||||
{
|
||||
return !strcmp(dev_name(chan->device->dev), "ep93xx-dma-m2p");
|
||||
}
|
||||
|
||||
/**
|
||||
* ep93xx_dma_chan_direction - returns direction the channel can be used
|
||||
* @chan: channel
|
||||
*
|
||||
* This function can be used in filter functions to find out whether the
|
||||
* channel supports given DMA direction. Only M2P channels have such
|
||||
* limitation, for M2M channels the direction is configurable.
|
||||
*/
|
||||
static inline enum dma_transfer_direction
|
||||
ep93xx_dma_chan_direction(struct dma_chan *chan)
|
||||
{
|
||||
if (!ep93xx_dma_chan_is_m2p(chan))
|
||||
return DMA_TRANS_NONE;
|
||||
|
||||
/* even channels are for TX, odd for RX */
|
||||
return (chan->chan_id % 2 == 0) ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
|
||||
}
|
||||
|
||||
#endif /* __ASM_ARCH_DMA_H */
|
@ -1,10 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _LINUX_PLATFORM_DATA_ETH_EP93XX
|
||||
#define _LINUX_PLATFORM_DATA_ETH_EP93XX
|
||||
|
||||
struct ep93xx_eth_data {
|
||||
unsigned char dev_addr[6];
|
||||
unsigned char phy_id;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,32 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __KEYPAD_EP93XX_H
|
||||
#define __KEYPAD_EP93XX_H
|
||||
|
||||
struct matrix_keymap_data;
|
||||
|
||||
/* flags for the ep93xx_keypad driver */
|
||||
#define EP93XX_KEYPAD_DISABLE_3_KEY (1<<0) /* disable 3-key reset */
|
||||
#define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */
|
||||
#define EP93XX_KEYPAD_BACK_DRIVE (1<<2) /* back driving mode */
|
||||
#define EP93XX_KEYPAD_TEST_MODE (1<<3) /* scan only column 0 */
|
||||
#define EP93XX_KEYPAD_AUTOREPEAT (1<<4) /* enable key autorepeat */
|
||||
|
||||
/**
|
||||
* struct ep93xx_keypad_platform_data - platform specific device structure
|
||||
* @keymap_data: pointer to &matrix_keymap_data
|
||||
* @debounce: debounce start count; terminal count is 0xff
|
||||
* @prescale: row/column counter pre-scaler load value
|
||||
* @flags: see above
|
||||
*/
|
||||
struct ep93xx_keypad_platform_data {
|
||||
struct matrix_keymap_data *keymap_data;
|
||||
unsigned int debounce;
|
||||
unsigned int prescale;
|
||||
unsigned int flags;
|
||||
unsigned int clk_rate;
|
||||
};
|
||||
|
||||
#define EP93XX_MATRIX_ROWS (8)
|
||||
#define EP93XX_MATRIX_COLS (8)
|
||||
|
||||
#endif /* __KEYPAD_EP93XX_H */
|
@ -1,15 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __ASM_MACH_EP93XX_SPI_H
|
||||
#define __ASM_MACH_EP93XX_SPI_H
|
||||
|
||||
struct spi_device;
|
||||
|
||||
/**
|
||||
* struct ep93xx_spi_info - EP93xx specific SPI descriptor
|
||||
* @use_dma: use DMA for the transfers
|
||||
*/
|
||||
struct ep93xx_spi_info {
|
||||
bool use_dma;
|
||||
};
|
||||
|
||||
#endif /* __ASM_MACH_EP93XX_SPI_H */
|
@ -2,7 +2,18 @@
|
||||
#ifndef _SOC_EP93XX_H
|
||||
#define _SOC_EP93XX_H
|
||||
|
||||
struct platform_device;
|
||||
struct regmap;
|
||||
struct spinlock_t;
|
||||
|
||||
enum ep93xx_soc_model {
|
||||
EP93XX_9301_SOC,
|
||||
EP93XX_9307_SOC,
|
||||
EP93XX_9312_SOC,
|
||||
};
|
||||
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/compiler_types.h>
|
||||
#include <linux/container_of.h>
|
||||
|
||||
#define EP93XX_CHIP_REV_D0 3
|
||||
#define EP93XX_CHIP_REV_D1 4
|
||||
@ -10,28 +21,18 @@ struct platform_device;
|
||||
#define EP93XX_CHIP_REV_E1 6
|
||||
#define EP93XX_CHIP_REV_E2 7
|
||||
|
||||
#ifdef CONFIG_ARCH_EP93XX
|
||||
int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
|
||||
void ep93xx_pwm_release_gpio(struct platform_device *pdev);
|
||||
int ep93xx_ide_acquire_gpio(struct platform_device *pdev);
|
||||
void ep93xx_ide_release_gpio(struct platform_device *pdev);
|
||||
int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
|
||||
void ep93xx_keypad_release_gpio(struct platform_device *pdev);
|
||||
int ep93xx_i2s_acquire(void);
|
||||
void ep93xx_i2s_release(void);
|
||||
unsigned int ep93xx_chip_revision(void);
|
||||
struct ep93xx_regmap_adev {
|
||||
struct auxiliary_device adev;
|
||||
struct regmap *map;
|
||||
void __iomem *base;
|
||||
spinlock_t *lock;
|
||||
void (*write)(struct regmap *map, spinlock_t *lock, unsigned int reg,
|
||||
unsigned int val);
|
||||
void (*update_bits)(struct regmap *map, spinlock_t *lock,
|
||||
unsigned int reg, unsigned int mask, unsigned int val);
|
||||
};
|
||||
|
||||
#else
|
||||
static inline int ep93xx_pwm_acquire_gpio(struct platform_device *pdev) { return 0; }
|
||||
static inline void ep93xx_pwm_release_gpio(struct platform_device *pdev) {}
|
||||
static inline int ep93xx_ide_acquire_gpio(struct platform_device *pdev) { return 0; }
|
||||
static inline void ep93xx_ide_release_gpio(struct platform_device *pdev) {}
|
||||
static inline int ep93xx_keypad_acquire_gpio(struct platform_device *pdev) { return 0; }
|
||||
static inline void ep93xx_keypad_release_gpio(struct platform_device *pdev) {}
|
||||
static inline int ep93xx_i2s_acquire(void) { return 0; }
|
||||
static inline void ep93xx_i2s_release(void) {}
|
||||
static inline unsigned int ep93xx_chip_revision(void) { return 0; }
|
||||
|
||||
#endif
|
||||
#define to_ep93xx_regmap_adev(_adev) \
|
||||
container_of((_adev), struct ep93xx_regmap_adev, adev)
|
||||
|
||||
#endif
|
||||
|
@ -31,12 +31,3 @@ config SND_EP93XX_SOC_I2S_WATCHDOG
|
||||
|
||||
endif # if SND_EP93XX_SOC_I2S
|
||||
|
||||
config SND_EP93XX_SOC_EDB93XX
|
||||
tristate "SoC Audio support for Cirrus Logic EDB93xx boards"
|
||||
depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A)
|
||||
select SND_EP93XX_SOC_I2S
|
||||
select SND_SOC_CS4271_I2C if I2C
|
||||
select SND_SOC_CS4271_SPI if SPI_MASTER
|
||||
help
|
||||
Say Y or M here if you want to add support for I2S audio on the
|
||||
Cirrus Logic EDB93xx boards.
|
||||
|
@ -6,7 +6,3 @@ snd-soc-ep93xx-i2s-y := ep93xx-i2s.o
|
||||
obj-$(CONFIG_SND_EP93XX_SOC) += snd-soc-ep93xx.o
|
||||
obj-$(CONFIG_SND_EP93XX_SOC_I2S) += snd-soc-ep93xx-i2s.o
|
||||
|
||||
# EP93XX Machine Support
|
||||
snd-soc-edb93xx-y := edb93xx.o
|
||||
|
||||
obj-$(CONFIG_SND_EP93XX_SOC_EDB93XX) += snd-soc-edb93xx.o
|
||||
|
@ -1,116 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* SoC audio for EDB93xx
|
||||
*
|
||||
* Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
|
||||
*
|
||||
* This driver support CS4271 codec being master or slave, working
|
||||
* in control port mode, connected either via SPI or I2C.
|
||||
* The data format accepted is I2S or left-justified.
|
||||
* DAPM support not implemented.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/soc/cirrus/ep93xx.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
static int edb93xx_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
|
||||
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
int err;
|
||||
unsigned int mclk_rate;
|
||||
unsigned int rate = params_rate(params);
|
||||
|
||||
/*
|
||||
* According to CS4271 datasheet we use MCLK/LRCK=256 for
|
||||
* rates below 50kHz and 128 for higher sample rates
|
||||
*/
|
||||
if (rate < 50000)
|
||||
mclk_rate = rate * 64 * 4;
|
||||
else
|
||||
mclk_rate = rate * 64 * 2;
|
||||
|
||||
err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate,
|
||||
SND_SOC_CLOCK_IN);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate,
|
||||
SND_SOC_CLOCK_OUT);
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops edb93xx_ops = {
|
||||
.hw_params = edb93xx_hw_params,
|
||||
};
|
||||
|
||||
SND_SOC_DAILINK_DEFS(hifi,
|
||||
DAILINK_COMP_ARRAY(COMP_CPU("ep93xx-i2s")),
|
||||
DAILINK_COMP_ARRAY(COMP_CODEC("spi0.0", "cs4271-hifi")),
|
||||
DAILINK_COMP_ARRAY(COMP_PLATFORM("ep93xx-i2s")));
|
||||
|
||||
static struct snd_soc_dai_link edb93xx_dai = {
|
||||
.name = "CS4271",
|
||||
.stream_name = "CS4271 HiFi",
|
||||
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBC_CFC,
|
||||
.ops = &edb93xx_ops,
|
||||
SND_SOC_DAILINK_REG(hifi),
|
||||
};
|
||||
|
||||
static struct snd_soc_card snd_soc_edb93xx = {
|
||||
.name = "EDB93XX",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &edb93xx_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static int edb93xx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &snd_soc_edb93xx;
|
||||
int ret;
|
||||
|
||||
ret = ep93xx_i2s_acquire();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
|
||||
ret = snd_soc_register_card(card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
|
||||
ret);
|
||||
ep93xx_i2s_release();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void edb93xx_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
ep93xx_i2s_release();
|
||||
}
|
||||
|
||||
static struct platform_driver edb93xx_driver = {
|
||||
.driver = {
|
||||
.name = "edb93xx-audio",
|
||||
},
|
||||
.probe = edb93xx_probe,
|
||||
.remove = edb93xx_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(edb93xx_driver);
|
||||
|
||||
MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
|
||||
MODULE_DESCRIPTION("ALSA SoC EDB93xx");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:edb93xx-audio");
|
@ -24,7 +24,6 @@
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
|
||||
#include <linux/platform_data/dma-ep93xx.h>
|
||||
#include <linux/soc/cirrus/ep93xx.h>
|
||||
|
||||
#include "ep93xx-pcm.h"
|
||||
@ -80,19 +79,6 @@ struct ep93xx_i2s_info {
|
||||
struct snd_dmaengine_dai_dma_data dma_params_tx;
|
||||
};
|
||||
|
||||
static struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
|
||||
[SNDRV_PCM_STREAM_PLAYBACK] = {
|
||||
.name = "i2s-pcm-out",
|
||||
.port = EP93XX_DMA_I2S1,
|
||||
.direction = DMA_MEM_TO_DEV,
|
||||
},
|
||||
[SNDRV_PCM_STREAM_CAPTURE] = {
|
||||
.name = "i2s-pcm-in",
|
||||
.port = EP93XX_DMA_I2S1,
|
||||
.direction = DMA_DEV_TO_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
static inline void ep93xx_i2s_write_reg(struct ep93xx_i2s_info *info,
|
||||
unsigned reg, unsigned val)
|
||||
{
|
||||
@ -198,11 +184,6 @@ static int ep93xx_i2s_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
info->dma_params_tx.filter_data =
|
||||
&ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_PLAYBACK];
|
||||
info->dma_params_rx.filter_data =
|
||||
&ep93xx_i2s_dma_data[SNDRV_PCM_STREAM_CAPTURE];
|
||||
|
||||
snd_soc_dai_init_dma_data(dai, &info->dma_params_tx,
|
||||
&info->dma_params_rx);
|
||||
|
||||
|
@ -18,8 +18,6 @@
|
||||
#include <sound/soc.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
|
||||
#include <linux/platform_data/dma-ep93xx.h>
|
||||
|
||||
#include "ep93xx-pcm.h"
|
||||
|
||||
static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
|
||||
@ -35,30 +33,15 @@ static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
|
||||
.fifo_size = 32,
|
||||
};
|
||||
|
||||
static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
|
||||
{
|
||||
struct ep93xx_dma_data *data = filter_param;
|
||||
|
||||
if (data->direction == ep93xx_dma_chan_direction(chan)) {
|
||||
chan->private = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static const struct snd_dmaengine_pcm_config ep93xx_dmaengine_pcm_config = {
|
||||
.pcm_hardware = &ep93xx_pcm_hardware,
|
||||
.compat_filter_fn = ep93xx_pcm_dma_filter,
|
||||
.prealloc_buffer_size = 131072,
|
||||
};
|
||||
|
||||
int devm_ep93xx_pcm_platform_register(struct device *dev)
|
||||
{
|
||||
return devm_snd_dmaengine_pcm_register(dev,
|
||||
&ep93xx_dmaengine_pcm_config,
|
||||
SND_DMAENGINE_PCM_FLAG_NO_DT |
|
||||
SND_DMAENGINE_PCM_FLAG_COMPAT);
|
||||
&ep93xx_dmaengine_pcm_config, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_ep93xx_pcm_platform_register);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user