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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

> Subject: Re: [PATCH v10 2/2] misc: Add iop driver for Sunplus SP7021
> 
> On 07/03/2022 06:25, Tony Huang wrote:
> > 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.
> >
> > Signed-off-by: Tony Huang <tonyhuang.sunplus@xxxxxxxxx>
> > ---
> > 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
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS index 6f336c9..11ecefa 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -18246,6 +18246,7 @@ SUNPLUS IOP DRIVER
> >  M:	Tony Huang <tonyhuang.sunplus@xxxxxxxxx>
> >  S:	Maintained
> >  F:	Documentation/devicetree/bindings/misc/sunplu-iop.yaml
> > +F:	drivers/misc/sunplus_iop.c
> >
> >  SUPERH
> >  M:	Yoshinori Sato <ysato@xxxxxxxxxxxxxxxxxxxx>
> > diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index
> > 0f5a49f..3106f15 100644
> > --- a/drivers/misc/Kconfig
> > +++ b/drivers/misc/Kconfig
> > @@ -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"
> > diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index
> > a086197..eafeab6 100644
> > --- a/drivers/misc/Makefile
> > +++ b/drivers/misc/Makefile
> > @@ -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/
> > diff --git a/drivers/misc/sunplus_iop.c b/drivers/misc/sunplus_iop.c
> > new file mode 100644 index 0000000..03301b4
> > --- /dev/null
> > +++ b/drivers/misc/sunplus_iop.c
> > @@ -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.
> > + */
> > +#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:
> 
> > +enum IOP_Status_e {
> > +	IOP_SUCCESS,		/* successful */
> > +	IOP_ERR_IOP_BUSY,	/* IOP is busy */
> > +};
> 
> please do not redefine true/false or ERRNO.
> 
> > +
> > +/* 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
> > +#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.
> 
> > +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.
> 
> > +	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...
> 
> > +	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;
> > +}
> > +
> > +/* 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.
> 
> > +
> > +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) {
> > +		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.
> 
> > +	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)
> > +{
> > +	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 '='.
> 
> > +		goto fail_kmalloc;
> > +	}
> > +	/* init */
> 
> Remove useless comments.
> 
> > +	mutex_init(&iop->write_lock);
> 
> Where are lock/unlock operations? What is this all code? This looks like
> half-baked solution...
> 
> > +	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.
> 
> > +	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);
> > +	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.
> 
> > +	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 = {
> > +		.name	= "sunplus,sp7021-iop",
> > +		.of_match_table = sp_iop_of_match,
> > +	}
> > +};
> > +
> > +module_platform_driver(sp_iop_platform_driver);
> > +
> > +MODULE_AUTHOR("Tony Huang <tonyhuang.sunplus@xxxxxxxxx>");
> > +MODULE_DESCRIPTION("Sunplus IOP Driver"); MODULE_LICENSE("GPL
> v2");
> 
> 
> Best regards,
> Krzysztof




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux