diff mbox

[U-Boot,v1,8/8] lpc32xx: add support for board work_92105

Message ID 1421392760-21810-9-git-send-email-albert.aribaud@3adev.fr
State Superseded
Delegated to: Tom Rini
Headers show

Commit Message

Albert ARIBAUD (3ADEV) Jan. 16, 2015, 7:19 a.m. UTC
Work_92105 from Work Microwave is an LPC3250-
based board with the following features:
- 64MB SDR DRAM
- 1 GB SLC NAND, managed through MLC controller.
- Ethernet
- Ethernet + PHY SMSC8710
- I2C:
  - EEPROM (24M01-compatible)
  - RTC (DS1374-compatible)
  - Temperature sensor (DS620)
  - DACs (2 x MAX518)
- SPI (through SSP interface)
  - Port expander MAX6957
- LCD display (HD44780-compatible), controlled
  through the port expander and DACs

This board has SPL support, and uses the LPC32XX boot
image format.

Signed-off-by: Albert ARIBAUD (3ADEV) <albert.aribaud@3adev.fr>
---

 arch/arm/Kconfig                                   |   6 +
 arch/arm/cpu/arm926ejs/lpc32xx/Makefile            |   2 +
 arch/arm/cpu/arm926ejs/lpc32xx/clk.c               |  34 ++
 arch/arm/cpu/arm926ejs/lpc32xx/cpu.c               |   4 +
 arch/arm/cpu/arm926ejs/lpc32xx/dram.c              |  80 +++++
 arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S     |  45 +++
 arch/arm/include/asm/arch-lpc32xx/clk.h            |   5 +
 arch/arm/include/asm/arch-lpc32xx/sys_proto.h      |   4 +-
 board/work-microwave/work_92105/Kconfig            |  15 +
 board/work-microwave/work_92105/MAINTAINERS        |   6 +
 board/work-microwave/work_92105/Makefile           |   8 +
 board/work-microwave/work_92105/README             |  23 ++
 board/work-microwave/work_92105/work_92105.c       |  85 +++++
 .../work-microwave/work_92105/work_92105_display.c | 345 +++++++++++++++++++++
 .../work-microwave/work_92105/work_92105_display.h |  14 +
 configs/work_92105_defconfig                       |   3 +
 drivers/hwmon/ds620.c                              |   1 +
 include/configs/work_92105.h                       | 257 +++++++++++++++
 18 files changed, 936 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/cpu/arm926ejs/lpc32xx/dram.c
 create mode 100644 arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S
 create mode 100644 board/work-microwave/work_92105/Kconfig
 create mode 100644 board/work-microwave/work_92105/MAINTAINERS
 create mode 100644 board/work-microwave/work_92105/Makefile
 create mode 100644 board/work-microwave/work_92105/README
 create mode 100644 board/work-microwave/work_92105/work_92105.c
 create mode 100644 board/work-microwave/work_92105/work_92105_display.c
 create mode 100644 board/work-microwave/work_92105/work_92105_display.h
 create mode 100644 configs/work_92105_defconfig
 create mode 100644 include/configs/work_92105.h
diff mbox

Patch

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 5eb1d03..0907136 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -238,6 +238,11 @@  config TARGET_DEVKIT3250
 	bool "Support devkit3250"
 	select CPU_ARM926EJS
 
+config TARGET_WORK_92105
+	bool "Support work_92105"
+	select CPU_ARM926EJS
+	select SUPPORT_SPL
+
 config TARGET_JADECPU
 	bool "Support jadecpu"
 	select CPU_ARM926EJS
@@ -981,6 +986,7 @@  source "board/udoo/Kconfig"
 source "board/vpac270/Kconfig"
 source "board/wandboard/Kconfig"
 source "board/woodburn/Kconfig"
+source "board/work-microwave/work_92105/Kconfig"
 source "board/xaeniax/Kconfig"
 source "board/zipitz2/Kconfig"
 
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/Makefile b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile
index 314f004..4837377 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/Makefile
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile
@@ -6,3 +6,5 @@ 
 #
 
 obj-y   = cpu.o clk.o devices.o timer.o
+
+obj-$(CONFIG_SPL_BUILD) += dram.o lowlevel_init.o
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/clk.c b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c
index b7a44d5..1ef8a36 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/clk.c
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c
@@ -98,6 +98,40 @@  unsigned int get_periph_clk_rate(void)
 	return get_hclk_pll_rate() / get_periph_clk_div();
 }
 
+unsigned int get_sdram_clk_rate(void)
+{
+	unsigned int src_clk;
+
+	if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN))
+		return get_sys_clk_rate();
+
+	src_clk = get_hclk_pll_rate();
+
+	if (readl(&clk->sdramclk_ctrl) & CLK_SDRAM_DDR_SEL) {
+		/* using DDR */
+		switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_DDRAM_MASK) {
+		case CLK_HCLK_DDRAM_HALF:
+			return src_clk/2;
+		case CLK_HCLK_DDRAM_NOMINAL:
+			return src_clk;
+		default:
+			return 0;
+		}
+	} else {
+		/* using SDR */
+		switch (readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK) {
+		case CLK_HCLK_ARM_PLL_DIV_4:
+			return src_clk/4;
+		case CLK_HCLK_ARM_PLL_DIV_2:
+			return src_clk/2;
+		case CLK_HCLK_ARM_PLL_DIV_1:
+			return src_clk;
+		default:
+			return 0;
+		}
+	}
+}
+
 int get_serial_clock(void)
 {
 	return get_periph_clk_rate();
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
index eec4d9e..f4d7f02 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c
@@ -9,6 +9,7 @@ 
 #include <asm/arch/cpu.h>
 #include <asm/arch/clk.h>
 #include <asm/arch/wdt.h>
+#include <asm/arch/sys_proto.h>
 #include <asm/io.h>
 
 static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
@@ -33,6 +34,9 @@  void reset_cpu(ulong addr)
 #if defined(CONFIG_ARCH_CPU_INIT)
 int arch_cpu_init(void)
 {
+#if defined(CONFIG_SPL_BUILD)
+	ddr_init();
+#endif
 	/*
 	 * It might be necessary to flush data cache, if U-boot is loaded
 	 * from kickstart bootloader, e.g. from S1L loader
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/dram.c b/arch/arm/cpu/arm926ejs/lpc32xx/dram.c
new file mode 100644
index 0000000..606f49d
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/dram.c
@@ -0,0 +1,80 @@ 
+/*
+ * LPC32xx dram init
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * This is called by SPL to gain access to the SDR DRAM.
+ *
+ * This code runs from SRAM.
+ *
+ * Actual CONFIG_LPC32XX_SDRAM_* parameters must be provided
+ * by the board configuration file.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <netdev.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/wdt.h>
+#include <asm/arch/emc.h>
+#include <asm/io.h>
+
+static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE;
+static struct emc_regs *emc = (struct emc_regs *)EMC_BASE;
+
+#if defined(CONFIG_SPL_BUILD)
+
+void ddr_init(void)
+{
+	uint32_t ck;
+
+	/* Enable EMC interface and choose little endian mode */
+	emc->ctrl = 1;
+	emc->config = 0;
+	/* Select maximum EMC Dynamic Memory Refresh Time */
+	emc->refresh = 0x7FF;
+	/* Determine CLK */
+	ck = get_sdram_clk_rate();
+	/* Configure SDRAM */
+	clk->sdramclk_ctrl = (CONFIG_LPC32XX_SDRAM_COMMAND_DELAY << 14);
+	emc->config0 = CONFIG_LPC32XX_SDRAM_CONFIG0;
+	emc->rascas0 = CONFIG_LPC32XX_SDRAM_RASCAS0;
+	emc->read_config = CONFIG_LPC32XX_SDRAM_READ_CONFIG;
+	/* Set timings */
+	emc->t_rp = (ck / CONFIG_LPC32XX_SDRAM_T_RP) & 0x0000000F;
+	emc->t_ras = (ck / CONFIG_LPC32XX_SDRAM_T_RAS) & 0x0000000F;
+	emc->t_srex = (ck / CONFIG_LPC32XX_SDRAM_T_SREX) & 0x0000007F;
+	emc->t_wr = (ck / CONFIG_LPC32XX_SDRAM_T_WR) & 0x0000000F;
+	emc->t_rc = (ck / CONFIG_LPC32XX_SDRAM_T_RC) & 0x0000001F;
+	emc->t_rfc = (ck / CONFIG_LPC32XX_SDRAM_T_RFC) & 0x0000001F;
+	emc->t_xsr = (ck / CONFIG_LPC32XX_SDRAM_T_XSR) & 0x000000FF;
+	emc->t_rrd = CONFIG_LPC32XX_SDRAM_T_RRD;
+	emc->t_mrd = CONFIG_LPC32XX_SDRAM_T_MRD;
+	emc->t_cdlr = CONFIG_LPC32XX_SDRAM_T_CDLR;
+	/* Dynamic refresh */
+	emc->refresh = (((ck / CONFIG_LPC32XX_SDRAM_REFRESH) >> 4) & 0x7FF);
+	udelay(10);
+	/* Force all clocks, enable inverted ck, issue NOP command */
+	emc->control = 0x00000193;
+	udelay(100);
+	/* Keep all clocks enabled, issue a PRECHARGE ALL command */
+	emc->control = 0x00000113;
+	/* Fast dynamic refresh for at least a few SDRAM ck cycles */
+	emc->refresh = (((128) >> 4) & 0x7FF);
+	udelay(10);
+	/* set correct dynamic refresh timing */
+	emc->refresh = (((ck / CONFIG_LPC32XX_SDRAM_REFRESH) >> 4) & 0x7FF);
+	udelay(10);
+	/* set normal mode to CAS=3 */
+	emc->control = 0x00000093;
+	readl(EMC_DYCS0_BASE | CONFIG_LPC32XX_DRAM_MODE);
+	/* set extended mode to all zeroes */
+	emc->control = 0x00000093;
+	readl(EMC_DYCS0_BASE | CONFIG_LPC32XX_DRAM_EMODE);
+	/* stop forcing clocks, keep inverted clock, issue normal mode */
+	emc->control = 0x00000010;
+}
+#endif
diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S b/arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S
new file mode 100644
index 0000000..4b8053e
--- /dev/null
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/lowlevel_init.S
@@ -0,0 +1,45 @@ 
+/*
+ * WORK Microwave work_92105 board low level init
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * Low level init is called from SPL to set up the clocks.
+ * On entry, the LPC3250 is in Direct Run mode with all clocks
+ * running at 13 MHz; on exit, ARM clock is 208 MHz, HCLK is
+ * 104 MHz and PCLK is 13 MHz.
+ *
+ * This code must run from SRAM so that the clock changes do
+ * not prevent it from executing.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+.globl lowlevel_init
+
+lowlevel_init:
+
+	/* Set ARM, HCLK, PCLK dividers for normal mode */
+	ldr	r0, =0x0000003D
+	ldr	r1, =0x40004040
+	str	r0, [r1]
+
+	/* Start HCLK PLL for 208 MHz */
+	ldr	r0, =0x0001401E
+	ldr	r1, =0x40004058
+	str	r0, [r1]
+
+	/* wait for HCLK PLL to lock */
+1:
+	ldr	r0, [r1]
+	ands	r0, r0, #1
+	beq	1b
+
+	/* switch to normal mode */
+	ldr	r1, =0x40004044
+	ldr	r0, [r1]
+	orr	r0, #0x00000004
+	str	r0, [r1]
+
+	/* Return to U-boot via saved link register */
+	mov	pc, lr
diff --git a/arch/arm/include/asm/arch-lpc32xx/clk.h b/arch/arm/include/asm/arch-lpc32xx/clk.h
index 2cb5703..9449869 100644
--- a/arch/arm/include/asm/arch-lpc32xx/clk.h
+++ b/arch/arm/include/asm/arch-lpc32xx/clk.h
@@ -71,6 +71,7 @@  struct clk_pm_regs {
 };
 
 /* HCLK Divider Control Register bits */
+#define CLK_HCLK_DDRAM_MASK		(0x3 << 7)
 #define CLK_HCLK_DDRAM_HALF		(0x2 << 7)
 #define CLK_HCLK_DDRAM_NOMINAL		(0x1 << 7)
 #define CLK_HCLK_DDRAM_STOPPED		(0x0 << 7)
@@ -158,11 +159,15 @@  struct clk_pm_regs {
 /* SSP Clock Control Register bits */
 #define CLK_SSP0_ENABLE_CLOCK		(1 << 0)
 
+/* SDRAMCLK register bits */
+#define CLK_SDRAM_DDR_SEL		(1 << 1)
+
 unsigned int get_sys_clk_rate(void);
 unsigned int get_hclk_pll_rate(void);
 unsigned int get_hclk_clk_div(void);
 unsigned int get_hclk_clk_rate(void);
 unsigned int get_periph_clk_div(void);
 unsigned int get_periph_clk_rate(void);
+unsigned int get_sdram_clk_rate(void);
 
 #endif /* _LPC32XX_CLK_H */
diff --git a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
index 86d5ee9..edcc4bc 100644
--- a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
+++ b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
@@ -12,5 +12,7 @@  void lpc32xx_mac_init(void);
 void lpc32xx_mlc_nand_init(void);
 void lpc32xx_i2c_init(unsigned int devnum);
 void lpc32xx_ssp_init(void);
-
+#if defined(CONFIG_SPL_BUILD)
+void ddr_init(void);
+#endif
 #endif /* _LPC32XX_SYS_PROTO_H */
diff --git a/board/work-microwave/work_92105/Kconfig b/board/work-microwave/work_92105/Kconfig
new file mode 100644
index 0000000..74f004f
--- /dev/null
+++ b/board/work-microwave/work_92105/Kconfig
@@ -0,0 +1,15 @@ 
+if TARGET_WORK_92105
+
+config SYS_BOARD
+	default "work_92105"
+
+config SYS_VENDOR
+	default "work-microwave"
+
+config SYS_SOC
+	default "lpc32xx"
+
+config SYS_CONFIG_NAME
+	default "work_92105"
+
+endif
diff --git a/board/work-microwave/work_92105/MAINTAINERS b/board/work-microwave/work_92105/MAINTAINERS
new file mode 100644
index 0000000..29a92c5
--- /dev/null
+++ b/board/work-microwave/work_92105/MAINTAINERS
@@ -0,0 +1,6 @@ 
+WORK_92105 BOARD
+M:	Albert ARIBAUD <albert.aribaud@3adev.fr>
+S:	Maintained
+F:	board/work-microwave/work_92105/
+F:	include/configs/work_92105.h
+F:	configs/work_92105_defconfig
diff --git a/board/work-microwave/work_92105/Makefile b/board/work-microwave/work_92105/Makefile
new file mode 100644
index 0000000..853dea9
--- /dev/null
+++ b/board/work-microwave/work_92105/Makefile
@@ -0,0 +1,8 @@ 
+#
+# (C) Copyright 2014  DENX Software Engineering GmbH
+# Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= work_92105.o work_92105_display.o
diff --git a/board/work-microwave/work_92105/README b/board/work-microwave/work_92105/README
new file mode 100644
index 0000000..091d731
--- /dev/null
+++ b/board/work-microwave/work_92105/README
@@ -0,0 +1,23 @@ 
+Work_92105 from Work Microwave is an LPC3250- based board with the
+following features:
+
+    - 64MB SDR DRAM
+    - 1 GB SLC NAND, managed through MLC controller.
+    - Ethernet
+    - Ethernet + PHY SMSC8710
+    - I2C:
+      - EEPROM (24M01-compatible)
+      - RTC (DS1374-compatible)
+      - Temperature sensor (DS620)
+      - DACs (2 x MAX518)
+    - SPI (through SSP interface)
+      - Port expander MAX6957
+    - LCD display (HD44780-compatible), controlled
+      through the port expander and DACs
+
+This board has SPL support, and uses the LPC32XX boot image format.
+Once the U-Boot target "work_92105" is built, the following two files
+can be flashed:
+
+	spl/lpc32xx-spl.bin at offset 0x0
+	u-boot.bin at offset 0x40000
diff --git a/board/work-microwave/work_92105/work_92105.c b/board/work-microwave/work_92105/work_92105.c
new file mode 100644
index 0000000..399a7cd
--- /dev/null
+++ b/board/work-microwave/work_92105/work_92105.c
@@ -0,0 +1,85 @@ 
+/*
+ * WORK Microwave work_92105 board support
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/emc.h>
+#include <asm/gpio.h>
+#include <spl.h>
+#include "work_92105_display.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if defined(CONFIG_SPL_BUILD)
+
+void spl_board_init(void)
+{
+	/* initialize serial port for console */
+	lpc32xx_uart_init(CONFIG_SYS_LPC32XX_UART);
+	/* initialize console */
+	preloader_console_init();
+	/* init DDR and NAND to chainload U-Boot */
+	ddr_init();
+	lpc32xx_mlc_nand_init();
+}
+
+#else /* ! defined(CONFIG_SPL_BUILD) */
+
+int board_early_init_f(void)
+{
+	/* initialize serial port for console */
+	lpc32xx_uart_init(CONFIG_SYS_LPC32XX_UART);
+	/* enable I2C, SSP, MAC, NAND */
+	lpc32xx_i2c_init(1); /* only I2C1 has devices, I2C2 has none */
+	lpc32xx_ssp_init();
+	lpc32xx_mac_init();
+	lpc32xx_mlc_nand_init();
+	/* Display must wait until after relocation and devices init */
+	return 0;
+}
+
+#define GPO_19 115
+
+int board_early_init_r(void)
+{
+	/* Set NAND !WP to 1 through GPO_19 */
+	gpio_set_value(GPO_19, 1);
+
+	/* initialize display */
+	work_92105_display_init();
+
+	return 0;
+}
+
+#endif /* CONFIG_SPL_BUILD */
+
+int board_init(void)
+{
+	/* adress of boot parameters */
+	gd->bd->bi_boot_params  = CONFIG_SYS_SDRAM_BASE + 0x100;
+
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE,
+				    CONFIG_SYS_SDRAM_SIZE);
+
+	return 0;
+}
+
+#if defined(CONFIG_SPL_BUILD)
+u32 spl_boot_device(void)
+{
+	return BOOT_DEVICE_NAND;
+}
+#endif
diff --git a/board/work-microwave/work_92105/work_92105_display.c b/board/work-microwave/work_92105/work_92105_display.c
new file mode 100644
index 0000000..31d945e
--- /dev/null
+++ b/board/work-microwave/work_92105/work_92105_display.c
@@ -0,0 +1,345 @@ 
+/*
+ * work_92105 display support
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * The work_92105 display is a HD44780-compatible module
+ * controlled through a MAX6957AAX SPI port expander, two
+ * MAX518 I2C DACs and native LPC32xx GPO 15.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/emc.h>
+#include <asm/gpio.h>
+#include <spi.h>
+#include <i2c.h>
+#include <version.h>
+#include <vsprintf.h>
+
+/*
+ * GPO 15 in port 3 is gpio 3*32+15 = 111
+ */
+
+#define GPO_15 111
+
+/**
+ * MAX6957AAX registers that we will be using
+ */
+
+#define MAX6957_CONF		0x04
+
+#define MAX6957_CONF_08_11	0x0A
+#define MAX6957_CONF_12_15	0x0B
+#define MAX6957_CONF_16_19	0x0C
+
+/**
+ * Individual gpio ports (one per gpio) to HD44780
+ */
+
+#define MAX6957AAX_HD44780_RS	0x29
+#define MAX6957AAX_HD44780_R_W	0x2A
+#define MAX6957AAX_HD44780_EN	0x2B
+#define MAX6957AAX_HD44780_DATA	0x4C
+
+/**
+ * Display controller instructions
+ */
+
+/* Function set: eight bits, two lines, 8-dot font */
+#define HD44780_FUNCTION_SET		0x38
+
+/* Display ON / OFF: turn display on */
+#define HD44780_DISPLAY_ON_OFF_CONTROL	0x0C
+
+/* Entry mode: increment */
+#define HD44780_ENTRY_MODE_SET		0x06
+
+/* Clear */
+#define HD44780_CLEAR_DISPLAY		0x01
+
+/* Set DDRAM addr (to be ORed with exact address) */
+#define HD44780_SET_DDRAM_ADDR		0x80
+
+/* Set CGRAM addr (to be ORed with exact address) */
+#define HD44780_SET_CGRAM_ADDR		0x40
+
+/**
+ * Default value for contrats
+ */
+
+#define CONTRAST_DEFAULT  25
+
+/**
+ * Define slave as a module-wide local to save passing it around,
+ * plus we will need it after init for the "hd44780" command.
+ */
+
+static struct spi_slave *slave;
+
+/*
+ * Write a value into a MAX6957AAX register.
+ */
+
+static void max6957aax_write(uint8_t reg, uint8_t value)
+{
+	uint8_t dout[2];
+
+	dout[0] = reg;
+	dout[1] = value;
+	gpio_set_value(GPO_15, 0);
+	/* do SPI read/write (passing din==dout is OK) */
+	spi_xfer(slave, 16, dout, dout, SPI_XFER_BEGIN | SPI_XFER_END);
+	gpio_set_value(GPO_15, 1);
+}
+
+/*
+ * Read a value from a MAX6957AAX register.
+ *
+ * According to the MAX6957AAX datasheet, we should release the chip
+ * select halfway through the read sequence, when the actual register
+ * value is read; but the WORK_92105 hardware prevents the MAX6957AAX
+ * SPI OUT from reaching the LPC32XX SIP MISO if chip is not selected.
+ * so let's release the CS an hold it again while reading the result.
+ */
+
+static uint8_t max6957aax_read(uint8_t reg)
+{
+	uint8_t dout[2], din[2];
+
+	/* send read command */
+	dout[0] = reg | 0x80; /* set bit 7 to indicate read */
+	dout[1] = 0;
+	gpio_set_value(GPO_15, 0);
+	/* do SPI read/write (passing din==dout is OK) */
+	spi_xfer(slave, 16, dout, dout, SPI_XFER_BEGIN | SPI_XFER_END);
+	/* latch read command */
+	gpio_set_value(GPO_15, 1);
+	/* read register -- din = noop on xmit, din[1] = reg on recv */
+	din[0] = 0;
+	din[1] = 0;
+	gpio_set_value(GPO_15, 0);
+	/* do SPI read/write (passing din==dout is OK) */
+	spi_xfer(slave, 16, din, din, SPI_XFER_BEGIN | SPI_XFER_END);
+	/* end of read. */
+	gpio_set_value(GPO_15, 1);
+	return din[1];
+}
+
+static void hd44780_instruction(unsigned long instruction)
+{
+	max6957aax_write(MAX6957AAX_HD44780_RS, 0);
+	max6957aax_write(MAX6957AAX_HD44780_R_W, 0);
+	max6957aax_write(MAX6957AAX_HD44780_EN, 1);
+	max6957aax_write(MAX6957AAX_HD44780_DATA, instruction);
+	max6957aax_write(MAX6957AAX_HD44780_EN, 0);
+	/* HD44780 takes 37 us for most instructions, 1520 for clear */
+	if (instruction == HD44780_CLEAR_DISPLAY)
+		udelay(2000);
+	else
+		udelay(100);
+}
+
+static void hd44780_write_char(char c)
+{
+	max6957aax_write(MAX6957AAX_HD44780_RS, 1);
+	max6957aax_write(MAX6957AAX_HD44780_R_W, 0);
+	max6957aax_write(MAX6957AAX_HD44780_EN, 1);
+	max6957aax_write(MAX6957AAX_HD44780_DATA, c);
+	max6957aax_write(MAX6957AAX_HD44780_EN, 0);
+	/* HD44780 takes 37 us to write to DDRAM or CGRAM */
+	udelay(100);
+}
+
+static void hd44780_write_str(char *s)
+{
+	max6957aax_write(MAX6957AAX_HD44780_RS, 1);
+	max6957aax_write(MAX6957AAX_HD44780_R_W, 0);
+	while (*s) {
+		max6957aax_write(MAX6957AAX_HD44780_EN, 1);
+		max6957aax_write(MAX6957AAX_HD44780_DATA, *s);
+		max6957aax_write(MAX6957AAX_HD44780_EN, 0);
+		s++;
+		/* HD44780 takes 37 us to write to DDRAM or CGRAM */
+		udelay(100);
+	}
+}
+
+/*
+ * Existing user code might expect these custom characters to be
+ * recognized and displayed on the LCD
+ */
+
+static u8 char_gen_chars[] = {
+	/* #8, empty rectangle */
+	0x1F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1F,
+	/* #9, filled right arrow */
+	0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00,
+	/* #10, filled left arrow */
+	0x01, 0x03, 0x07, 0x0F, 0x07, 0x03, 0x01, 0x00,
+	/* #11, up and down arrow */
+	0x04, 0x0E, 0x1F, 0x00, 0x00, 0x1F, 0x0E, 0x04,
+	/* #12, plus/minus */
+	0x04, 0x04, 0x1F, 0x04, 0x04, 0x00, 0x1F, 0x00,
+	/* #13, fat exclamation mark */
+	0x06, 0x06, 0x06, 0x06, 0x00, 0x06, 0x06, 0x00,
+	/* #14, empty square */
+	0x00, 0x1F, 0x11, 0x11, 0x11, 0x1F, 0x00, 0x00,
+	/* #15, struck out square */
+	0x00, 0x1F, 0x19, 0x15, 0x13, 0x1F, 0x00, 0x00,
+};
+
+static void hd44780_init_char_gen(void)
+{
+	int i;
+
+	hd44780_instruction(HD44780_SET_CGRAM_ADDR);
+
+	for (i = 0; i < sizeof(char_gen_chars); i++)
+		hd44780_write_char(char_gen_chars[i]);
+
+	hd44780_instruction(HD44780_SET_DDRAM_ADDR);
+}
+
+void work_92105_display_init(void)
+{
+	int claim_err;
+	char *display_contrast_str;
+	uint8_t display_contrast = CONTRAST_DEFAULT;
+	uint8_t enable_backlight = 0x96;
+
+	slave = spi_setup_slave(0, 0, 500000, 0);
+
+	if (!slave) {
+		printf("Failed to set up SPI slave\n");
+		return;
+	}
+
+	claim_err = spi_claim_bus(slave);
+
+	if (claim_err)
+		debug("Failed to claim SPI bus: %d\n", claim_err);
+
+	/* enable backlight */
+	i2c_write(0x2c, 0x01, 1, &enable_backlight, 1);
+
+	/* set display contrast */
+	display_contrast_str = getenv("fwopt_dispcontrast");
+	if (display_contrast_str)
+		display_contrast = simple_strtoul(display_contrast_str,
+			NULL, 10);
+	i2c_write(0x2c, 0x00, 1, &display_contrast, 1);
+
+	/* enable MAX6957 portexpander */
+	max6957aax_write(MAX6957_CONF, 0x01);
+	/* configure pin 8 as input, pins 9..19 as outputs */
+	max6957aax_write(MAX6957_CONF_08_11, 0x56);
+	max6957aax_write(MAX6957_CONF_12_15, 0x55);
+	max6957aax_write(MAX6957_CONF_16_19, 0x55);
+
+	/* initialize HD44780 */
+	max6957aax_write(MAX6957AAX_HD44780_EN, 0);
+	hd44780_instruction(HD44780_FUNCTION_SET);
+	hd44780_instruction(HD44780_DISPLAY_ON_OFF_CONTROL);
+	hd44780_instruction(HD44780_ENTRY_MODE_SET);
+
+	/* write custom character glyphs */
+	hd44780_init_char_gen();
+
+	/* Show U-Boot version, date and time as a sign-of-life */
+	hd44780_instruction(HD44780_CLEAR_DISPLAY);
+	hd44780_instruction(HD44780_SET_DDRAM_ADDR | 0);
+	hd44780_write_str(U_BOOT_VERSION);
+	hd44780_instruction(HD44780_SET_DDRAM_ADDR | 64);
+	hd44780_write_str(U_BOOT_DATE);
+	hd44780_instruction(HD44780_SET_DDRAM_ADDR | 64 | 20);
+	hd44780_write_str(U_BOOT_TIME);
+}
+
+#ifdef CONFIG_CMD_MAX6957
+
+static int do_max6957aax(cmd_tbl_t *cmdtp, int flag, int argc,
+			 char *const argv[])
+{
+	int reg, val;
+
+	if (argc != 3)
+		return CMD_RET_USAGE;
+	switch (argv[1][0]) {
+	case 'r':
+	case 'R':
+		reg = simple_strtoul(argv[2], NULL, 0);
+		val = max6957aax_read(reg);
+		printf("MAX6957 reg 0x%02x read 0x%02x\n", reg, val);
+		return 0;
+	default:
+		reg = simple_strtoul(argv[1], NULL, 0);
+		val = simple_strtoul(argv[2], NULL, 0);
+		max6957aax_write(reg, val);
+		printf("MAX6957 reg 0x%02x wrote 0x%02x\n", reg, val);
+		return 0;
+	}
+	return 1;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char max6957aax_help_text[] =
+	"max6957aax - write or read display register:\n"
+		"\tmax6957aax R|r reg - read display register;\n"
+		"\tmax6957aax reg val - write display register.";
+#endif
+
+U_BOOT_CMD(
+	max6957aax, 6, 1, do_max6957aax,
+	"SPI MAX6957 display write/read",
+	max6957aax_help_text
+);
+#endif /* CONFIG_CMD_MAX6957 */
+
+#ifdef CONFIG_CMD_HD44760
+
+/*
+ * We need the HUSH parser because we need string arguments, and
+ * only HUSH can understand them.
+ */
+
+#if !defined(CONFIG_SYS_HUSH_PARSER)
+#error CONFIG_CMD_HD44760 requires CONFIG_SYS_HUSH_PARSER
+#endif
+
+static int do_hd44780(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	char *cmd;
+
+	if (argc != 3)
+		return CMD_RET_USAGE;
+
+	cmd = argv[1];
+
+	if (strcasecmp(cmd, "cmd") == 0)
+		hd44780_instruction(simple_strtol(argv[2], NULL, 0));
+	else if (strcasecmp(cmd, "data") == 0)
+		hd44780_write_char(simple_strtol(argv[2], NULL, 0));
+	else if (strcasecmp(cmd, "str") == 0)
+		hd44780_write_str(argv[2]);
+	return 0;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char hd44780_help_text[] =
+	"hd44780 - control LCD driver:\n"
+		"\thd44780 cmd <val> - send command <val> to driver;\n"
+		"\thd44780 data <val> - send data <val> to driver;\n"
+		"\thd44780 str \"<text>\" - send \"<text>\" to driver.";
+#endif
+
+U_BOOT_CMD(
+	hd44780, 6, 1, do_hd44780,
+	"HD44780 LCD driver control",
+	hd44780_help_text
+);
+#endif /* CONFIG_CMD_HD44780 */
diff --git a/board/work-microwave/work_92105/work_92105_display.h b/board/work-microwave/work_92105/work_92105_display.h
new file mode 100644
index 0000000..dd6e768
--- /dev/null
+++ b/board/work-microwave/work_92105/work_92105_display.h
@@ -0,0 +1,14 @@ 
+/*
+ * work_92105 display support interface
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * The work_92105 display is a HD44780-compatible module
+ * controlled through a MAX6957AAX SPI port expander, two
+ * MAX518 I2C DACs and native LPC32xx GPO 15.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+void work_92105_display_init(void);
diff --git a/configs/work_92105_defconfig b/configs/work_92105_defconfig
new file mode 100644
index 0000000..b982c10
--- /dev/null
+++ b/configs/work_92105_defconfig
@@ -0,0 +1,3 @@ 
+CONFIG_SPL=y
++S:CONFIG_ARM=y
++S:CONFIG_TARGET_WORK_92105=y
diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c
index b9a60fc..1ecc3da 100644
--- a/drivers/hwmon/ds620.c
+++ b/drivers/hwmon/ds620.c
@@ -1,5 +1,6 @@ 
 /*
  * DS620 DTT support
+ *
  * (C) Copyright 2014 3ADEV <http://www.3adev.com>
  * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
  *
diff --git a/include/configs/work_92105.h b/include/configs/work_92105.h
new file mode 100644
index 0000000..b1badbe
--- /dev/null
+++ b/include/configs/work_92105.h
@@ -0,0 +1,257 @@ 
+/*
+ * WORK Microwave work_92105 board configuration file
+ *
+ * (C) Copyright 2014  DENX Software Engineering GmbH
+ * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __CONFIG_WORK_92105_H__
+#define __CONFIG_WORK_92105_H__
+
+/* SoC and board defines */
+#include <linux/sizes.h>
+#include <asm/arch/cpu.h>
+
+/*
+ * Define work_92105 machine type by hand -- done only for compatibility
+ * with original board code
+ */
+#define MACH_TYPE_WORK_92105		736
+#define CONFIG_MACH_TYPE		MACH_TYPE_WORK_92105
+
+#define CONFIG_SYS_ICACHE_OFF
+#define CONFIG_SYS_DCACHE_OFF
+#if !defined(CONFIG_SPL_BUILD)
+#define CONFIG_SKIP_LOWLEVEL_INIT
+#endif
+#define CONFIG_BOARD_EARLY_INIT_F
+#define CONFIG_BOARD_EARLY_INIT_R
+
+/* generate LPC32XX-specific SPL image */
+#define CONFIG_LPC32XX_SPL
+
+/*
+ * Memory configurations
+ */
+#define CONFIG_NR_DRAM_BANKS		1
+#define CONFIG_SYS_MALLOC_LEN		SZ_1M
+#define CONFIG_SYS_SDRAM_BASE		EMC_DYCS0_BASE
+#define CONFIG_SYS_SDRAM_SIZE		SZ_64M
+#define CONFIG_SYS_TEXT_BASE		0x80100000
+#define CONFIG_SYS_MEMTEST_START	(CONFIG_SYS_SDRAM_BASE + SZ_32K)
+#define CONFIG_SYS_MEMTEST_END		(CONFIG_SYS_TEXT_BASE - SZ_1M)
+
+#define CONFIG_SYS_LOAD_ADDR		(CONFIG_SYS_SDRAM_BASE + SZ_32K)
+
+#define CONFIG_SYS_INIT_SP_ADDR		(CONFIG_SYS_SDRAM_BASE + SZ_4K \
+					 - GENERATED_GBL_DATA_SIZE)
+
+/*
+ * Serial Driver
+ */
+#define CONFIG_SYS_LPC32XX_UART		5   /* UART5 - NS16550 */
+#define CONFIG_BAUDRATE			115200
+
+/*
+ * Ethernet Driver
+ */
+
+#define CONFIG_PHY_SMSC
+#define CONFIG_LPC32XX_ETH
+#define CONFIG_PHYLIB
+#define CONFIG_PHY_ADDR 0
+#define CONFIG_SYS_FAULT_ECHO_LINK_DOWN
+#define CONFIG_CMD_MII
+#define CONFIG_CMD_PING
+#define CONFIG_CMD_DHCP
+/* FIXME: remove "Waiting for PHY auto negotiation to complete..." message */
+
+/*
+ * I2C driver
+ */
+
+#define CONFIG_SYS_I2C_LPC32XX
+#define CONFIG_SYS_I2C
+#define CONFIG_CMD_I2C
+#define CONFIG_SYS_I2C_SPEED 350000
+
+/*
+ * I2C EEPROM
+ */
+
+#define CONFIG_CMD_EEPROM
+#define CONFIG_SYS_I2C_EEPROM_ADDR 0x56
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 2
+
+/*
+ * I2C RTC
+ */
+
+#define CONFIG_CMD_DATE
+#define CONFIG_RTC_DS1374
+
+/*
+ * I2C Temperature Sensor (DTT)
+ */
+
+#define CONFIG_CMD_DTT
+#define CONFIG_DTT_SENSORS { 0, 1 }
+#define CONFIG_DTT_DS620
+
+/*
+ * U-Boot General Configurations
+ */
+#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_SYS_CBSIZE		1024
+#define CONFIG_SYS_PBSIZE		\
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_MAXARGS		16
+#define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE
+
+#define CONFIG_SYS_HUSH_PARSER
+
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+#define CONFIG_VERSION_VARIABLE
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_DOS_PARTITION
+
+/*
+ * No NOR
+ */
+
+#define CONFIG_SYS_NO_FLASH
+
+/*
+ * NAND chip timings for FIXME: which one?
+ */
+
+#define CONFIG_LPC32XX_NAND_MLC_TCEA_DELAY  333333333
+#define CONFIG_LPC32XX_NAND_MLC_BUSY_DELAY   10000000
+#define CONFIG_LPC32XX_NAND_MLC_NAND_TA      18181818
+#define CONFIG_LPC32XX_NAND_MLC_RD_HIGH      31250000
+#define CONFIG_LPC32XX_NAND_MLC_RD_LOW       45454545
+#define CONFIG_LPC32XX_NAND_MLC_WR_HIGH      40000000
+#define CONFIG_LPC32XX_NAND_MLC_WR_LOW       83333333
+
+/*
+ * NAND
+ */
+
+/* driver configuration */
+#define CONFIG_SYS_MAX_NAND_DEVICE 1
+#define CONFIG_SYS_NAND_BASE MLC_NAND_BASE
+#define CONFIG_NAND_LPC32XX_MLC
+
+#define CONFIG_CMD_NAND
+
+/*
+ * GPIO
+ */
+
+#define CONFIG_CMD_GPIO
+#define CONFIG_LPC32XX_GPIO
+
+/*
+ * SSP/SPI/DISPLAY
+ */
+
+#define CONFIG_CMD_SPI
+#define CONFIG_LPC32XX_SSP
+#define CONFIG_LPC32XX_SSP_TIMEOUT 100000
+#define CONFIG_CMD_MAX6957
+#define CONFIG_CMD_HD44760
+/*
+ * Environment
+ */
+
+#define CONFIG_ENV_IS_IN_NAND		1
+#define CONFIG_ENV_SIZE			0x00020000
+#define CONFIG_ENV_OFFSET		0x00100000
+#define CONFIG_ENV_OFFSET_REDUND	0x00120000
+#define CONFIG_ENV_ADDR			0x80000100
+/* provide default ethernet address */
+#define CONFIG_ETHADDR			00:12:B4:00:AF:FE
+#define	CONFIG_OVERWRITE_ETHADDR_ONCE
+
+/*
+ * U-Boot Commands
+ */
+#include <config_cmd_default.h>
+
+/*
+ * Boot Linux
+ */
+#define CONFIG_CMDLINE_TAG
+#define CONFIG_SETUP_MEMORY_TAGS
+#define CONFIG_INITRD_TAG
+
+#define CONFIG_ZERO_BOOTDELAY_CHECK
+#define CONFIG_BOOTDELAY		3
+
+#define CONFIG_BOOTFILE			"uImage"
+#define CONFIG_BOOTARGS			"console=ttyS2,115200n8"
+#define CONFIG_LOADADDR			0x80008000
+
+/*
+ * DRAM timings for MT48H16M16LFBF-8 (x2 chips -> 64MB)
+ */
+
+/* delay commands by 7*0.25 = 1.75 ns */
+#define CONFIG_LPC32XX_SDRAM_COMMAND_DELAY  7
+/* 256Mb (16Mx16), 4banks, row len 13, column len 9, LP SDR */
+#define CONFIG_LPC32XX_SDRAM_CONFIG0 0x00005682
+/* CAS latency 6 * 0.5 = 3 clk, RAS latency = 2 clk */
+#define CONFIG_LPC32XX_SDRAM_RASCAS0 0x00000302
+/* capture on HCLK pos edge, apply command delay */
+#define CONFIG_LPC32XX_SDRAM_READ_CONFIG 0x00000011
+/* Timings */
+#define CONFIG_LPC32XX_SDRAM_T_RP   52631578 /* 19 ns */
+#define CONFIG_LPC32XX_SDRAM_T_RAS  20833333 /* 48 ns */
+#define CONFIG_LPC32XX_SDRAM_T_SREX 12500000 /* 80 ns */
+#define CONFIG_LPC32XX_SDRAM_T_WR   66666666 /* 15 ns */
+#define CONFIG_LPC32XX_SDRAM_T_RC   13888888 /* 72 ns */
+#define CONFIG_LPC32XX_SDRAM_T_RFC  10256410 /* 97.5 ns */
+#define CONFIG_LPC32XX_SDRAM_T_XSR  12500000 /* 80 ns */
+#define CONFIG_LPC32XX_SDRAM_T_RRD         1 /* 2 clocks */
+#define CONFIG_LPC32XX_SDRAM_T_MRD         1 /* 2 clocks */
+#define CONFIG_LPC32XX_SDRAM_T_CDLR        0 /* 1 clock */
+#define CONFIG_LPC32XX_SDRAM_REFRESH  128000
+#define CONFIG_LPC32XX_DRAM_MODE  0x00000030 /* CAS = 3 */
+#define CONFIG_LPC32XX_DRAM_EMODE 0x02000000 /* all zeroes */
+
+/*
+ * SPL
+ */
+
+/* SPL will be executed at offset 0 */
+#define CONFIG_SPL_TEXT_BASE 0x00000000
+/* SPL will use SRAM as stack */
+#define CONFIG_SPL_STACK     0x0000FFF8
+#define CONFIG_SPL_BOARD_INIT
+/* Use the framework and generic lib */
+#define CONFIG_SPL_FRAMEWORK
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
+#define CONFIG_SPL_LIBCOMMON_SUPPORT
+/* SPL will use serial */
+#define CONFIG_SPL_SERIAL_SUPPORT
+/* SPL will load U-Boot from NAND offset 0x40000 */
+#define CONFIG_SPL_NAND_SUPPORT
+#define CONFIG_SPL_NAND_DRIVERS
+#define CONFIG_SPL_NAND_BASE
+#define CONFIG_SPL_NAND_BOOT
+#define CONFIG_SYS_NAND_U_BOOT_OFFS  0x00040000
+/* U-Boot will be 0x40000 bytes, loaded and run at CONFIG_SYS_TEXT_BASE */
+#define CONFIG_SYS_MONITOR_LEN 0x40000 /* actually, MAX size */
+#define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_NAND_U_BOOT_DST   CONFIG_SYS_TEXT_BASE
+
+/*
+ * Include SoC specific configuration
+ */
+#include <asm/arch/config.h>
+
+#endif  /* __CONFIG_WORK_92105_H__*/