Skip to contentSkip to conversation

Add iop driver for Sunplus SP7021

PATCH Superseded Tony Huang 4 participants 7 messages Mar 7, 2022 – Mar 9, 2022

Subsystems (2)

v10 of 12 Superseded Latest is v12 →

lore
Share & tools
lore

Tony Huang

author
#0 lore raw

v10 cover Add iop driver for Sunplus SP7021

Add iop driver for Sunplus SP7021 SOC

This is a patch series for iop driver for Sunplus SP7021 SOC.

Sunplus SP7021 is an ARM Cortex A7 (4 cores) based SoC. It integrates many peripherals (ex: UART, I2C, SPI, SDIO, eMMC, USB, SD card and etc.) into a single chip. It is designed for industrial control.

Refer to:
https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
https://tibbo.com/store/plus1.html

Tony Huang (2):
dt-binding: misc: Add iop yaml file for Sunplus SP7021
misc: Add iop driver for Sunplus SP7021

 .../devicetree/bindings/misc/sunplus-iop.yaml      |  76 ++++
 MAINTAINERS                                        |   6 +
 drivers/misc/Kconfig                               |  36 ++
 drivers/misc/Makefile                              |   1 +
 drivers/misc/sunplus_iop.c                         | 438 +++++++++++++++++++++
 5 files changed, 557 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/sunplus-iop.yaml
 create mode 100644 drivers/misc/sunplus_iop.c
Signature · 1 line
2.7.4
author
#1 lore raw

PATCH v10 1/2 dt-binding: misc: Add iop yaml file for Sunplus SP7021

Add iop yaml file for Sunplus SP7021

---
Changes in v10:
-No change

 .../devicetree/bindings/misc/sunplus-iop.yaml      | 76 ++++++++++++++++++++++
 MAINTAINERS                                        |  5 ++
 2 files changed, 81 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/sunplus-iop.yaml
Documentation/devicetree/bindings/misc/sunplus-iop.yaml new file +76 -0
new file mode 100644
index 0000000..b37e697
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Ltd. Co. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/misc/sunplus-iop.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus IOP(8051) controller
+
+maintainers:
+  - Tony Huang <[email protected]>
+
+description: |
+  Processor for I/O control, RTC wake-up procedure management,
+  and cooperation with CPU&PMC in power management.
+
+properties:
+  compatible:
+    enum:
+      - sunplus,sp7021-iop
+
+  reg:
+    items:
+      - description: IOP registers regions
+      - description: PMC registers regions
+      - description: MOON0 registers regions
+
+  reg-names:
+    items:
+      - const: iop
+      - const: iop_pmc
+      - const: moon0
+
+  interrupts:
+    items:
+      - description: IOP_INT0. IOP to system Interrupt 0.
+                     Sent by IOP to system RISC.
+      - description: IOP_INT1. IOP to System Interrupt 1.
+                     Sent by IOP to system RISC.
+
+  memory-region:
+    maxItems: 1
+
+  wakeup-gpios:
+    description: When the linux kernel system is powered off.
+      8051 is always powered. 8051 cand receive external signals
+      according to this gpio pin. 8051 receives external signal
+      through gpio pin. 8051 can power on linux kernel system.
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - memory-region
+  - wakeup-gpios
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/gpio/gpio.h>
+    iop: iop@9c000400 {
+        compatible = "sunplus,sp7021-iop";
+        reg = <0x9c000400 0x80>, <0x9c003100 0x80>, <0x9c000000 0x80>;
+        reg-names = "iop", "iop_pmc", "moon0";
+        interrupt-parent = <&intc>;
+        interrupts = <41 IRQ_TYPE_LEVEL_HIGH>, <42 IRQ_TYPE_LEVEL_HIGH>;
+        memory-region = <&iop_reserve>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&iop_pins>;
+        wakeup-gpios = <&pctl 1 GPIO_ACTIVE_HIGH>;
+    };
+...
MAINTAINERS +5 -0
index fb18ce7..6f336c9 100644
@@ -18242,6 +18242,11 @@ L:	[email protected]
 S:	Maintained
 F:	drivers/net/ethernet/dlink/sundance.c
 
+SUNPLUS IOP DRIVER
+M:	Tony Huang <[email protected]>
+S:	Maintained
+F:	Documentation/devicetree/bindings/misc/sunplu-iop.yaml
+
 SUPERH
 M:	Yoshinori Sato <[email protected]>
 M:	Rich Felker <[email protected]>
Signature · 1 line
2.7.4
#2 lore raw

Re: [PATCH v10 1/2] dt-binding: misc: Add iop yaml file for Sunplus SP7021

Quoted 1 line · Tony Huang

Add iop yaml file for Sunplus SP7021

subject prefix is "dt-bindings", not "dt-binding".

Quoted 18 lines

---
Changes in v10:
-No change

 .../devicetree/bindings/misc/sunplus-iop.yaml      | 76 ++++++++++++++++++++++
 MAINTAINERS                                        |  5 ++
 2 files changed, 81 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/misc/sunplus-iop.yaml
Documentation/devicetree/bindings/misc/sunplus-iop.yaml new file +0 -0
new file mode 100644
index 0000000..b37e697

Documentation/devicetree/bindings/misc/sunplus-iop.yaml line 5

Quoted 5 lines
Documentation/devicetree/bindings/misc/sunplus-iop.yaml new file +5 -0
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Ltd. Co. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/misc/sunplus-iop.yaml#

Use file name in "vendor,name" format, so "sunplus,iop.yaml".

Quoted 33 lines
Documentation/devicetree/bindings/misc/sunplus-iop.yaml new file +33 -0
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus IOP(8051) controller
+
+maintainers:
+  - Tony Huang <[email protected]>
+
+description: |
+  Processor for I/O control, RTC wake-up procedure management,
+  and cooperation with CPU&PMC in power management.
+
+properties:
+  compatible:
+    enum:
+      - sunplus,sp7021-iop
+
+  reg:
+    items:
+      - description: IOP registers regions
+      - description: PMC registers regions
+      - description: MOON0 registers regions
+
+  reg-names:
+    items:
+      - const: iop
+      - const: iop_pmc
+      - const: moon0
+
+  interrupts:
+    items:
+      - description: IOP_INT0. IOP to system Interrupt 0.
+                     Sent by IOP to system RISC.
+      - description: IOP_INT1. IOP to System Interrupt 1.

Documentation/devicetree/bindings/misc/sunplus-iop.yaml line 48

Quoted 10 lines
Documentation/devicetree/bindings/misc/sunplus-iop.yaml new file +10 -0
+                     Sent by IOP to system RISC.
+
+  memory-region:
+    maxItems: 1
+
+  wakeup-gpios:
+    description: When the linux kernel system is powered off.
+      8051 is always powered. 8051 cand receive external signals
+      according to this gpio pin. 8051 receives external signal
+      through gpio pin. 8051 can power on linux kernel system.

How many items (maxItems)? Unless Rob already asked about it...

Quoted 33 lines
Documentation/devicetree/bindings/misc/sunplus-iop.yaml new file +28 -0
+
+required:
+  - compatible
+  - reg
+  - reg-names
+  - interrupts
+  - memory-region
+  - wakeup-gpios
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/gpio/gpio.h>
+    iop: iop@9c000400 {
+        compatible = "sunplus,sp7021-iop";
+        reg = <0x9c000400 0x80>, <0x9c003100 0x80>, <0x9c000000 0x80>;
+        reg-names = "iop", "iop_pmc", "moon0";
+        interrupt-parent = <&intc>;
+        interrupts = <41 IRQ_TYPE_LEVEL_HIGH>, <42 IRQ_TYPE_LEVEL_HIGH>;
+        memory-region = <&iop_reserve>;
+        pinctrl-names = "default";
+        pinctrl-0 = <&iop_pins>;
+        wakeup-gpios = <&pctl 1 GPIO_ACTIVE_HIGH>;
+    };
+...
MAINTAINERS +0 -0
index fb18ce7..6f336c9 100644

MAINTAINERS L: [email protected] · line 18248

Quoted 7 lines
MAINTAINERS +4 -0
@@ -18242,6 +18242,11 @@ L:	[email protected]
 S:	Maintained
 F:	drivers/net/ethernet/dlink/sundance.c
 
+SUNPLUS IOP DRIVER
+M:	Tony Huang <[email protected]>
+S:	Maintained
+F:	Documentation/devicetree/bindings/misc/sunplu-iop.yaml

Wrong path.

MAINTAINERS L: [email protected] · line 18252

Quoted 4 lines
MAINTAINERS +1 -0
+
 SUPERH
 M:	Yoshinori Sato <[email protected]>
 M:	Rich Felker <[email protected]>

Best regards,
Krzysztof

author
#3 lore raw

PATCH v10 2/2 misc: Add iop driver for Sunplus SP7021

In reply to Tony Huang

This driver is load 8051 bin code.
Processor for I/O control:
SP7021 has its own GPIO device driver.
The user can configure the gpio pin for 8051 use. The 8051 support wake-up with IR key after system poweroff.

Monitor RTC interrupt:
SP7021 system has its own RTC device driver (rtc-sunplus.c). The user can set the RTC wake-up time through rtc-sunplus.c. The IOP code does not need to increase the RTC subsystem function,
set the RTC register. When the linux kernel system is poweroff.
Only the 8051 CPU has power and can monitor the RTC wake-up interrupt.

PMC in power management purpose:
Add sp_iop_poweroff() function. pm_power_off=sp_iop_poweroff. When the poweroff command is executed.
The 8051 has a register to control the power-on and power-off of the system. If you turn off the power through the 8051 register(DEF_PWR_EN_0=0). The current measured by the circuit board is 0.4mA only. In order to save power.

---
Changes in v10:
- Added sp_iop_poweroff function for poweroff command.

 MAINTAINERS                |   1 +
 drivers/misc/Kconfig       |  36 ++++
 drivers/misc/Makefile      |   1 +
 drivers/misc/sunplus_iop.c | 438 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 476 insertions(+)
 create mode 100644 drivers/misc/sunplus_iop.c
MAINTAINERS +1 -0
index 6f336c9..11ecefa 100644
@@ -18246,6 +18246,7 @@ SUNPLUS IOP DRIVER
 M:	Tony Huang <[email protected]>
 S:	Maintained
 F:	Documentation/devicetree/bindings/misc/sunplu-iop.yaml
+F:	drivers/misc/sunplus_iop.c
 
 SUPERH
 M:	Yoshinori Sato <[email protected]>
drivers/misc/Kconfig +36 -0
index 0f5a49f..3106f15 100644
@@ -470,6 +470,42 @@ config HISI_HIKEY_USB
 	  switching between the dual-role USB-C port and the USB-A host ports
 	  using only one USB controller.
 
+config SUNPLUS_IOP
+	tristate "Sunplus IOP support"
+	default ARCH_SUNPLUS
+	help
+	  This driver is load 8051 bin code.
+	  Processor for I/O control:
+	  SP7021 has its own GPIO device driver.
+	  The user can configure the gpio pin for 8051 use.
+	  8051 support wake-up with IR key after system poweroff.
+
+	  Monitor RTC interrupt:
+	  SP7021 system has its own RTC device driver (rtc-sunplus.c).
+	  The user can set the RTC wake-up time through rtc-sunplus.c.
+	  The IOP code does not need to increase the RTC subsystem function,
+	  set the RTC register.	When the linux kernel system is poweroff.
+	  Only the 8051 CPU has power and can monitor the RTC wake-up interrupt.
+
+	  PMC in power management purpose:
+	  Add sp_iop_poweroff() function. pm_power_off=sp_iop_poweroff.
+	  When the poweroff command is executed.
+	  The 8051 has a register to control the power-on and power-off of the system.
+	  If you turn off the power through the 8051 register(DEF_PWR_EN_0=0),
+	  The current measured by the circuit board is 0.4mA only. In order to save power.
+
+	  The IOP core is DQ8051, so also named IOP8051.
+	  Need Install DQ8051, The DQ8051 bin file generated by keil C.
+	  We will provide users with 8051 normal and standby source code.
+	  Path: https://sunplus.atlassian.net/wiki/spaces/doc/pages/610172933/
+	  How+to+use+I+O+processor+8051+of+SP7021#5.-Write-C-or-assembly-source-files-for-IOP
+	  Users can follow the operation steps to generate normal.bin and standby.bin.
+	  Path: https://sunplus.atlassian.net/wiki/spaces/doc/pages/466190338/26.+IOP8051
+	  26.5?How To Create 8051 bin file
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called sunplus_iop.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
drivers/misc/Makefile +1 -0
index a086197..eafeab6 100644
@@ -52,6 +52,7 @@ obj-$(CONFIG_DW_XDATA_PCIE)	+= dw-xdata-pcie.o
 obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
 obj-$(CONFIG_OCXL)		+= ocxl/
 obj-$(CONFIG_BCM_VK)		+= bcm-vk/
+obj-$(CONFIG_SUNPLUS_IOP)	+= sunplus_iop.o
 obj-y				+= cardreader/
 obj-$(CONFIG_PVPANIC)   	+= pvpanic/
 obj-$(CONFIG_HABANA_AI)		+= habanalabs/
drivers/misc/sunplus_iop.c new file +438 -0

438 lines not on this page · raw message

Signature · 1 line
2.7.4
maintainer
#4 lore raw

Re: [PATCH v10 2/2] misc: Add iop driver for Sunplus SP7021

Quoted 14 lines · Tony Huang

This driver is load 8051 bin code.
Processor for I/O control:
SP7021 has its own GPIO device driver.
The user can configure the gpio pin for 8051 use. The 8051 support wake-up with IR key after system poweroff.

Monitor RTC interrupt:
SP7021 system has its own RTC device driver (rtc-sunplus.c). The user can set the RTC wake-up time through rtc-sunplus.c. The IOP code does not need to increase the RTC subsystem function,
set the RTC register. When the linux kernel system is poweroff.
Only the 8051 CPU has power and can monitor the RTC wake-up interrupt.

Quoted 10 lines

PMC in power management purpose:
Add sp_iop_poweroff() function. pm_power_off=sp_iop_poweroff. When the poweroff command is executed.
The 8051 has a register to control the power-on and power-off of the system. If you turn off the power through the 8051 register(DEF_PWR_EN_0=0). The current measured by the circuit board is 0.4mA only. In order to save power. Changes in v10:
- Added sp_iop_poweroff function for poweroff command.

Thank you for finally adding support for one of the functions of the hardware!

Quoted 21 lines
drivers/misc/Kconfig +13 -0
index 0f5a49f..3106f15 100644
@@ -470,6 +470,42 @@ config HISI_HIKEY_USB
          switching between the dual-role USB-C port and the USB-A host ports
          using only one USB controller.
 
+config SUNPLUS_IOP
+       tristate "Sunplus IOP support"
+       default ARCH_SUNPLUS
+       help
+         This driver is load 8051 bin code.
+         Processor for I/O control:
+         SP7021 has its own GPIO device driver.
+         The user can configure the gpio pin for 8051 use.
+         8051 support wake-up with IR key after system poweroff.
+
+         Monitor RTC interrupt:
+         SP7021 system has its own RTC device driver (rtc-sunplus.c).
+         The user can set the RTC wake-up time through rtc-sunplus.c.

drivers/misc/Kconfig config HISI_HIKEY_USB · line 495

Quoted 10 lines
drivers/misc/Kconfig +10 -0
+         The IOP code does not need to increase the RTC subsystem function,
+         set the RTC register. When the linux kernel system is poweroff.
+         Only the 8051 CPU has power and can monitor the RTC wake-up interrupt.
+
+         PMC in power management purpose:
+         Add sp_iop_poweroff() function. pm_power_off=sp_iop_poweroff.
+         When the poweroff command is executed.
+         The 8051 has a register to control the power-on and power-off of the system.
+         If you turn off the power through the 8051 register(DEF_PWR_EN_0=0),
+         The current measured by the circuit board is 0.4mA only. In order to save power.

The description sounds misleading here: At the moment, you only add support for poweroff, not for system suspend.

Maybe leave out the description about the RTC and power savings here and only describe the bits that the driver actually implements. Can you add some text to the patch changelog to describe what your plans are for supporting suspend mode, and clarify which functions are implemented already, compared to those that are possible in hardware but not part of this patch series?

drivers/misc/Kconfig config HISI_HIKEY_USB · line 503

Quoted 8 lines
drivers/misc/Kconfig +8 -0
+static void sp_iop_run_standby_code(struct sp_iop *iop)
+{
+       void __iomem *iop_kernel_base;
+       unsigned long reg;
+
+       iop_kernel_base = ioremap(iop->iop_mem_start, STANDBY_CODE_MAX_SIZE);
+       memset(iop_kernel_base, 0, STANDBY_CODE_MAX_SIZE);
+       memcpy(iop_kernel_base, iop->iop_standby_code, STANDBY_CODE_MAX_SIZE);

'standby' mode usually refers to 'suspend-to-ram' mode, which is something the driver does not (yet) support. Can you clarify whether that means you want to add it later, or you just used the wrong term here?

drivers/misc/Kconfig config HISI_HIKEY_USB

Quoted 11 lines
drivers/misc/Kconfig +11 -0
+
+/* 8051 informs linux kerenl. 8051 has been switched to standby.bin code. */
+#define IOP_READY      0x0004
+#define RISC_READY     0x0008
+
+/* System linux kernel tells 8051 which  gpio pin to wake-up through. */
+#define WAKEUP_PIN     0xFE02
+
+/* System linux kernel tells 8051 to execute S1 or S3 mode. */
+#define S1     0x5331
+#define S3     0x5333

Again, the names here seem misleading: in power management terms, 's1' and 's3' typically refer to types of system power saving modes that are different from power-off or suspend-to-disk. Maybe try to use less confusing terms here?

drivers/misc/Kconfig

Quoted 6 lines
drivers/misc/Kconfig +6 -0
+       /* IOP Hardware IP reset */
+       reg = readl(iop->moon0_regs + IOP_RESET0);
+       reg |= 0x10;
+       writel(reg, (iop->moon0_regs + IOP_RESET0));
+       reg &= ~(0x10);
+       writel(reg, (iop->moon0_regs + IOP_RESET0));

This looks like you are writing individual bits into a shared clock/reset controller that is part of the SoC. If this is the case, it would be better to make that a separate driver that owns the moon0_regs registers and exposes them through the
clk and reset subsystem interfaces (drivers/clk, drivers/reset).

Quoted 8 lines
drivers/misc/Kconfig +8 -0
+static void sp_iop_poweroff(void)
+{
+       struct sp_iop *iop = iop_poweroff;
+       unsigned int ret, value;
+
+       value = readl(iop->iop_regs + IOP_DATA11);
+       sp_iop_run_standby_code(iop);
+

drivers/misc/Kconfig

Quoted 10 lines
drivers/misc/Kconfig +10 -0
+       ret = readl_poll_timeout(iop->iop_regs + IOP_DATA0, value,
+                                value == 0x2222, 1000, 100000);
+       if (ret)
+               dev_warn(iop->dev, "timed out\n");
+
+       if (value == S1)
+               sp_iop_s1mode(iop->dev, iop);
+       else
+               sp_iop_s3mode(iop->dev, iop);
+}

The power-off logic should probably be a separate driver in drivers/power/reset/ that calls into the common driver.

Arnd

#5 lore raw

Re: [PATCH v10 2/2] misc: Add iop driver for Sunplus SP7021

In reply to Tony Huang
Quoted 117 lines · Tony Huang

This driver is load 8051 bin code.
Processor for I/O control:
SP7021 has its own GPIO device driver.
The user can configure the gpio pin for 8051 use. The 8051 support wake-up with IR key after system poweroff.

Monitor RTC interrupt:
SP7021 system has its own RTC device driver (rtc-sunplus.c). The user can set the RTC wake-up time through rtc-sunplus.c. The IOP code does not need to increase the RTC subsystem function,
set the RTC register. When the linux kernel system is poweroff.
Only the 8051 CPU has power and can monitor the RTC wake-up interrupt.

PMC in power management purpose:
Add sp_iop_poweroff() function. pm_power_off=sp_iop_poweroff. When the poweroff command is executed.
The 8051 has a register to control the power-on and power-off of the system. If you turn off the power through the 8051 register(DEF_PWR_EN_0=0). The current measured by the circuit board is 0.4mA only. In order to save power.

---
Changes in v10:
- Added sp_iop_poweroff function for poweroff command.

 MAINTAINERS                |   1 +
 drivers/misc/Kconfig       |  36 ++++
 drivers/misc/Makefile      |   1 +
 drivers/misc/sunplus_iop.c | 438 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 476 insertions(+)
 create mode 100644 drivers/misc/sunplus_iop.c
MAINTAINERS +1 -0
index 6f336c9..11ecefa 100644
@@ -18246,6 +18246,7 @@ SUNPLUS IOP DRIVER
 M:	Tony Huang <[email protected]>
 S:	Maintained
 F:	Documentation/devicetree/bindings/misc/sunplu-iop.yaml
+F:	drivers/misc/sunplus_iop.c
 
 SUPERH
 M:	Yoshinori Sato <[email protected]>
drivers/misc/Kconfig +36 -0
index 0f5a49f..3106f15 100644
@@ -470,6 +470,42 @@ config HISI_HIKEY_USB
 	  switching between the dual-role USB-C port and the USB-A host ports
 	  using only one USB controller.
 
+config SUNPLUS_IOP
+	tristate "Sunplus IOP support"
+	default ARCH_SUNPLUS
+	help
+	  This driver is load 8051 bin code.
+	  Processor for I/O control:
+	  SP7021 has its own GPIO device driver.
+	  The user can configure the gpio pin for 8051 use.
+	  8051 support wake-up with IR key after system poweroff.
+
+	  Monitor RTC interrupt:
+	  SP7021 system has its own RTC device driver (rtc-sunplus.c).
+	  The user can set the RTC wake-up time through rtc-sunplus.c.
+	  The IOP code does not need to increase the RTC subsystem function,
+	  set the RTC register.	When the linux kernel system is poweroff.
+	  Only the 8051 CPU has power and can monitor the RTC wake-up interrupt.
+
+	  PMC in power management purpose:
+	  Add sp_iop_poweroff() function. pm_power_off=sp_iop_poweroff.
+	  When the poweroff command is executed.
+	  The 8051 has a register to control the power-on and power-off of the system.
+	  If you turn off the power through the 8051 register(DEF_PWR_EN_0=0),
+	  The current measured by the circuit board is 0.4mA only. In order to save power.
+
+	  The IOP core is DQ8051, so also named IOP8051.
+	  Need Install DQ8051, The DQ8051 bin file generated by keil C.
+	  We will provide users with 8051 normal and standby source code.
+	  Path: https://sunplus.atlassian.net/wiki/spaces/doc/pages/610172933/
+	  How+to+use+I+O+processor+8051+of+SP7021#5.-Write-C-or-assembly-source-files-for-IOP
+	  Users can follow the operation steps to generate normal.bin and standby.bin.
+	  Path: https://sunplus.atlassian.net/wiki/spaces/doc/pages/466190338/26.+IOP8051
+	  26.5?How To Create 8051 bin file
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called sunplus_iop.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
drivers/misc/Makefile +1 -0
index a086197..eafeab6 100644
@@ -52,6 +52,7 @@ obj-$(CONFIG_DW_XDATA_PCIE)	+= dw-xdata-pcie.o
 obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
 obj-$(CONFIG_OCXL)		+= ocxl/
 obj-$(CONFIG_BCM_VK)		+= bcm-vk/
+obj-$(CONFIG_SUNPLUS_IOP)	+= sunplus_iop.o
 obj-y				+= cardreader/
 obj-$(CONFIG_PVPANIC)   	+= pvpanic/
 obj-$(CONFIG_HABANA_AI)		+= habanalabs/
drivers/misc/sunplus_iop.c new file +7 -0
new file mode 100644
index 0000000..03301b4
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The IOP driver for Sunplus SP7021
+ *
+ * Copyright (C) 2021 Sunplus Technology Inc.
+ *
+ * All Rights Reserved.

drivers/misc/sunplus_iop.c line 17

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+ */
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+

Except comments from Arnd also:

drivers/misc/sunplus_iop.c line 21

Quoted 4 lines
drivers/misc/sunplus_iop.c new file +4 -0
+enum IOP_Status_e {
+	IOP_SUCCESS,		/* successful */
+	IOP_ERR_IOP_BUSY,	/* IOP is busy */
+};

please do not redefine true/false or ERRNO.

Quoted 25 lines
drivers/misc/sunplus_iop.c new file +25 -0
+
+/* moon0 register offset */
+#define IOP_CLKEN0	0x04
+#define IOP_RESET0	0x54
+
+/* IOP register offset */
+#define IOP_CONTROL	0x00
+#define IOP_DATA0	0x20
+#define IOP_DATA1	0x24
+#define IOP_DATA2	0x28
+#define IOP_DATA3	0x2c
+#define IOP_DATA4	0x30
+#define IOP_DATA5	0x34
+#define IOP_DATA6	0x38
+#define IOP_DATA7	0x3c
+#define IOP_DATA8	0x40
+#define IOP_DATA9	0x44
+#define IOP_DATA10	0x48
+#define IOP_DATA11	0x4c
+#define IOP_BASE_ADR_L	0x50
+#define IOP_BASE_ADR_H	0x54
+
+/* PMC register offset */
+#define IOP_PMC_TIMER		0x00
+#define IOP_PMC_CTRL		0x04

drivers/misc/sunplus_iop.c line 56

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+#define IOP_XTAL27M_PASSWORD_I	0x08
+#define IOP_XTAL27M_PASSWORD_II	0x0c
+#define IOP_XTAL32K_PASSWORD_I	0x10
+#define IOP_XTAL32K_PASSWORD_II	0x14
+#define IOP_CLK27M_PASSWORD_I	0x18
+#define IOP_CLK27M_PASSWORD_II	0x1c
+#define IOP_PMC_TIMER2		0x20
+
+#define NORMAL_CODE_MAX_SIZE 0X1000	/* Max size of normal.bin that can be received */
+#define STANDBY_CODE_MAX_SIZE 0x4000	/* Max size of standby.bin that can be received */

Empty line.

drivers/misc/sunplus_iop.c line 59

Quoted 3 lines
drivers/misc/sunplus_iop.c new file +3 -0
+struct sp_iop {
+	struct device *dev;
+	struct mutex write_lock;	/* avoid parallel access */

This comment is useless. It is obvious that mutex is used to avoid parallel access, what else could it be used?

Instead, you need to describe which members/variables/parts of code are protected with the mutex.

drivers/misc/sunplus_iop.c line 66

Quoted 7 lines
drivers/misc/sunplus_iop.c new file +7 -0
+	void __iomem *iop_regs;
+	void __iomem *pmc_regs;
+	void __iomem *moon0_regs;
+	int irq;
+	int gpio_wakeup;
+	unsigned char iop_normal_code[NORMAL_CODE_MAX_SIZE];
+	unsigned char iop_standby_code[STANDBY_CODE_MAX_SIZE];

Why not using firmware? include/linux/firmware.h? Do not reimplement existing solutions...

Quoted 75 lines
drivers/misc/sunplus_iop.c new file +75 -0
+	resource_size_t iop_mem_start;
+	resource_size_t iop_mem_size;
+	unsigned char bin_code_mode;
+};
+
+static struct sp_iop *iop_poweroff;
+
+static void sp_iop_run_normal_code(struct sp_iop *iop)
+{
+	void __iomem *iop_kernel_base;
+	unsigned int reg;
+
+	iop_kernel_base = ioremap(iop->iop_mem_start, NORMAL_CODE_MAX_SIZE);
+	memset(iop_kernel_base, 0, NORMAL_CODE_MAX_SIZE);
+	memcpy(iop_kernel_base, iop->iop_normal_code, NORMAL_CODE_MAX_SIZE);
+
+	writel(0x00100010, iop->moon0_regs + IOP_CLKEN0);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg |= 0x01;
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg &= ~(0x8000);
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg |= 0x0200;// disable watchdog event reset IOP
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+
+	reg = (iop->iop_mem_start & 0xFFFF);
+	writel(reg, iop->iop_regs + IOP_BASE_ADR_L);
+	reg	= (iop->iop_mem_start >> 16);
+	writel(reg, iop->iop_regs + IOP_BASE_ADR_H);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg &= ~(0x01);
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+	iop->bin_code_mode = 0;
+}
+
+static void sp_iop_run_standby_code(struct sp_iop *iop)
+{
+	void __iomem *iop_kernel_base;
+	unsigned long reg;
+
+	iop_kernel_base = ioremap(iop->iop_mem_start, STANDBY_CODE_MAX_SIZE);
+	memset(iop_kernel_base, 0, STANDBY_CODE_MAX_SIZE);
+	memcpy(iop_kernel_base, iop->iop_standby_code, STANDBY_CODE_MAX_SIZE);
+
+	writel(0x00100010, iop->moon0_regs + IOP_CLKEN0);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg |= 0x01;
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg &= ~(0x8000);
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg |= 0x0200;// disable watchdog event reset IOP
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+
+	reg = (iop->iop_mem_start & 0xFFFF);
+	writel(reg, iop->iop_regs + IOP_BASE_ADR_L);
+	reg = (iop->iop_mem_start >> 16);
+	writel(reg, iop->iop_regs + IOP_BASE_ADR_H);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg &= ~(0x01);
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+	iop->bin_code_mode = 1;
+}
+

drivers/misc/sunplus_iop.c line 151

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+/* 8051 informs linux kerenl. 8051 has been switched to standby.bin code. */
+#define IOP_READY	0x0004
+#define RISC_READY	0x0008
+
+/* System linux kernel tells 8051 which  gpio pin to wake-up through. */
+#define WAKEUP_PIN	0xFE02
+
+/* System linux kernel tells 8051 to execute S1 or S3 mode. */
+#define S1	0x5331
+#define S3	0x5333

Keep defines together, so beginning of file.

Quoted 77 lines
drivers/misc/sunplus_iop.c new file +77 -0
+
+static int sp_iop_s3mode(struct device *dev, struct sp_iop *iop)
+{
+	unsigned int reg;
+	int ret, value;
+
+	/* PMC set */
+	writel(0x00010001, iop->pmc_regs + IOP_PMC_TIMER);
+	reg = readl(iop->pmc_regs + IOP_PMC_CTRL);
+	/* disable system reset PMC, enalbe power down IOP Domain, enable gating clock 27Mhz */
+	reg |= 0x23;
+	writel(reg, iop->pmc_regs + IOP_PMC_CTRL);
+
+	writel(0x55aa00ff, iop->pmc_regs + IOP_XTAL27M_PASSWORD_I);
+	writel(0x00ff55aa, iop->pmc_regs + IOP_XTAL27M_PASSWORD_II);
+	writel(0xaa00ff55, iop->pmc_regs + IOP_XTAL32K_PASSWORD_I);
+	writel(0xff55aa00, iop->pmc_regs + IOP_XTAL32K_PASSWORD_II);
+	writel(0xaaff0055, iop->pmc_regs + IOP_CLK27M_PASSWORD_I);
+	writel(0x5500aaff, iop->pmc_regs + IOP_CLK27M_PASSWORD_II);
+	writel(0x01000100, iop->pmc_regs + IOP_PMC_TIMER2);
+
+	/* IOP Hardware IP reset */
+	reg = readl(iop->moon0_regs + IOP_RESET0);
+	reg |= 0x10;
+	writel(reg, (iop->moon0_regs + IOP_RESET0));
+	reg &= ~(0x10);
+	writel(reg, (iop->moon0_regs + IOP_RESET0));
+
+	writel(0x00ff0085, (iop->moon0_regs + 32 * 4 * 1 + 4 * 1));
+
+	reg = readl(iop->moon0_regs + 32 * 4 * 1 + 4 * 2);
+	reg |= 0x08000800;
+	writel(reg, (iop->moon0_regs + 32 * 4 * 1 + 4 * 2));
+
+	writel(WAKEUP_PIN, iop->iop_regs + IOP_DATA0);
+	writel(iop->gpio_wakeup, iop->iop_regs + IOP_DATA1);
+
+	ret = readl_poll_timeout(iop->iop_regs + IOP_DATA2, value,
+				 (value & IOP_READY) == IOP_READY, 1000, 10000);
+	if (ret) {
+		dev_err(dev, "timed out\n");
+		return ret;
+	}
+
+	reg = RISC_READY;
+	writel(reg, iop->iop_regs + IOP_DATA2);
+	reg = 0x0000;
+	writel(reg, iop->iop_regs + IOP_DATA5);
+	reg = 0x0060;
+	writel(reg, iop->iop_regs + IOP_DATA6);
+
+	ret = readl_poll_timeout(iop->iop_regs + IOP_DATA7, value,
+				 value == 0xaaaa, 1000, 10000);
+	if (ret) {
+		dev_err(dev, "timed out\n");
+		return ret;
+	}
+
+	/* 8051 bin file call Ultra low function. */
+	writel(0xdd, iop->iop_regs + IOP_DATA1);
+	/*
+	 * When the execution is here, the system linux kernel
+	 * is about to be powered off
+	 * The purpose of mdelay(10): Do not let the system linux
+	 * kernel continue to run other programs.
+	 */
+	mdelay(10);
+	return 0;
+}
+
+static int sp_iop_s1mode(struct device *dev, struct sp_iop *iop)
+{
+	int ret, value;
+
+	ret = readl_poll_timeout(iop->iop_regs + IOP_DATA2, value,
+				 (value & IOP_READY) == IOP_READY, 1000, 10000);
+	if (ret) {

drivers/misc/sunplus_iop.c line 238

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+		dev_err(dev, "timed out\n");
+		return ret;
+	}
+
+	writel(RISC_READY, iop->iop_regs + IOP_DATA2);
+	writel(0x0000, iop->iop_regs + IOP_DATA5);
+	writel(0x0060, iop->iop_regs + IOP_DATA6);
+
+	ret = readl_poll_timeout(iop->iop_regs + IOP_DATA7, value,
+				 value == 0xaaaa, 1000, 10000);

Hundreds of magical constants... Almost all of these should be defined or described.

Quoted 108 lines
drivers/misc/sunplus_iop.c new file +108 -0
+	if (ret) {
+		dev_err(dev, "timed out\n");
+		return ret;
+	}
+
+	/* 8051 bin file call S1_mode function. */
+	writel(0xee, iop->iop_regs + IOP_DATA1);
+	/*
+	 * When the execution is here, the system linux kernel
+	 * is about to be powered off
+	 * The purpose of mdelay(10): Do not let the system linux
+	 * kernel continue to run other programs.
+	 */
+	mdelay(10);
+	return 0;
+}
+
+static int  sp_iop_get_normal_code(struct device *dev, struct sp_iop *iop)
+{
+	const struct firmware *fw;
+	static const char file[] = "normal.bin";
+	unsigned int err, i;
+
+	err = request_firmware(&fw, file, dev);
+	if (err) {
+		dev_err(dev, "get bin file error\n");
+		return err;
+	}
+
+	for (i = 0; i < NORMAL_CODE_MAX_SIZE; i++) {
+		char temp;
+
+		temp = fw->data[i];
+		iop->iop_normal_code[i] = temp;
+	}
+	release_firmware(fw);
+	return err;
+}
+
+static int  sp_iop_get_standby_code(struct device *dev, struct sp_iop *iop)
+{
+	const struct firmware *fw;
+	static const char file[] = "standby.bin";
+	unsigned int err, i;
+
+	err = request_firmware(&fw, file, dev);
+	if (err) {
+		dev_err(dev, "get bin file error\n");
+		return err;
+	}
+
+	for (i = 0; i < STANDBY_CODE_MAX_SIZE; i++) {
+		char temp;
+
+		temp = fw->data[i];
+		iop->iop_standby_code[i] = temp;
+	}
+	release_firmware(fw);
+	return err;
+}
+
+static void sp_iop_poweroff(void)
+{
+	struct sp_iop *iop = iop_poweroff;
+	unsigned int ret, value;
+
+	value = readl(iop->iop_regs + IOP_DATA11);
+	sp_iop_run_standby_code(iop);
+
+	ret = readl_poll_timeout(iop->iop_regs + IOP_DATA0, value,
+				 value == 0x2222, 1000, 100000);
+	if (ret)
+		dev_warn(iop->dev, "timed out\n");
+
+	if (value == S1)
+		sp_iop_s1mode(iop->dev, iop);
+	else
+		sp_iop_s3mode(iop->dev, iop);
+}
+
+static int sp_iop_get_resources(struct platform_device *pdev, struct sp_iop *p_sp_iop_info)
+{
+	struct resource *r;
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iop");
+	p_sp_iop_info->iop_regs = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(p_sp_iop_info->iop_regs)) {
+		dev_err(&pdev->dev, "ioremap fail\n");
+		return PTR_ERR(p_sp_iop_info->iop_regs);
+	}
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iop_pmc");
+	p_sp_iop_info->pmc_regs = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(p_sp_iop_info->pmc_regs)) {
+		dev_err(&pdev->dev, "ioremap fail\n");
+		return PTR_ERR(p_sp_iop_info->pmc_regs);
+	}
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "moon0");
+	p_sp_iop_info->moon0_regs = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(p_sp_iop_info->moon0_regs)) {
+		dev_err(&pdev->dev, "ioremap fail\n");
+		return PTR_ERR(p_sp_iop_info->moon0_regs);
+	}
+	return IOP_SUCCESS;
+}
+
+static int sp_iop_platform_driver_probe(struct platform_device *pdev)

drivers/misc/sunplus_iop.c line 356

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+{
+	int ret = -ENXIO;
+	int rc;
+	struct sp_iop *iop;
+	struct device_node *memnp;
+	struct resource mem_res;
+
+	iop = devm_kzalloc(&pdev->dev, sizeof(struct sp_iop), GFP_KERNEL);
+	if (!iop) {
+		ret	= -ENOMEM;

Wrong spacing before '='.

drivers/misc/sunplus_iop.c line 359

Quoted 3 lines
drivers/misc/sunplus_iop.c new file +3 -0
+		goto fail_kmalloc;
+	}
+	/* init */

Remove useless comments.

drivers/misc/sunplus_iop.c line 360

Quoted 1 line
drivers/misc/sunplus_iop.c new file +1 -0
+	mutex_init(&iop->write_lock);

Where are lock/unlock operations? What is this all code? This looks like half-baked solution...

drivers/misc/sunplus_iop.c line 363

Quoted 3 lines
drivers/misc/sunplus_iop.c new file +3 -0
+	ret = sp_iop_get_resources(pdev, iop);
+
+	// Get reserve address

Keep consistent style. For comments /* is preferred. But definitely do not mix one with another.

This code is difficult to read.

Quoted 32 lines
drivers/misc/sunplus_iop.c new file +32 -0
+	memnp = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
+	if (!memnp) {
+		dev_err(&pdev->dev, "no memory-region node\n");
+		return -EINVAL;
+	}
+
+	rc = of_address_to_resource(memnp, 0, &mem_res);
+	of_node_put(memnp);
+	if (rc) {
+		dev_err(&pdev->dev, "failed to translate memory-region to a resource\n");
+		return -EINVAL;
+	}
+
+	iop->dev = &pdev->dev;
+	iop->iop_mem_start = mem_res.start;
+	iop->iop_mem_size = resource_size(&mem_res);
+
+	/*
+	 * 8051 has two bin files, normal.bin and standby.bin in rootfs.
+	 * Normally, 8051 executes normal.bin code. Normal.bin code size can exceed 16K.
+	 * When system linux kernel is shutdown, 8051 is to execute standby.bin code.
+	 * Standby.bin code cannot exceed 16K bytes. Because 8051 Icache size is 16k.
+	 * 8051 runs with standby.bin code in the Icache before the system(linux kernel)
+	 * is poweroff.
+	 */
+	ret = sp_iop_get_normal_code(&pdev->dev, iop);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "get normal code err=%d\n", ret);
+		return ret;
+	}
+
+	ret = sp_iop_get_standby_code(&pdev->dev, iop);

drivers/misc/sunplus_iop.c line 405

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+	if (ret != 0) {
+		dev_err(&pdev->dev, "get standby code err=%d\n", ret);
+		return ret;
+	}
+
+	sp_iop_run_normal_code(iop);
+	platform_set_drvdata(pdev, iop);
+	iop->gpio_wakeup = of_get_named_gpio(pdev->dev.of_node, "iop-wakeup", 0);
+	iop_poweroff = iop;
+	pm_power_off = sp_iop_poweroff;

Blank line. Before every such return. Please, open some recent drivers and look at their code style.

Quoted 23 lines
drivers/misc/sunplus_iop.c new file +23 -0
+	return 0;
+
+fail_kmalloc:
+	return ret;
+}
+
+static int sp_iop_remove(struct platform_device *pdev)
+{
+	pm_power_off = NULL;
+	return 0;
+}
+
+static const struct of_device_id sp_iop_of_match[] = {
+	{ .compatible = "sunplus,sp7021-iop" },
+	{ /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, sp_iop_of_match);
+
+static struct platform_driver sp_iop_platform_driver = {
+	.probe		= sp_iop_platform_driver_probe,
+	.remove		= sp_iop_remove,
+	.driver = {

drivers/misc/sunplus_iop.c line 438

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+		.name	= "sunplus,sp7021-iop",
+		.of_match_table = sp_iop_of_match,
+	}
+};
+
+module_platform_driver(sp_iop_platform_driver);
+
+MODULE_AUTHOR("Tony Huang <[email protected]>");
+MODULE_DESCRIPTION("Sunplus IOP Driver");
+MODULE_LICENSE("GPL v2");

Best regards,
Krzysztof

#6 lore raw

RE: [PATCH v10 2/2] misc: Add iop driver for Sunplus SP7021

Dear Krzysztof:
I will modify the code to follow your comments
Thanks

Quoted 618 lines

Subject: Re: [PATCH v10 2/2] misc: Add iop driver for Sunplus SP7021

Quoted 59 lines · Tony Huang

This driver is load 8051 bin code.
Processor for I/O control:
SP7021 has its own GPIO device driver.
The user can configure the gpio pin for 8051 use. The 8051 support wake-up with IR key after system poweroff.

Monitor RTC interrupt:
SP7021 system has its own RTC device driver (rtc-sunplus.c). The user can set the RTC wake-up time through rtc-sunplus.c. The IOP code does not need to increase the RTC subsystem function,
set the RTC register. When the linux kernel system is poweroff.
Only the 8051 CPU has power and can monitor the RTC wake-up interrupt.

PMC in power management purpose:
Add sp_iop_poweroff() function. pm_power_off=sp_iop_poweroff. When the poweroff command is executed.
The 8051 has a register to control the power-on and power-off of the system. If you turn off the power through the 8051 register(DEF_PWR_EN_0=0). The current measured by the circuit board is 0.4mA only. In order to save power.

---
Changes in v10:
- Added sp_iop_poweroff function for poweroff command.

 MAINTAINERS                |   1 +
 drivers/misc/Kconfig       |  36 ++++
 drivers/misc/Makefile      |   1 +
 drivers/misc/sunplus_iop.c | 438
+++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 476 insertions(+)
 create mode 100644 drivers/misc/sunplus_iop.c
MAINTAINERS +1 -0
@@ -18246,6 +18246,7 @@ SUNPLUS IOP DRIVER
 M:	Tony Huang <[email protected]>
 S:	Maintained
 F:	Documentation/devicetree/bindings/misc/sunplu-iop.yaml
+F:	drivers/misc/sunplus_iop.c
 
 SUPERH
 M:	Yoshinori Sato <[email protected]>
drivers/misc/Kconfig index renamed from drivers/misc/Kconfig +0 -0

0f5a49f..3106f15 100644

drivers/misc/Kconfig +6 -0
@@ -470,6 +470,42 @@ config HISI_HIKEY_USB
 	  switching between the dual-role USB-C port and the USB-A host ports
 	  using only one USB controller.
 
+config SUNPLUS_IOP
+	tristate "Sunplus IOP support"
+	default ARCH_SUNPLUS
+	help
+	  This driver is load 8051 bin code.
+	  Processor for I/O control:

drivers/misc/Kconfig config HISI_HIKEY_USB · line 488

Quoted 10 lines
drivers/misc/Kconfig +10 -0
+	  SP7021 has its own GPIO device driver.
+	  The user can configure the gpio pin for 8051 use.
+	  8051 support wake-up with IR key after system poweroff.
+
+	  Monitor RTC interrupt:
+	  SP7021 system has its own RTC device driver (rtc-sunplus.c).
+	  The user can set the RTC wake-up time through rtc-sunplus.c.
+	  The IOP code does not need to increase the RTC subsystem function,
+	  set the RTC register.	When the linux kernel system is poweroff.
+	  Only the 8051 CPU has power and can monitor the RTC wake-up

interrupt.

drivers/misc/Kconfig config HISI_HIKEY_USB

Quoted 5 lines
drivers/misc/Kconfig +5 -0
+
+	  PMC in power management purpose:
+	  Add sp_iop_poweroff() function. pm_power_off=sp_iop_poweroff.
+	  When the poweroff command is executed.
+	  The 8051 has a register to control the power-on and power-off of the

system.

drivers/misc/Kconfig config HISI_HIKEY_USB · line 495

Quoted 2 lines
drivers/misc/Kconfig +2 -0
+	  If you turn off the power through the 8051 register(DEF_PWR_EN_0=0),
+	  The current measured by the circuit board is 0.4mA only. In order to

save power.

drivers/misc/Kconfig config HISI_HIKEY_USB · line 505

Quoted 6 lines
drivers/misc/Kconfig +6 -0
+
+	  The IOP core is DQ8051, so also named IOP8051.
+	  Need Install DQ8051, The DQ8051 bin file generated by keil C.
+	  We will provide users with 8051 normal and standby source code.
+	  Path: https://sunplus.atlassian.net/wiki/spaces/doc/pages/610172933/
+

How+to+use+I+O+processor+8051+of+SP7021#5.-Write-C-or-assembly-source- files-for-IOP

drivers/misc/Kconfig config HISI_HIKEY_USB · line 502

Quoted 1 line
drivers/misc/Kconfig +1 -0
+	  Users can follow the operation steps to generate normal.bin and

standby.bin.

drivers/misc/Kconfig config HISI_HIKEY_USB · line 503

Quoted 1 line
drivers/misc/Kconfig +1 -0
+	  Path:

https://sunplus.atlassian.net/wiki/spaces/doc/pages/466190338/26.+IOP8051

Quoted 32 lines
drivers/misc/Kconfig +5 -0
+	  26.5?How To Create 8051 bin file
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called sunplus_iop.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
drivers/misc/Makefile index renamed from drivers/misc/Makefile +0 -0

a086197..eafeab6 100644

drivers/misc/Makefile +1 -0
@@ -52,6 +52,7 @@ obj-$(CONFIG_DW_XDATA_PCIE)	+= dw-xdata-pcie.o
 obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
 obj-$(CONFIG_OCXL)		+= ocxl/
 obj-$(CONFIG_BCM_VK)		+= bcm-vk/
+obj-$(CONFIG_SUNPLUS_IOP)	+= sunplus_iop.o
 obj-y				+= cardreader/
 obj-$(CONFIG_PVPANIC)   	+= pvpanic/
 obj-$(CONFIG_HABANA_AI)		+= habanalabs/
drivers/misc/sunplus_iop.c new file +7 -0
new file mode 100644 index 0000000..03301b4
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The IOP driver for Sunplus SP7021
+ *
+ * Copyright (C) 2021 Sunplus Technology Inc.
+ *
+ * All Rights Reserved.

drivers/misc/sunplus_iop.c line 17

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+ */
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+

Except comments from Arnd also:

drivers/misc/sunplus_iop.c line 21

Quoted 4 lines
drivers/misc/sunplus_iop.c new file +4 -0
+enum IOP_Status_e {
+	IOP_SUCCESS,		/* successful */
+	IOP_ERR_IOP_BUSY,	/* IOP is busy */
+};

please do not redefine true/false or ERRNO.

Quoted 24 lines
drivers/misc/sunplus_iop.c new file +24 -0
+
+/* moon0 register offset */
+#define IOP_CLKEN0	0x04
+#define IOP_RESET0	0x54
+
+/* IOP register offset */
+#define IOP_CONTROL	0x00
+#define IOP_DATA0	0x20
+#define IOP_DATA1	0x24
+#define IOP_DATA2	0x28
+#define IOP_DATA3	0x2c
+#define IOP_DATA4	0x30
+#define IOP_DATA5	0x34
+#define IOP_DATA6	0x38
+#define IOP_DATA7	0x3c
+#define IOP_DATA8	0x40
+#define IOP_DATA9	0x44
+#define IOP_DATA10	0x48
+#define IOP_DATA11	0x4c
+#define IOP_BASE_ADR_L	0x50
+#define IOP_BASE_ADR_H	0x54
+
+/* PMC register offset */
+#define IOP_PMC_TIMER		0x00

drivers/misc/sunplus_iop.c

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+#define IOP_PMC_CTRL		0x04
+#define IOP_XTAL27M_PASSWORD_I	0x08
+#define IOP_XTAL27M_PASSWORD_II	0x0c
+#define IOP_XTAL32K_PASSWORD_I	0x10
+#define IOP_XTAL32K_PASSWORD_II	0x14
+#define IOP_CLK27M_PASSWORD_I	0x18
+#define IOP_CLK27M_PASSWORD_II	0x1c
+#define IOP_PMC_TIMER2		0x20
+
+#define NORMAL_CODE_MAX_SIZE 0X1000	/* Max size of normal.bin

that can be received */

drivers/misc/sunplus_iop.c line 56

Quoted 1 line
drivers/misc/sunplus_iop.c new file +1 -0
+#define STANDBY_CODE_MAX_SIZE 0x4000	/* Max size of standby.bin

that can be received */

Empty line.

drivers/misc/sunplus_iop.c line 59

Quoted 3 lines
drivers/misc/sunplus_iop.c new file +3 -0
+struct sp_iop {
+	struct device *dev;
+	struct mutex write_lock;	/* avoid parallel access */

This comment is useless. It is obvious that mutex is used to avoid parallel access, what else could it be used?

Instead, you need to describe which members/variables/parts of code are protected with the mutex.

drivers/misc/sunplus_iop.c line 66

Quoted 7 lines
drivers/misc/sunplus_iop.c new file +7 -0
+	void __iomem *iop_regs;
+	void __iomem *pmc_regs;
+	void __iomem *moon0_regs;
+	int irq;
+	int gpio_wakeup;
+	unsigned char iop_normal_code[NORMAL_CODE_MAX_SIZE];
+	unsigned char iop_standby_code[STANDBY_CODE_MAX_SIZE];

Why not using firmware? include/linux/firmware.h? Do not reimplement existing solutions...

drivers/misc/sunplus_iop.c

Quoted 12 lines
drivers/misc/sunplus_iop.c new file +12 -0
+	resource_size_t iop_mem_start;
+	resource_size_t iop_mem_size;
+	unsigned char bin_code_mode;
+};
+
+static struct sp_iop *iop_poweroff;
+
+static void sp_iop_run_normal_code(struct sp_iop *iop) {
+	void __iomem *iop_kernel_base;
+	unsigned int reg;
+
+	iop_kernel_base = ioremap(iop->iop_mem_start,

NORMAL_CODE_MAX_SIZE);

drivers/misc/sunplus_iop.c line 80

Quoted 2 lines
drivers/misc/sunplus_iop.c new file +2 -0
+	memset(iop_kernel_base, 0, NORMAL_CODE_MAX_SIZE);
+	memcpy(iop_kernel_base, iop->iop_normal_code,

NORMAL_CODE_MAX_SIZE);

Quoted 21 lines
drivers/misc/sunplus_iop.c new file +21 -0
+
+	writel(0x00100010, iop->moon0_regs + IOP_CLKEN0);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg |= 0x01;
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg &= ~(0x8000);
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg |= 0x0200;// disable watchdog event reset IOP
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+
+	reg = (iop->iop_mem_start & 0xFFFF);
+	writel(reg, iop->iop_regs + IOP_BASE_ADR_L);
+	reg	= (iop->iop_mem_start >> 16);
+	writel(reg, iop->iop_regs + IOP_BASE_ADR_H);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);

drivers/misc/sunplus_iop.c

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+	reg &= ~(0x01);
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+	iop->bin_code_mode = 0;
+}
+
+static void sp_iop_run_standby_code(struct sp_iop *iop) {
+	void __iomem *iop_kernel_base;
+	unsigned long reg;
+
+	iop_kernel_base = ioremap(iop->iop_mem_start,

STANDBY_CODE_MAX_SIZE);

Quoted 20 lines
drivers/misc/sunplus_iop.c new file +20 -0
+	memset(iop_kernel_base, 0, STANDBY_CODE_MAX_SIZE);
+	memcpy(iop_kernel_base, iop->iop_standby_code,
+STANDBY_CODE_MAX_SIZE);
+
+	writel(0x00100010, iop->moon0_regs + IOP_CLKEN0);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg |= 0x01;
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg &= ~(0x8000);
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg |= 0x0200;// disable watchdog event reset IOP
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+
+	reg = (iop->iop_mem_start & 0xFFFF);
+	writel(reg, iop->iop_regs + IOP_BASE_ADR_L);

drivers/misc/sunplus_iop.c

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+	reg = (iop->iop_mem_start >> 16);
+	writel(reg, iop->iop_regs + IOP_BASE_ADR_H);
+
+	reg = readl(iop->iop_regs + IOP_CONTROL);
+	reg &= ~(0x01);
+	writel(reg, iop->iop_regs + IOP_CONTROL);
+	iop->bin_code_mode = 1;
+}
+
+/* 8051 informs linux kerenl. 8051 has been switched to standby.bin code.

*/

drivers/misc/sunplus_iop.c line 151

Quoted 9 lines
drivers/misc/sunplus_iop.c new file +9 -0
+#define IOP_READY	0x0004
+#define RISC_READY	0x0008
+
+/* System linux kernel tells 8051 which  gpio pin to wake-up through. */
+#define WAKEUP_PIN	0xFE02
+
+/* System linux kernel tells 8051 to execute S1 or S3 mode. */
+#define S1	0x5331
+#define S3	0x5333

Keep defines together, so beginning of file.

drivers/misc/sunplus_iop.c

Quoted 9 lines
drivers/misc/sunplus_iop.c new file +9 -0
+
+static int sp_iop_s3mode(struct device *dev, struct sp_iop *iop) {
+	unsigned int reg;
+	int ret, value;
+
+	/* PMC set */
+	writel(0x00010001, iop->pmc_regs + IOP_PMC_TIMER);
+	reg = readl(iop->pmc_regs + IOP_PMC_CTRL);
+	/* disable system reset PMC, enalbe power down IOP Domain, enable

gating clock 27Mhz */

Quoted 66 lines
drivers/misc/sunplus_iop.c new file +66 -0
+	reg |= 0x23;
+	writel(reg, iop->pmc_regs + IOP_PMC_CTRL);
+
+	writel(0x55aa00ff, iop->pmc_regs + IOP_XTAL27M_PASSWORD_I);
+	writel(0x00ff55aa, iop->pmc_regs + IOP_XTAL27M_PASSWORD_II);
+	writel(0xaa00ff55, iop->pmc_regs + IOP_XTAL32K_PASSWORD_I);
+	writel(0xff55aa00, iop->pmc_regs + IOP_XTAL32K_PASSWORD_II);
+	writel(0xaaff0055, iop->pmc_regs + IOP_CLK27M_PASSWORD_I);
+	writel(0x5500aaff, iop->pmc_regs + IOP_CLK27M_PASSWORD_II);
+	writel(0x01000100, iop->pmc_regs + IOP_PMC_TIMER2);
+
+	/* IOP Hardware IP reset */
+	reg = readl(iop->moon0_regs + IOP_RESET0);
+	reg |= 0x10;
+	writel(reg, (iop->moon0_regs + IOP_RESET0));
+	reg &= ~(0x10);
+	writel(reg, (iop->moon0_regs + IOP_RESET0));
+
+	writel(0x00ff0085, (iop->moon0_regs + 32 * 4 * 1 + 4 * 1));
+
+	reg = readl(iop->moon0_regs + 32 * 4 * 1 + 4 * 2);
+	reg |= 0x08000800;
+	writel(reg, (iop->moon0_regs + 32 * 4 * 1 + 4 * 2));
+
+	writel(WAKEUP_PIN, iop->iop_regs + IOP_DATA0);
+	writel(iop->gpio_wakeup, iop->iop_regs + IOP_DATA1);
+
+	ret = readl_poll_timeout(iop->iop_regs + IOP_DATA2, value,
+				 (value & IOP_READY) == IOP_READY, 1000, 10000);
+	if (ret) {
+		dev_err(dev, "timed out\n");
+		return ret;
+	}
+
+	reg = RISC_READY;
+	writel(reg, iop->iop_regs + IOP_DATA2);
+	reg = 0x0000;
+	writel(reg, iop->iop_regs + IOP_DATA5);
+	reg = 0x0060;
+	writel(reg, iop->iop_regs + IOP_DATA6);
+
+	ret = readl_poll_timeout(iop->iop_regs + IOP_DATA7, value,
+				 value == 0xaaaa, 1000, 10000);
+	if (ret) {
+		dev_err(dev, "timed out\n");
+		return ret;
+	}
+
+	/* 8051 bin file call Ultra low function. */
+	writel(0xdd, iop->iop_regs + IOP_DATA1);
+	/*
+	 * When the execution is here, the system linux kernel
+	 * is about to be powered off
+	 * The purpose of mdelay(10): Do not let the system linux
+	 * kernel continue to run other programs.
+	 */
+	mdelay(10);
+	return 0;
+}
+
+static int sp_iop_s1mode(struct device *dev, struct sp_iop *iop) {
+	int ret, value;
+
+	ret = readl_poll_timeout(iop->iop_regs + IOP_DATA2, value,
+				 (value & IOP_READY) == IOP_READY, 1000, 10000);
+	if (ret) {

drivers/misc/sunplus_iop.c line 238

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+		dev_err(dev, "timed out\n");
+		return ret;
+	}
+
+	writel(RISC_READY, iop->iop_regs + IOP_DATA2);
+	writel(0x0000, iop->iop_regs + IOP_DATA5);
+	writel(0x0060, iop->iop_regs + IOP_DATA6);
+
+	ret = readl_poll_timeout(iop->iop_regs + IOP_DATA7, value,
+				 value == 0xaaaa, 1000, 10000);

Hundreds of magical constants... Almost all of these should be defined or described.

Quoted 82 lines
drivers/misc/sunplus_iop.c new file +82 -0
+	if (ret) {
+		dev_err(dev, "timed out\n");
+		return ret;
+	}
+
+	/* 8051 bin file call S1_mode function. */
+	writel(0xee, iop->iop_regs + IOP_DATA1);
+	/*
+	 * When the execution is here, the system linux kernel
+	 * is about to be powered off
+	 * The purpose of mdelay(10): Do not let the system linux
+	 * kernel continue to run other programs.
+	 */
+	mdelay(10);
+	return 0;
+}
+
+static int  sp_iop_get_normal_code(struct device *dev, struct sp_iop
+*iop) {
+	const struct firmware *fw;
+	static const char file[] = "normal.bin";
+	unsigned int err, i;
+
+	err = request_firmware(&fw, file, dev);
+	if (err) {
+		dev_err(dev, "get bin file error\n");
+		return err;
+	}
+
+	for (i = 0; i < NORMAL_CODE_MAX_SIZE; i++) {
+		char temp;
+
+		temp = fw->data[i];
+		iop->iop_normal_code[i] = temp;
+	}
+	release_firmware(fw);
+	return err;
+}
+
+static int  sp_iop_get_standby_code(struct device *dev, struct sp_iop
+*iop) {
+	const struct firmware *fw;
+	static const char file[] = "standby.bin";
+	unsigned int err, i;
+
+	err = request_firmware(&fw, file, dev);
+	if (err) {
+		dev_err(dev, "get bin file error\n");
+		return err;
+	}
+
+	for (i = 0; i < STANDBY_CODE_MAX_SIZE; i++) {
+		char temp;
+
+		temp = fw->data[i];
+		iop->iop_standby_code[i] = temp;
+	}
+	release_firmware(fw);
+	return err;
+}
+
+static void sp_iop_poweroff(void)
+{
+	struct sp_iop *iop = iop_poweroff;
+	unsigned int ret, value;
+
+	value = readl(iop->iop_regs + IOP_DATA11);
+	sp_iop_run_standby_code(iop);
+
+	ret = readl_poll_timeout(iop->iop_regs + IOP_DATA0, value,
+				 value == 0x2222, 1000, 100000);
+	if (ret)
+		dev_warn(iop->dev, "timed out\n");
+
+	if (value == S1)
+		sp_iop_s1mode(iop->dev, iop);
+	else
+		sp_iop_s3mode(iop->dev, iop);
+}
+
+static int sp_iop_get_resources(struct platform_device *pdev, struct
+sp_iop *p_sp_iop_info) {

drivers/misc/sunplus_iop.c

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+	struct resource *r;
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iop");
+	p_sp_iop_info->iop_regs = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(p_sp_iop_info->iop_regs)) {
+		dev_err(&pdev->dev, "ioremap fail\n");
+		return PTR_ERR(p_sp_iop_info->iop_regs);
+	}
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM,

"iop_pmc");

Quoted 16 lines
drivers/misc/sunplus_iop.c new file +16 -0
+	p_sp_iop_info->pmc_regs = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(p_sp_iop_info->pmc_regs)) {
+		dev_err(&pdev->dev, "ioremap fail\n");
+		return PTR_ERR(p_sp_iop_info->pmc_regs);
+	}
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "moon0");
+	p_sp_iop_info->moon0_regs = devm_ioremap_resource(&pdev->dev, r);
+	if (IS_ERR(p_sp_iop_info->moon0_regs)) {
+		dev_err(&pdev->dev, "ioremap fail\n");
+		return PTR_ERR(p_sp_iop_info->moon0_regs);
+	}
+	return IOP_SUCCESS;
+}
+
+static int sp_iop_platform_driver_probe(struct platform_device *pdev)

drivers/misc/sunplus_iop.c line 356

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+{
+	int ret = -ENXIO;
+	int rc;
+	struct sp_iop *iop;
+	struct device_node *memnp;
+	struct resource mem_res;
+
+	iop = devm_kzalloc(&pdev->dev, sizeof(struct sp_iop), GFP_KERNEL);
+	if (!iop) {
+		ret	= -ENOMEM;

Wrong spacing before '='.

drivers/misc/sunplus_iop.c line 359

Quoted 3 lines
drivers/misc/sunplus_iop.c new file +3 -0
+		goto fail_kmalloc;
+	}
+	/* init */

Remove useless comments.

drivers/misc/sunplus_iop.c line 360

Quoted 1 line
drivers/misc/sunplus_iop.c new file +1 -0
+	mutex_init(&iop->write_lock);

Where are lock/unlock operations? What is this all code? This looks like half-baked solution...

drivers/misc/sunplus_iop.c line 363

Quoted 3 lines
drivers/misc/sunplus_iop.c new file +3 -0
+	ret = sp_iop_get_resources(pdev, iop);
+
+	// Get reserve address

Keep consistent style. For comments /* is preferred. But definitely do not mix one with another.

This code is difficult to read.

drivers/misc/sunplus_iop.c

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+	memnp = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
+	if (!memnp) {
+		dev_err(&pdev->dev, "no memory-region node\n");
+		return -EINVAL;
+	}
+
+	rc = of_address_to_resource(memnp, 0, &mem_res);
+	of_node_put(memnp);
+	if (rc) {
+		dev_err(&pdev->dev, "failed to translate memory-region to a

resource\n");

drivers/misc/sunplus_iop.c

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+		return -EINVAL;
+	}
+
+	iop->dev = &pdev->dev;
+	iop->iop_mem_start = mem_res.start;
+	iop->iop_mem_size = resource_size(&mem_res);
+
+	/*
+	 * 8051 has two bin files, normal.bin and standby.bin in rootfs.
+	 * Normally, 8051 executes normal.bin code. Normal.bin code size can

exceed 16K.

drivers/misc/sunplus_iop.c line 381

Quoted 1 line
drivers/misc/sunplus_iop.c new file +1 -0
+	 * When system linux kernel is shutdown, 8051 is to execute standby.bin

code.

drivers/misc/sunplus_iop.c line 382

Quoted 1 line
drivers/misc/sunplus_iop.c new file +1 -0
+	 * Standby.bin code cannot exceed 16K bytes. Because 8051 Icache size is

16k.

drivers/misc/sunplus_iop.c line 383

Quoted 1 line
drivers/misc/sunplus_iop.c new file +1 -0
+	 * 8051 runs with standby.bin code in the Icache before the system(linux

kernel)

Quoted 7 lines
drivers/misc/sunplus_iop.c new file +7 -0
+	 * is poweroff.
+	 */
+	ret = sp_iop_get_normal_code(&pdev->dev, iop);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "get normal code err=%d\n", ret);
+		return ret;
+	}

drivers/misc/sunplus_iop.c

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+
+	ret = sp_iop_get_standby_code(&pdev->dev, iop);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "get standby code err=%d\n", ret);
+		return ret;
+	}
+
+	sp_iop_run_normal_code(iop);
+	platform_set_drvdata(pdev, iop);
+	iop->gpio_wakeup = of_get_named_gpio(pdev->dev.of_node,

"iop-wakeup", 0);

drivers/misc/sunplus_iop.c line 405

Quoted 2 lines
drivers/misc/sunplus_iop.c new file +2 -0
+	iop_poweroff = iop;
+	pm_power_off = sp_iop_poweroff;

Blank line. Before every such return. Please, open some recent drivers and look at their code style.

Quoted 21 lines
drivers/misc/sunplus_iop.c new file +21 -0
+	return 0;
+
+fail_kmalloc:
+	return ret;
+}
+
+static int sp_iop_remove(struct platform_device *pdev) {
+	pm_power_off = NULL;
+	return 0;
+}
+
+static const struct of_device_id sp_iop_of_match[] = {
+	{ .compatible = "sunplus,sp7021-iop" },
+	{ /* sentinel */ },
+};
+
+MODULE_DEVICE_TABLE(of, sp_iop_of_match);
+
+static struct platform_driver sp_iop_platform_driver = {
+	.probe		= sp_iop_platform_driver_probe,
+	.remove		= sp_iop_remove,

drivers/misc/sunplus_iop.c

Quoted 10 lines
drivers/misc/sunplus_iop.c new file +10 -0
+	.driver = {
+		.name	= "sunplus,sp7021-iop",
+		.of_match_table = sp_iop_of_match,
+	}
+};
+
+module_platform_driver(sp_iop_platform_driver);
+
+MODULE_AUTHOR("Tony Huang <[email protected]>");
+MODULE_DESCRIPTION("Sunplus IOP Driver"); MODULE_LICENSE("GPL

v2");

Best regards,
Krzysztof