diff options
Diffstat (limited to 'target/linux/bmips')
6 files changed, 776 insertions, 1 deletions
diff --git a/target/linux/bmips/dts/bcm63168-sercomm-shg2500.dts b/target/linux/bmips/dts/bcm63168-sercomm-shg2500.dts new file mode 100644 index 0000000000..76bedfac94 --- /dev/null +++ b/target/linux/bmips/dts/bcm63168-sercomm-shg2500.dts @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "bcm63268.dtsi" + +/ { + model = "Sercomm SHG2500"; + compatible = "sercomm,shg2500", "brcm,bcm63168", "brcm,bcm63268"; + + aliases { + led-boot = &led_power_red; + led-failsafe = &led_power_red; + led-running = &led_power_red; + led-upgrade = &led_power_red; + + led-internet = &led_internet_green; + led-usb = &led_modem_green; + led-wireless = &led_wireless_green; + }; + + i2c { + compatible = "i2c-gpio"; + sda-gpios = <&gpio 14 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + scl-gpios = <&gpio 9 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + #address-cells = <1>; + #size-cells = <0>; + }; + + keys { + compatible = "gpio-keys-polled"; + poll-interval = <20>; + + wps { + label = "wps"; + gpios = <&gpio 34 GPIO_ACTIVE_LOW>; + linux,code = <KEY_WPS_BUTTON>; + debounce-interval = <60>; + }; + + reset { + label = "reset"; + gpios = <&gpio 35 GPIO_ACTIVE_LOW>; + linux,code = <KEY_RESTART>; + debounce-interval = <60>; + }; + }; +}; + +&ehci { + status = "okay"; +}; + +ðernet { + status = "okay"; + + nvmem-cells = <&macaddr_cferom_6a0>; + nvmem-cell-names = "mac-address"; +}; + +&hsspi { + status = "okay"; + + led-controller@1 { + compatible = "sercomm,msp430-leds"; + reg = <1>; + spi-max-frequency = <500000>; + + led@1 { + reg = <1>; + label = "red:modem"; + }; + + led_modem_green: led@2 { + reg = <2>; + label = "green:modem"; + }; + + led@3 { + reg = <3>; + label = "blue:modem"; + }; + + led@4 { + reg = <4>; + label = "red:internet"; + }; + + led@5 { + reg = <5>; + label = "red:phone"; + }; + + led@6 { + reg = <6>; + label = "green:phone"; + }; + + led_wireless_green: led@7 { + reg = <7>; + label = "green:wifi"; + }; + + led_power_red: led@8 { + reg = <8>; + label = "red:power"; + }; + + led_internet_green: led@9 { + reg = <9>; + label = "green:internet"; + }; + }; +}; + +&mdio_int { + phy12: ethernet-phy@c { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <12>; + }; +}; + +&mdio_ext { + switch@1e { + compatible = "brcm,bcm53125"; + reg = <30>; + + dsa,member = <1 0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + label = "lan1"; + }; + + port@2 { + reg = <2>; + label = "lan2"; + }; + + port@3 { + reg = <3>; + label = "lan3"; + }; + + port@4 { + reg = <4>; + label = "lan4"; + }; + + port@8 { + reg = <8>; + + phy-mode = "rgmii"; + ethernet = <&switch0port4>; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; + }; +}; + +&nflash { + status = "okay"; + + nandcs@0 { + compatible = "brcm,nandcs"; + reg = <0>; + nand-ecc-step-size = <512>; + nand-ecc-strength = <15>; + nand-on-flash-bbt; + brcm,nand-oob-sector-size = <64>; + + #address-cells = <1>; + #size-cells = <1>; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + cferom: partition@0 { + label = "cferom"; + reg = <0x0000000 0x0020000>; + read-only; + }; + + partition@20000 { + label = "part_map"; + reg = <0x0020000 0x00a0000>; + read-only; + }; + + partition@c0000 { + label = "cferam1"; + reg = <0x00c0000 0x0140000>; + read-only; + }; + + partition@200000 { + label = "cferam2"; + reg = <0x0200000 0x0140000>; + read-only; + }; + + artition@6920000 { + label = "bootflag1"; + reg = <0x6920000 0x0140000>; + }; + + partition@6a60000 { + label = "bootflag2"; + reg = <0x6a60000 0x0140000>; + }; + + partition@520000 { + compatible = "sercomm,wfi"; + label = "wfi"; + reg = <0x0520000 0x6400000>; + }; + + partition@6ba0000 { + label = "xml_cfg"; + reg = <0x6ba0000 0x0280000>; + read-only; + }; + + partition@6e20000 { + label = "app_data"; + reg = <0x6e20000 0x0280000>; + read-only; + }; + }; + }; +}; + +&ohci { + status = "okay"; +}; + +&pcie { + status = "okay"; +}; + +&pinctrl { + pinctrl_uart1: uart1-pins { + pinctrl_uart1_sdin: uart1_sdin { + function = "uart1_sdin"; + pins = "gpio12"; + }; + + pinctrl_uart1_sdout: uart1_sdout { + function = "uart1_sdout"; + pins = "gpio13"; + }; + }; +}; + +&switch0 { + dsa,member = <0 0>; + + ports { + port@3 { + reg = <3>; + label = "wan"; + + phy-handle = <&phy12>; + phy-mode = "gmii"; + }; + + switch0port4: port@4 { + reg = <4>; + label = "extsw"; + + phy-mode = "rgmii"; + + fixed-link { + speed = <1000>; + full-duplex; + }; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +&uart1 { + status = "okay"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1>; +}; + +&usbh { + status = "okay"; +}; + +&cferom { + compatible = "nvmem-cells"; + #address-cells = <1>; + #size-cells = <1>; + + macaddr_cferom_6a0: macaddr@6a0 { + reg = <0x6a0 0x6>; + }; +}; diff --git a/target/linux/bmips/files/drivers/leds/leds-sercomm-msp430.c b/target/linux/bmips/files/drivers/leds/leds-sercomm-msp430.c new file mode 100644 index 0000000000..5409142989 --- /dev/null +++ b/target/linux/bmips/files/drivers/leds/leds-sercomm-msp430.c @@ -0,0 +1,380 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for Sercomm MSP430G2513 LEDs. + * + * Copyright 2023 Álvaro Fernández Rojas <noltari@gmail.com> + */ + +#include <linux/delay.h> +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/spi/spi.h> +#include "leds.h" + +/* + * MSP430G2513 SPI protocol description: + * +----+----+----+----+----+----+ + * | b1 | b2 | b3 | b4 | b5 | b6 | + * +----+----+----+----+----+----+ + * 6 bytes TX & RX per transaction. + * + * LEDs: + * MSP430G2513 can control up to 9 LEDs. + * b1: LED ID [1,9] + * b2: LED function + * b3-b6: LED function parameters + * + * LED functions: + * [0] Off + * [1] On + * [2] Flash + * - b4: delay (x 6ms) + * - b5: repeat (0 = infinite) + * [3] Pulse + * - b3: delay (x 6ms) + * - b4: blink while pulsing? (unknown) + * - b5: repeat (0 = infinite) + * [4] Pulse On + * - b3: delay (x 6ms) + * - b4: blink while pulsing? (unknown) + * - b5: repeat (0 = infinite) + * [5] Pulse Off + * - b3: delay (x 6ms) + * - b4: blink while pulsing? (unknown) + * - b5: repeat (0 = infinite) + * [6] Level + * - b3: brightness [0,4] + * + * MCU Commands (b1 = 0x55): + * [0x0a] FW upgrade data + * - b3: Data size (usually 0x40), which is appended to TX & RX. + * [0x31] Get MCU version? (unknown) + * [0x68] Get MCU work mode + * [0xa5] Start FW upgrade + * [0xf0] End FW upgrade + */ + +#define MSP430_CMD_BYTES 6 +#define MSP430_CMD_MCU 0x55 +#define MSP430_MCU_WM 0x68 + +#define MSP430_LED_MIN_ID 1 +#define MSP430_LED_MAX_ID 9 + +#define MSP430_LED_OFF 0 +#define MSP430_LED_ON 1 +#define MSP430_LED_FLASH 2 +#define MSP430_LED_PULSE 3 +#define MSP430_LED_PULSE_ON 4 +#define MSP430_LED_PULSE_OFF 5 +#define MSP430_LED_LEVEL 6 + +#define MSP430_LED_BLINK_DEF 500 +#define MSP430_LED_BLINK_MASK 0xff +#define MSP430_LED_BLINK_MS 6 +#define MSP430_LED_BLINK_MAX (MSP430_LED_BLINK_MS * \ + MSP430_LED_BLINK_MASK) + +#define MSP430_LED_BRIGHTNESS_MAX 5 +#define MSP430_LED_REPEAT_MAX 0xff + +/** + * struct msp430_led - state container for Sercomm MSP430 based LEDs + * @cdev: LED class device for this LED + * @spi: spi resource + * @id: LED ID + */ +struct msp430_led { + struct led_classdev cdev; + struct spi_device *spi; + u8 id; +}; + +static inline int msp430_cmd(struct spi_device *spi, u8 tx[MSP430_CMD_BYTES], + u8 rx[MSP430_CMD_BYTES]) +{ + struct device *dev = &spi->dev; + int rc; + + memset(rx, 0, MSP430_CMD_BYTES); + + rc = spi_write_then_read(spi, tx, MSP430_CMD_BYTES, + rx, MSP430_CMD_BYTES); + if (rc) + dev_err(dev, "spi error\n"); + + dev_dbg(dev, "msp430_cmd: [%02x %02x %02x %02x %02x %02x]" + " -> [%02x %02x %02x %02x %02x %02x]", + tx[0], tx[1], tx[2], tx[3], tx[4], tx[5], + rx[0], rx[1], rx[2], rx[3], rx[4], rx[5]); + + return rc; +} + +static unsigned long msp430_blink_delay(unsigned long delay) +{ + unsigned long msp430_delay; + + msp430_delay = delay + MSP430_LED_BLINK_MS / 2; + msp430_delay = msp430_delay / MSP430_LED_BLINK_MS; + if (msp430_delay == 0) + msp430_delay = 1; + + return msp430_delay; +} + +static int msp430_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct msp430_led *led = + container_of(led_cdev, struct msp430_led, cdev); + u8 tx[MSP430_CMD_BYTES] = {led->id, MSP430_LED_FLASH, 0, 0, 0, 0}; + u8 rx[MSP430_CMD_BYTES]; + unsigned long delay; + + if (!*delay_on) + *delay_on = MSP430_LED_BLINK_DEF; + if (!*delay_off) + *delay_off = MSP430_LED_BLINK_DEF; + + delay = msp430_blink_delay(*delay_on); + if (delay != msp430_blink_delay(*delay_off)) { + dev_dbg(led_cdev->dev, + "fallback to soft blinking (delay_on != delay_off)\n"); + return -EINVAL; + } + + if (delay > MSP430_LED_BLINK_MASK) { + dev_dbg(led_cdev->dev, + "fallback to soft blinking (delay > %ums)\n", + MSP430_LED_BLINK_MAX); + return -EINVAL; + } + + tx[3] = delay; + + return msp430_cmd(led->spi, tx, rx); +} + +static int msp430_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct msp430_led *led = + container_of(led_cdev, struct msp430_led, cdev); + u8 tx[MSP430_CMD_BYTES] = {led->id, 0, 0, 0, 0, 0}; + u8 rx[MSP430_CMD_BYTES]; + u8 val = (u8) brightness; + + switch (val) + { + case LED_OFF: + tx[1] = MSP430_LED_OFF; + break; + case MSP430_LED_BRIGHTNESS_MAX: + tx[1] = MSP430_LED_ON; + break; + default: + tx[1] = MSP430_LED_LEVEL; + tx[2] = val - 1; + break; + } + + return msp430_cmd(led->spi, tx, rx); +} + +static int msp430_pattern_clear(struct led_classdev *ldev) +{ + msp430_brightness_set(ldev, LED_OFF); + + return 0; +} + +static int msp430_pattern_set(struct led_classdev *led_cdev, + struct led_pattern *pattern, + u32 len, int repeat) +{ + struct msp430_led *led = + container_of(led_cdev, struct msp430_led, cdev); + u8 tx[MSP430_CMD_BYTES] = {led->id, 0, 0, 0, 0, 0}; + u8 rx[MSP430_CMD_BYTES]; + unsigned long delay0; + unsigned long delay1; + int rc; + + if (len != 2 || + repeat > MSP430_LED_REPEAT_MAX || + pattern[0].delta_t > MSP430_LED_BLINK_MAX || + pattern[1].delta_t > MSP430_LED_BLINK_MAX) + return -EINVAL; + + delay0 = msp430_blink_delay(pattern[0].delta_t); + delay1 = msp430_blink_delay(pattern[1].delta_t); + + /* Pulse: <off> <delay> <max> <delay> */ + if (delay0 == delay1 && + pattern[0].brightness == LED_OFF && + pattern[1].brightness == MSP430_LED_BRIGHTNESS_MAX) + { + tx[1] = MSP430_LED_PULSE; + tx[2] = delay0; + tx[4] = (u8) repeat; + } + + /* Pulse On: <off> <delay> <max> <0ms> */ + if (pattern[0].delta_t != 0 && + pattern[1].delta_t == 0 && + pattern[0].brightness == LED_OFF && + pattern[1].brightness == MSP430_LED_BRIGHTNESS_MAX) { + tx[1] = MSP430_LED_PULSE_ON; + tx[2] = delay0; + tx[4] = (u8) repeat; + } + + /* Pulse Off: <max> <delay> <off> <0ms> */ + if (pattern[0].delta_t != 0 && + pattern[1].delta_t == 0 && + pattern[0].brightness == MSP430_LED_BRIGHTNESS_MAX && + pattern[1].brightness == LED_OFF) { + tx[1] = MSP430_LED_PULSE_OFF; + tx[2] = delay0; + tx[4] = (u8) repeat; + } + + if (!tx[1]) + return -EINVAL; + + rc = msp430_cmd(led->spi, tx, rx); + if (rc) + return rc; + + return 0; +} + +static int msp430_led(struct spi_device *spi, struct device_node *nc, u8 id) +{ + struct device *dev = &spi->dev; + struct led_init_data init_data = {}; + struct msp430_led *led; + enum led_default_state state; + int rc; + + led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + led->id = id; + led->spi = spi; + + init_data.fwnode = of_fwnode_handle(nc); + + state = led_init_default_state_get(init_data.fwnode); + switch (state) { + case LEDS_DEFSTATE_ON: + led->cdev.brightness = MSP430_LED_BRIGHTNESS_MAX; + break; + default: + led->cdev.brightness = LED_OFF; + break; + } + + msp430_brightness_set(&led->cdev, led->cdev.brightness); + + led->cdev.blink_set = msp430_blink_set; + led->cdev.brightness_set_blocking = msp430_brightness_set; + led->cdev.max_brightness = MSP430_LED_BRIGHTNESS_MAX; + led->cdev.pattern_clear = msp430_pattern_clear; + led->cdev.pattern_set = msp430_pattern_set; + + rc = devm_led_classdev_register_ext(dev, &led->cdev, &init_data); + if (rc < 0) + return rc; + + dev_dbg(dev, "registered LED %s\n", led->cdev.name); + + return 0; +} + +static inline int msp430_check_workmode(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + u8 tx[MSP430_CMD_BYTES] = {MSP430_CMD_MCU, MSP430_MCU_WM, 0, 0, 0, 0}; + u8 rx[MSP430_CMD_BYTES]; + int rc; + + rc = msp430_cmd(spi, tx, rx); + if (rc) + return rc; + + if ((rx[3] == 0xA5 && rx[4] == 'Z') || + (rx[4] == 0xA5 && rx[5] == 'Z') || + (rx[4] == '\b' && rx[5] == '\n')) { + dev_err(dev, "invalid workmode: " + "[%02x %02x %02x %02x %02x %02x]\n", + rx[0], rx[1], rx[2], rx[3], rx[4], rx[5]); + return -EINVAL; + } + + return 0; +} + +static int msp430_leds_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct device_node *np = dev_of_node(dev); + struct device_node *child; + int rc; + + rc = msp430_check_workmode(spi); + if (rc) + return rc; + + for_each_available_child_of_node(np, child) { + u32 reg; + + if (of_property_read_u32(child, "reg", ®)) + continue; + + if (reg < MSP430_LED_MIN_ID || reg > MSP430_LED_MAX_ID) { + dev_err(dev, "invalid LED (%u) [%d, %d]\n", reg, + MSP430_LED_MIN_ID, MSP430_LED_MAX_ID); + continue; + } + + rc = msp430_led(spi, child, reg); + if (rc < 0) { + of_node_put(child); + return rc; + } + } + + return 0; +} + +static const struct of_device_id msp430_leds_of_match[] = { + { .compatible = "sercomm,msp430-leds", }, + { }, +}; +MODULE_DEVICE_TABLE(of, msp430_leds_of_match); + +static const struct spi_device_id msp430_leds_id_table[] = { + { "msp430-leds", 0 }, + { } +}; + +static struct spi_driver msp430_leds_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = msp430_leds_of_match, + }, + .id_table = msp430_leds_id_table, + .probe = msp430_leds_probe, +}; + +module_spi_driver(msp430_leds_driver); + +MODULE_AUTHOR("Álvaro Fernández Rojas <noltari@gmail.com>"); +MODULE_DESCRIPTION("LED driver for Sercomm MSP430 controllers"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:leds-sercomm-msp430"); diff --git a/target/linux/bmips/image/bcm63xx_nand.mk b/target/linux/bmips/image/bcm63xx_nand.mk index 89b634c8d1..faed7a0919 100644 --- a/target/linux/bmips/image/bcm63xx_nand.mk +++ b/target/linux/bmips/image/bcm63xx_nand.mk @@ -141,3 +141,23 @@ define Device/sercomm_h500-s-vfes SERCOMM_SWVER := 3417 endef TARGET_DEVICES += sercomm_h500-s-vfes + +define Device/sercomm_shg2500 + $(Device/sercomm-nand) + DEVICE_VENDOR := Sercomm + DEVICE_MODEL := SHG2500 + DEVICE_LOADADDR := $(KERNEL_LOADADDR) + KERNEL := kernel-bin | append-dtb | lzma | cfe-jffs2-kernel + CHIP_ID := 63268 + SOC := bcm63168 + BLOCKSIZE := 128k + PAGESIZE := 2048 + SUBPAGESIZE := 512 + VID_HDR_OFFSET := 2048 + DEVICE_PACKAGES += $(USB2_PACKAGES) kmod-i2c-gpio \ + kmod-leds-sercomm-msp430 + SERCOMM_FSVER := 1001 + SERCOMM_HWVER := 1424e4a + SERCOMM_SWVER := 3207 +endef +TARGET_DEVICES += sercomm_shg2500 diff --git a/target/linux/bmips/modules.mk b/target/linux/bmips/modules.mk new file mode 100644 index 0000000000..8f4b344357 --- /dev/null +++ b/target/linux/bmips/modules.mk @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only + +define KernelPackage/leds-sercomm-msp430 + SUBMENU:=$(LEDS_MENU) + TITLE:=Sercomm MSP430G2513 LED support + KCONFIG:=CONFIG_LEDS_SERCOMM_MSP430 + FILES:=$(LINUX_DIR)/drivers/leds/leds-sercomm-msp430.ko + DEPENDS:=@TARGET_bmips +kmod-ledtrig-pattern + AUTOLOAD:=$(call AutoLoad,60,leds-sercomm-msp430,1) +endef + +define KernelPackage/leds-sercomm-msp430/description + Kernel support for the Sercomm MSP430G2513 SPI LED controller. +endef + +$(eval $(call KernelPackage,leds-sercomm-msp430)) diff --git a/target/linux/bmips/nand/base-files/etc/board.d/02_network b/target/linux/bmips/nand/base-files/etc/board.d/02_network index b2a340ecf8..0e130103da 100644 --- a/target/linux/bmips/nand/base-files/etc/board.d/02_network +++ b/target/linux/bmips/nand/base-files/etc/board.d/02_network @@ -10,7 +10,8 @@ comtrend,vr-3032u) ucidef_set_interface_lan "lan1 lan2 lan3 lan4" ;; huawei,hg253s-v2 |\ -netgear,dgnd3700-v2) +netgear,dgnd3700-v2 |\ +sercomm,shg2500) ucidef_set_bridge_device switch ucidef_set_interfaces_lan_wan "lan1 lan2 lan3 lan4" "wan" ;; diff --git a/target/linux/bmips/patches-5.15/700-leds-add-support-for-Sercomm-MSP430-LED-controller.patch b/target/linux/bmips/patches-5.15/700-leds-add-support-for-Sercomm-MSP430-LED-controller.patch new file mode 100644 index 0000000000..eeeb8d1ae0 --- /dev/null +++ b/target/linux/bmips/patches-5.15/700-leds-add-support-for-Sercomm-MSP430-LED-controller.patch @@ -0,0 +1,46 @@ +From 1a5f2263d388016c88d39e141c7eb8085c9313fc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com> +Date: Wed, 5 Apr 2023 08:07:00 +0200 +Subject: [PATCH] leds: add support for Sercomm MSP430 LED controller +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Sercomm added an external MSP430G2513 for controlling LEDs through SPI on some +boards. + +Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com> +--- + drivers/leds/Kconfig | 9 +++++++++ + drivers/leds/Makefile | 1 + + drivers/spi/spidev.c | 2 ++ + 3 files changed, 12 insertions(+) + +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -288,6 +288,15 @@ config LEDS_COBALT_RAQ + help + This option enables support for the Cobalt Raq series LEDs. + ++config LEDS_SERCOMM_MSP430 ++ tristate "LED support for Sercomm MSP430 SPI LED controllers" ++ depends on LEDS_CLASS ++ depends on SPI ++ depends on OF ++ help ++ This option enables support for the Sercomm MSP430G2513 SPI LED ++ controllers. ++ + config LEDS_SUNFIRE + tristate "LED support for SunFire servers." + depends on LEDS_CLASS +--- a/drivers/leds/Makefile ++++ b/drivers/leds/Makefile +@@ -77,6 +77,7 @@ obj-$(CONFIG_LEDS_PWM) += leds-pwm.o + obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o + obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o + obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o ++obj-$(CONFIG_LEDS_SERCOMM_MSP430) += leds-sercomm-msp430.o + obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o + obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o + obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o |