diff --git a/commands/i2c.c b/commands/i2c.c index f0d16af..2f7f820 100644 --- a/commands/i2c.c +++ b/commands/i2c.c @@ -145,8 +145,12 @@ ret = 0; if (verbose) { - printf("wrote %i bytes starting at reg 0x%04x to i2cdev 0x%02x on bus %i\n", - count, reg, addr, adapter->nr); + if (reg >= 0) + printf("wrote %i bytes starting at reg 0x%04x to i2cdev 0x%02x on bus %i\n", + count, reg, addr, adapter->nr); + else + printf("sent %i bytes in master send mode to i2cdev 0x%02x on bus %i\n", + count, addr, adapter->nr); for (i = 0; i < count; i++) printf("0x%02x ", *(buf + i)); printf("\n"); @@ -161,7 +165,7 @@ BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-b BUS\t", "i2c bus number (default 0)") BAREBOX_CMD_HELP_OPT ("-a ADDR\t", "i2c device address") -BAREBOX_CMD_HELP_OPT ("-r START", "start register") +BAREBOX_CMD_HELP_OPT ("-r START", "start register (optional, master send mode if none given)") BAREBOX_CMD_HELP_OPT ("-w\t", "use word (16 bit) wide access") BAREBOX_CMD_HELP_OPT ("-v\t", "verbose") BAREBOX_CMD_HELP_END @@ -204,7 +208,7 @@ } } - if ((addr < 0) || (reg < 0) || (count < 1) || (addr > 0x7F)) + if ((addr < 0) || (count < 1) || (addr > 0x7F)) return COMMAND_ERROR_USAGE; adapter = i2c_get_adapter(bus); @@ -217,12 +221,21 @@ client.addr = addr; buf = xmalloc(count); - ret = i2c_read_reg(&client, reg | wide, buf, count); + if (reg >= 0) + ret = i2c_read_reg(&client, reg | wide, buf, count); + else + ret = i2c_master_recv(&client, buf, count); if (ret == count) { int i; - if (verbose) - printf("read %i bytes starting at reg 0x%04x from i2cdev 0x%02x on bus %i\n", - count, reg, addr, adapter->nr); + if (verbose) { + if (reg >= 0) + printf("read %i bytes starting at reg 0x%04x from i2cdev 0x%02x on bus %i\n", + count, reg, addr, adapter->nr); + else + printf("received %i bytes in master receive mode from i2cdev 0x%02x on bus %i\n", + count, addr, adapter->nr); + } + for (i = 0; i < count; i++) printf("0x%02x ", *(buf + i)); printf("\n"); @@ -237,7 +250,7 @@ BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT("-b BUS\t", "i2c bus number (default 0)") BAREBOX_CMD_HELP_OPT("-a ADDR\t", "i2c device address") -BAREBOX_CMD_HELP_OPT("-r START", "start register") +BAREBOX_CMD_HELP_OPT("-r START", "start register (optional, master receive mode if none given)") BAREBOX_CMD_HELP_OPT("-w\t", "use word (16 bit) wide access") BAREBOX_CMD_HELP_OPT("-c COUNT", "byte count") BAREBOX_CMD_HELP_OPT("-v\t", "verbose") diff --git a/commands/nand.c b/commands/nand.c index b065a66..c57b394 100644 --- a/commands/nand.c +++ b/commands/nand.c @@ -41,7 +41,7 @@ int command = 0; loff_t badblock = 0; int fd; - int ret; + int ret = 0; struct mtd_info_user mtdinfo; while((opt = getopt(argc, argv, "adb:g:i")) > 0) { @@ -88,13 +88,18 @@ optind++; } + + goto out_ret; } if (command == NAND_DEL) { while (optind < argc) { - dev_remove_bb_dev(basename(argv[optind])); + if (dev_remove_bb_dev(basename(argv[optind]))) + return 1; optind++; } + + goto out_ret; } fd = open(argv[optind], O_RDWR); @@ -149,10 +154,10 @@ printf("No bad blocks\n"); } - ret = 0; out: close(fd); +out_ret: return ret; } diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 3c95230..53e8c76 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -468,9 +468,44 @@ return 0; } +/* convenience to stop overlong match-table lines */ +#define OF_953X(__nrgpio, __int) (void *)(__nrgpio | PCA953X_TYPE | __int) +#define OF_957X(__nrgpio, __int) (void *)(__nrgpio | PCA957X_TYPE | __int) + +static const struct of_device_id pca953x_dt_ids[] = { + { .compatible = "nxp,pca9505", .data = OF_953X(40, PCA_INT), }, + { .compatible = "nxp,pca9534", .data = OF_953X( 8, PCA_INT), }, + { .compatible = "nxp,pca9535", .data = OF_953X(16, PCA_INT), }, + { .compatible = "nxp,pca9536", .data = OF_953X( 4, 0), }, + { .compatible = "nxp,pca9537", .data = OF_953X( 4, PCA_INT), }, + { .compatible = "nxp,pca9538", .data = OF_953X( 8, PCA_INT), }, + { .compatible = "nxp,pca9539", .data = OF_953X(16, PCA_INT), }, + { .compatible = "nxp,pca9554", .data = OF_953X( 8, PCA_INT), }, + { .compatible = "nxp,pca9555", .data = OF_953X(16, PCA_INT), }, + { .compatible = "nxp,pca9556", .data = OF_953X( 8, 0), }, + { .compatible = "nxp,pca9557", .data = OF_953X( 8, 0), }, + { .compatible = "nxp,pca9574", .data = OF_957X( 8, PCA_INT), }, + { .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), }, + { .compatible = "nxp,pca9698", .data = OF_953X(40, 0), }, + + { .compatible = "maxim,max7310", .data = OF_953X( 8, 0), }, + { .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), }, + { .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), }, + { .compatible = "maxim,max7315", .data = OF_953X( 8, PCA_INT), }, + + { .compatible = "ti,pca6107", .data = OF_953X( 8, PCA_INT), }, + { .compatible = "ti,tca6408", .data = OF_953X( 8, PCA_INT), }, + { .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), }, + { .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), }, + + { .compatible = "exar,xra1202", .data = OF_953X( 8, 0), }, + { } +}; + static struct driver_d pca953x_driver = { .name = "pca953x", .probe = pca953x_probe, + .of_compatible = DRV_OF_COMPAT(pca953x_dt_ids), .id_table = pca953x_id, }; diff --git a/drivers/led/Kconfig b/drivers/led/Kconfig index 50f0d8f..2a5920a 100644 --- a/drivers/led/Kconfig +++ b/drivers/led/Kconfig @@ -31,4 +31,13 @@ This allows to assign certain triggers like heartbeat or network activity to LEDs. +config LED_PCA955X + bool "LED Support for PCA955x I2C chips" + depends on I2C + help + This option enables support for LEDs connected to PCA955x + LED driver chips accessed via the I2C bus. Supported + devices include PCA9550, PCA9551, PCA9552, and PCA9553. + + endif diff --git a/drivers/led/Makefile b/drivers/led/Makefile index 619bbcf..35693a7 100644 --- a/drivers/led/Makefile +++ b/drivers/led/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_LED_GPIO) += led-gpio.o obj-$(CONFIG_LED_PWM) += led-pwm.o obj-$(CONFIG_LED_TRIGGERS) += led-triggers.o +obj-$(CONFIG_LED_PCA955X) += led-pca955x.o diff --git a/drivers/led/core.c b/drivers/led/core.c index 6f66de0..a388e6b 100644 --- a/drivers/led/core.c +++ b/drivers/led/core.c @@ -127,7 +127,7 @@ struct led *led; list_for_each_entry(led, &leds, list) { - bool on; + int on; if (!led->blink && !led->flash) continue; @@ -137,6 +137,8 @@ } on = !(led->blink_next_state % 2); + if (on) + on = led->max_value; led->blink_next_event = get_time_ns() + (led->blink_states[led->blink_next_state] * MSECOND); diff --git a/drivers/led/led-pca955x.c b/drivers/led/led-pca955x.c new file mode 100644 index 0000000..9c4f796 --- /dev/null +++ b/drivers/led/led-pca955x.c @@ -0,0 +1,421 @@ +/* + * Copyright 2007-2008 Extreme Engineering Solutions, Inc. + * Author: Nate Case + * + * Copyright (C) 2018 WAGO Kontakttechnik GmbH & Co. KG + * Author: Oleg Karfich + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * This code was ported from linux-4.18 kernel driver. + * Orginal code with it's copyright info can be found in + * drivers/leds/leds-pca955x.c + * + * LED driver for various PCA955x I2C LED drivers + * + * Supported devices: + * + * Device Description 7-bit slave address + * ------ ----------- ------------------- + * PCA9550 2-bit driver 0x60 .. 0x61 + * PCA9551 8-bit driver 0x60 .. 0x67 + * PCA9552 16-bit driver 0x60 .. 0x67 + * PCA9553/01 4-bit driver 0x62 + * PCA9553/02 4-bit driver 0x63 + * + * Philips PCA955x LED driver chips follow a register map as shown below: + * + * Control Register Description + * ---------------- ----------- + * 0x0 Input register 0 + * .. + * NUM_INPUT_REGS - 1 Last Input register X + * + * NUM_INPUT_REGS Frequency prescaler 0 + * NUM_INPUT_REGS + 1 PWM register 0 + * NUM_INPUT_REGS + 2 Frequency prescaler 1 + * NUM_INPUT_REGS + 3 PWM register 1 + * + * NUM_INPUT_REGS + 4 LED selector 0 + * NUM_INPUT_REGS + 4 + * + NUM_LED_REGS - 1 Last LED selector + * + * where NUM_INPUT_REGS and NUM_LED_REGS vary depending on how many + * bits the chip supports. + * + */ + +#include +#include +#include +#include +#include +#include + +/* LED select registers determine the source that drives LED outputs */ +#define PCA955X_LS_LED_ON 0x0 /* Output LOW */ +#define PCA955X_LS_LED_OFF 0x1 /* Output HI-Z */ +#define PCA955X_LS_BLINK0 0x2 /* Blink at PWM0 rate */ +#define PCA955X_LS_BLINK1 0x3 /* Blink at PWM1 rate */ + +enum led_brightness { + LED_OFF = 0, + LED_HALF = 127, + LED_FULL = 255, +}; + +enum pca955x_type { + pca9550, + pca9551, + pca9552, + pca9553, +}; + +struct pca955x_chipdef { + int bits; + u8 slv_addr; /* 7-bit slave address mask */ + int slv_addr_shift; /* Number of bits to ignore */ +}; + +static struct pca955x_chipdef pca955x_chipdefs[] = { + [pca9550] = { + .bits = 2, + .slv_addr = /* 110000x */ 0x60, + .slv_addr_shift = 1, + }, + [pca9551] = { + .bits = 8, + .slv_addr = /* 1100xxx */ 0x60, + .slv_addr_shift = 3, + }, + [pca9552] = { + .bits = 16, + .slv_addr = /* 1100xxx */ 0x60, + .slv_addr_shift = 3, + }, + [pca9553] = { + .bits = 4, + .slv_addr = /* 110001x */ 0x62, + .slv_addr_shift = 1, + }, +}; + +static const struct platform_device_id led_pca955x_id[] = { + { "pca9550", pca9550 }, + { "pca9551", pca9551 }, + { "pca9552", pca9552 }, + { "pca9553", pca9553 }, + { } +}; + +struct pca955x { + struct pca955x_led *leds; + struct pca955x_chipdef *chipdef; + struct i2c_client *client; +}; + +struct pca955x_led { + struct pca955x *pca955x; + struct led led_cdev; + int led_num; /* 0 .. 15 potentially */ + char name[32]; +}; + +struct pca955x_platform_data { + struct pca955x_led *leds; + int num_leds; +}; + +/* 8 bits per input register */ +static inline int pca95xx_num_input_regs(int bits) +{ + return (bits + 7) / 8; +} + +/* + * Return an LED selector register value based on an existing one, with + * the appropriate 2-bit state value set for the given LED number (0-3). + */ +static inline u8 pca955x_ledsel(u8 oldval, int led_num, int state) +{ + return (oldval & (~(0x3 << (led_num << 1)))) | + ((state & 0x3) << (led_num << 1)); +} + +/* + * Write to frequency prescaler register, used to program the + * period of the PWM output. period = (PSCx + 1) / 38 + */ +static int pca955x_write_psc(struct i2c_client *client, int n, u8 val) +{ + struct pca955x *pca955x = i2c_get_clientdata(client); + int ret; + + ret = i2c_smbus_write_byte_data(client, + pca95xx_num_input_regs(pca955x->chipdef->bits) + 2*n, + val); + if (ret < 0) + dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n", + __func__, n, val, ret); + return ret; +} + +/* + * Write to PWM register, which determines the duty cycle of the + * output. LED is OFF when the count is less than the value of this + * register, and ON when it is greater. If PWMx == 0, LED is always OFF. + * + * Duty cycle is (256 - PWMx) / 256 + */ +static int pca955x_write_pwm(struct i2c_client *client, int n, u8 val) +{ + struct pca955x *pca955x = i2c_get_clientdata(client); + int ret; + + ret = i2c_smbus_write_byte_data(client, + pca95xx_num_input_regs(pca955x->chipdef->bits) + 1 + 2*n, + val); + if (ret < 0) + dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n", + __func__, n, val, ret); + return ret; +} + +/* + * Write to LED selector register, which determines the source that + * drives the LED output. + */ +static int pca955x_write_ls(struct i2c_client *client, int n, u8 val) +{ + struct pca955x *pca955x = i2c_get_clientdata(client); + int ret; + + ret = i2c_smbus_write_byte_data(client, + pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n, + val); + if (ret < 0) + dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n", + __func__, n, val, ret); + return ret; +} + +/* + * Read the LED selector register, which determines the source that + * drives the LED output. + */ +static int pca955x_read_ls(struct i2c_client *client, int n, u8 *val) +{ + struct pca955x *pca955x = i2c_get_clientdata(client); + int ret; + + ret = i2c_smbus_read_byte_data(client, + pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n); + if (ret < 0) { + dev_err(&client->dev, "%s: reg 0x%x, err %d\n", + __func__, n, ret); + return ret; + } + *val = (u8)ret; + return 0; +} + +static void pca955x_led_set(struct led *led_cdev, unsigned int value) +{ + struct pca955x_led *pca955x_led; + struct pca955x *pca955x; + u8 ls; + int chip_ls; /* which LSx to use (0-3 potentially) */ + int ls_led; /* which set of bits within LSx to use (0-3) */ + int ret; + + pca955x_led = container_of(led_cdev, struct pca955x_led, led_cdev); + pca955x = pca955x_led->pca955x; + + chip_ls = pca955x_led->led_num / 4; + ls_led = pca955x_led->led_num % 4; + + ret = pca955x_read_ls(pca955x->client, chip_ls, &ls); + if (ret) + return; + + switch (value) { + case LED_FULL: + ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_ON); + break; + case LED_OFF: + ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_OFF); + break; + case LED_HALF: + ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK0); + break; + default: + /* + * Use PWM1 for all other values. This has the unwanted + * side effect of making all LEDs on the chip share the + * same brightness level if set to a value other than + * OFF, HALF, or FULL. But, this is probably better than + * just turning off for all other values. + */ + ret = pca955x_write_pwm(pca955x->client, 1, 255 - value); + if (ret) + return; + ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK1); + break; + } + + pca955x_write_ls(pca955x->client, chip_ls, ls); +} + +static struct pca955x_platform_data * +led_pca955x_pdata_of_init(struct device_node *np, struct pca955x *pca955x) +{ + struct device_node *child; + struct pca955x_chipdef *chip = pca955x->chipdef; + struct pca955x_platform_data *pdata; + int count, err; + + count = of_get_child_count(np); + if (!count || count > chip->bits) + return ERR_PTR(-ENODEV); + + pdata = xzalloc(sizeof(*pdata)); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->leds = xzalloc(chip->bits * sizeof(struct pca955x_led)); + if (!pdata->leds) + return ERR_PTR(-ENOMEM); + + for_each_child_of_node(np, child) { + struct pca955x_led *pca955x_led; + const char *name; + u32 reg; + int res; + + res = of_property_read_u32(child, "reg", ®); + if ((res != 0) || (reg >= chip->bits)) + continue; + + pca955x_led = &pdata->leds[reg]; + pca955x_led->led_num = reg; + pca955x_led->pca955x = pca955x; + + if (of_property_read_string(child, "label", &name)) + name = child->name; + + snprintf(pca955x_led->name, sizeof(pca955x_led->name), + "%s", name); + + pca955x_led->led_cdev.name = pca955x_led->name; + pca955x_led->led_cdev.set = pca955x_led_set; + pca955x_led->led_cdev.num = pca955x_led->led_num; + pca955x_led->led_cdev.max_value = 255; + + err = led_register(&pca955x_led->led_cdev); + if (err) + return ERR_PTR(err); + + /* Turn off LED */ + pca955x_led_set(&pca955x_led->led_cdev, LED_OFF); + + led_of_parse_trigger(&pca955x_led->led_cdev, child); + } + + pdata->num_leds = count; + + return pdata; +} + +static const struct of_device_id of_pca955x_match[] = { + { .compatible = "nxp,pca9550", .data = (void *)pca9550 }, + { .compatible = "nxp,pca9551", .data = (void *)pca9551 }, + { .compatible = "nxp,pca9552", .data = (void *)pca9552 }, + { .compatible = "nxp,pca9553", .data = (void *)pca9553 }, + {}, +}; + +static int led_pca955x_probe(struct device_d *dev) +{ + struct pca955x *pca955x; + struct pca955x_led *pca955x_led; + struct pca955x_chipdef *chip; + struct i2c_client *client; + int err; + struct pca955x_platform_data *pdata; + + chip = &pca955x_chipdefs[dev->id_entry->driver_data]; + client = to_i2c_client(dev); + + /* Make sure the slave address / chip type combo given is possible */ + if ((client->addr & ~((1 << chip->slv_addr_shift) - 1)) != + chip->slv_addr) { + dev_err(dev, "invalid slave address %02x\n", client->addr); + return -ENODEV; + } + + dev_info(dev, "leds-pca955x: Using %s %d-bit LED driver at " + "slave address 0x%02x\n", + client->dev.name, chip->bits, client->addr); + + pca955x = xzalloc(sizeof(*pca955x)); + if (!pca955x) + return -ENOMEM; + + pca955x->leds = xzalloc(chip->bits * sizeof(*pca955x_led)); + if (!pca955x->leds) + return -ENOMEM; + + i2c_set_clientdata(client, pca955x); + + pca955x->client = client; + pca955x->chipdef = chip; + + pdata = led_pca955x_pdata_of_init(dev->device_node, pca955x); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + + if (pdata->num_leds != chip->bits) + dev_warn(dev, "board info claims %d LEDs on a %d-bit chip\n", + pdata->num_leds, chip->bits); + + /* PWM0 is used for half brightness or 50% duty cycle */ + err = pca955x_write_pwm(client, 0, 255 - LED_HALF); + if (err) + return err; + + /* PWM1 is used for variable brightness, default to OFF */ + err = pca955x_write_pwm(client, 1, 0); + if (err) + return err; + + /* Set to fast frequency so we do not see flashing */ + err = pca955x_write_psc(client, 0, 0); + if (err) + return err; + err = pca955x_write_psc(client, 1, 0); + if (err) + return err; + + return 0; +} + +static struct driver_d led_pca955x_driver = { + .name = "led-pca955x", + .probe = led_pca955x_probe, + .id_table = led_pca955x_id, + .of_compatible = DRV_OF_COMPAT(of_pca955x_match), +}; + +static int __init led_pca955x_init(void) +{ + return i2c_driver_register(&led_pca955x_driver); +} +device_initcall(led_pca955x_init); diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c index d55e913..469ce4c 100644 --- a/drivers/mfd/rave-sp.c +++ b/drivers/mfd/rave-sp.c @@ -57,16 +57,6 @@ #define RAVE_SP_TX_BUFFER_SIZE \ (RAVE_SP_STX_ETX_SIZE + 2 * RAVE_SP_RX_BUFFER_SIZE) -#define RAVE_SP_BOOT_SOURCE_GET 0 -#define RAVE_SP_BOOT_SOURCE_SET 1 - -#define RAVE_SP_RDU2_BOARD_TYPE_RMB 0 -#define RAVE_SP_RDU2_BOARD_TYPE_DEB 1 - -#define RAVE_SP_BOOT_SOURCE_SD 0 -#define RAVE_SP_BOOT_SOURCE_EMMC 1 -#define RAVE_SP_BOOT_SOURCE_NOR 2 - /** * enum rave_sp_deframer_state - Possible state for de-framer * @@ -122,13 +112,46 @@ void (*subroutine)(const u8 *, size_t, u8 *); }; +struct rave_sp_version { + u8 hardware; + __le16 major; + u8 minor; + u8 letter[2]; +} __packed; + +struct rave_sp_status { + struct rave_sp_version bootloader_version; + struct rave_sp_version firmware_version; + u16 rdu_eeprom_flag; + u16 dds_eeprom_flag; + u8 pic_flag; + u8 orientation; + u32 etc; + s16 temp[2]; + u8 backlight_current[3]; + u8 dip_switch; + u8 host_interrupt; + u16 voltage_28; + u8 i2c_device_status; + u8 power_status; + u8 general_status; +#define RAVE_SP_STATUS_GS_FIRMWARE_MODE BIT(1) + + u8 deprecated1; + u8 power_led_status; + u8 deprecated2; + u8 periph_power_shutoff; +} __packed; + /** * struct rave_sp_variant_cmds - Variant specific command routines * * @translate: Generic to variant specific command mapping routine + * @get_status: Variant specific implementation of CMD_GET_STATUS */ struct rave_sp_variant_cmds { int (*translate)(enum rave_sp_command); + int (*get_status)(struct rave_sp *sp, struct rave_sp_status *); }; /** @@ -171,37 +194,6 @@ const char *part_number_bootloader; }; -struct rave_sp_version { - u8 hardware; - __le16 major; - u8 minor; - u8 letter[2]; -} __packed; - -struct rave_sp_status { - struct rave_sp_version bootloader_version; - struct rave_sp_version firmware_version; - u16 rdu_eeprom_flag; - u16 dds_eeprom_flag; - u8 pic_flag; - u8 orientation; - u32 etc; - s16 temp[2]; - u8 backlight_current[3]; - u8 dip_switch; - u8 host_interrupt; - u16 voltage_28; - u8 i2c_device_status; - u8 power_status; - u8 general_status; -#define RAVE_SP_STATUS_GS_FIRMWARE_MODE BIT(1) - - u8 deprecated1; - u8 power_led_status; - u8 deprecated2; - u8 periph_power_shutoff; -} __packed; - static bool rave_sp_id_is_event(u8 code) { return (code & 0xF0) == RAVE_SP_EVNT_BASE; @@ -596,12 +588,16 @@ return 0x14; case RAVE_SP_CMD_SW_WDT: return 0x1C; + case RAVE_SP_CMD_PET_WDT: + return 0x1D; case RAVE_SP_CMD_RESET: return 0x1E; case RAVE_SP_CMD_RESET_REASON: return 0x1F; case RAVE_SP_CMD_BOOTLOADER: return 0x2A; + case RAVE_SP_CMD_RMB_EEPROM: + return 0x20; default: return -EINVAL; } @@ -623,18 +619,45 @@ version->letter[1]); } -static int rave_sp_get_status(struct rave_sp *sp) + +static int rave_sp_rdu1_get_status(struct rave_sp *sp, + struct rave_sp_status *status) { - struct device_d *dev = sp->serdev->dev; u8 cmd[] = { [0] = RAVE_SP_CMD_STATUS, [1] = 0 }; + + return rave_sp_exec(sp, cmd, sizeof(cmd), status, sizeof(*status)); +} + +static int rave_sp_emulated_get_status(struct rave_sp *sp, + struct rave_sp_status *status) +{ + u8 cmd[] = { + [0] = RAVE_SP_CMD_GET_FIRMWARE_VERSION, + [1] = 0, + }; + int ret; + + ret = rave_sp_exec(sp, cmd, sizeof(cmd), &status->firmware_version, + sizeof(status->firmware_version)); + if (ret) + return ret; + + cmd[0] = RAVE_SP_CMD_GET_BOOTLOADER_VERSION; + return rave_sp_exec(sp, cmd, sizeof(cmd), &status->bootloader_version, + sizeof(status->bootloader_version)); +} + +static int rave_sp_get_status(struct rave_sp *sp) +{ + struct device_d *dev = sp->serdev->dev; struct rave_sp_status status; const char *mode; int ret; - ret = rave_sp_exec(sp, cmd, sizeof(cmd), &status, sizeof(status)); + ret = sp->variant->cmd.get_status(sp, &status); if (ret) return ret; @@ -663,9 +686,10 @@ }; static const struct rave_sp_variant rave_sp_legacy = { - .checksum = &rave_sp_checksum_8b2c, + .checksum = &rave_sp_checksum_ccitt, .cmd = { .translate = rave_sp_default_cmd_translate, + .get_status = rave_sp_emulated_get_status, }, }; @@ -673,6 +697,7 @@ .checksum = &rave_sp_checksum_8b2c, .cmd = { .translate = rave_sp_rdu1_cmd_translate, + .get_status = rave_sp_rdu1_get_status, }, }; @@ -680,6 +705,7 @@ .checksum = &rave_sp_checksum_ccitt, .cmd = { .translate = rave_sp_rdu2_cmd_translate, + .get_status = rave_sp_emulated_get_status, }, }; diff --git a/include/common.h b/include/common.h index f93bd7f..abbe73f 100644 --- a/include/common.h +++ b/include/common.h @@ -109,8 +109,8 @@ #define PAGE_SIZE 4096 #define PAGE_SHIFT 12 -#define PAGE_ALIGN(s) (((s) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) -#define PAGE_ALIGN_DOWN(x) ((x) & ~(PAGE_SIZE - 1)) +#define PAGE_ALIGN(s) ALIGN(s, PAGE_SIZE) +#define PAGE_ALIGN_DOWN(x) ALIGN_DOWN(x, PAGE_SIZE) int memory_display(const void *addr, loff_t offs, unsigned nbytes, int size, int swab); diff --git a/include/linux/log2.h b/include/linux/log2.h index 36519e3..2af7f77 100644 --- a/include/linux/log2.h +++ b/include/linux/log2.h @@ -16,12 +16,6 @@ #include /* - * deal with unrepresentable constant logarithms - */ -extern __attribute__((const, noreturn)) -int ____ilog2_NaN(void); - -/* * non-constant log of base 2 calculators * - the arch may override these in asm/bitops.h if they can be implemented * more efficiently than using fls() and fls64() @@ -43,28 +37,33 @@ } #endif -/* - * Determine whether some value is a power of two, where zero is +/** + * is_power_of_2() - check if a value is a power of two + * @n: the value to check + * + * Determine whether some value is a power of two, where zero is * *not* considered a power of two. + * Return: true if @n is a power of 2, otherwise false. */ - static inline __attribute__((const)) bool is_power_of_2(unsigned long n) { return (n != 0 && ((n & (n - 1)) == 0)); } -/* - * round up to nearest power of two +/** + * __roundup_pow_of_two() - round up to nearest power of two + * @n: value to round up */ static inline __attribute__((const)) unsigned long __roundup_pow_of_two(unsigned long n) { - return 1UL << fls(n - 1); + return 1UL << fls_long(n - 1); } -/* - * round down to nearest power of two +/** + * __rounddown_pow_of_two() - round down to nearest power of two + * @n: value to round down */ static inline __attribute__((const)) unsigned long __rounddown_pow_of_two(unsigned long n) @@ -73,19 +72,16 @@ } /** - * ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value - * @n - parameter + * const_ilog2 - log base 2 of 32-bit or a 64-bit constant unsigned value + * @n: parameter * - * constant-capable log of base 2 calculation - * - this can be used to initialise global variables from constant data, hence - * the massive ternary operator construction - * - * selects the appropriately-sized optimised version depending on sizeof(n) + * Use this where sparse expects a true constant expression, e.g. for array + * indices. */ -#define ilog2(n) \ +#define const_ilog2(n) \ ( \ __builtin_constant_p(n) ? ( \ - (n) < 1 ? ____ilog2_NaN() : \ + (n) < 2 ? 0 : \ (n) & (1ULL << 63) ? 63 : \ (n) & (1ULL << 62) ? 62 : \ (n) & (1ULL << 61) ? 61 : \ @@ -148,18 +144,31 @@ (n) & (1ULL << 4) ? 4 : \ (n) & (1ULL << 3) ? 3 : \ (n) & (1ULL << 2) ? 2 : \ - (n) & (1ULL << 1) ? 1 : \ - (n) & (1ULL << 0) ? 0 : \ - ____ilog2_NaN() \ - ) : \ - (sizeof(n) <= 4) ? \ - __ilog2_u32(n) : \ - __ilog2_u64(n) \ + 1) : \ + -1) + +/** + * ilog2 - log base 2 of 32-bit or a 64-bit unsigned value + * @n: parameter + * + * constant-capable log of base 2 calculation + * - this can be used to initialise global variables from constant data, hence + * the massive ternary operator construction + * + * selects the appropriately-sized optimised version depending on sizeof(n) + */ +#define ilog2(n) \ +( \ + __builtin_constant_p(n) ? \ + const_ilog2(n) : \ + (sizeof(n) <= 4) ? \ + __ilog2_u32(n) : \ + __ilog2_u64(n) \ ) /** * roundup_pow_of_two - round the given value up to nearest power of two - * @n - parameter + * @n: parameter * * round the given value up to the nearest power of two * - the result is undefined when n == 0 @@ -176,7 +185,7 @@ /** * rounddown_pow_of_two - round the given value down to nearest power of two - * @n - parameter + * @n: parameter * * round the given value down to the nearest power of two * - the result is undefined when n == 0 @@ -189,6 +198,12 @@ __rounddown_pow_of_two(n) \ ) +static inline __attribute_const__ +int __order_base_2(unsigned long n) +{ + return n > 1 ? ilog2(n - 1) + 1 : 0; +} + /** * order_base_2 - calculate the (rounded up) base 2 order of the argument * @n: parameter @@ -202,7 +217,11 @@ * ob2(5) = 3 * ... and so on. */ - -#define order_base_2(n) ilog2(roundup_pow_of_two(n)) - +#define order_base_2(n) \ +( \ + __builtin_constant_p(n) ? ( \ + ((n) == 0 || (n) == 1) ? 0 : \ + ilog2((n) - 1) + 1) : \ + __order_base_2(n) \ +) #endif /* _LINUX_LOG2_H */ diff --git a/include/linux/mfd/rave-sp.h b/include/linux/mfd/rave-sp.h index e0d97a5..50c9865 100644 --- a/include/linux/mfd/rave-sp.h +++ b/include/linux/mfd/rave-sp.h @@ -21,6 +21,7 @@ RAVE_SP_CMD_STATUS = 0xA0, RAVE_SP_CMD_SW_WDT = 0xA1, RAVE_SP_CMD_PET_WDT = 0xA2, + RAVE_SP_CMD_RMB_EEPROM = 0xA4, RAVE_SP_CMD_SET_BACKLIGHT = 0xA6, RAVE_SP_CMD_RESET = 0xA7, RAVE_SP_CMD_RESET_REASON = 0xA8, diff --git a/include/ratp.h b/include/ratp.h index 6f4cf8a..d2a8192 100644 --- a/include/ratp.h +++ b/include/ratp.h @@ -11,7 +11,7 @@ void ratp_close(struct ratp *ratp); int ratp_recv(struct ratp *ratp, void **data, size_t *len); int ratp_send(struct ratp *ratp, const void *data, size_t len); -int ratp_send_complete(struct ratp *ratp, const void *data, size_t len, +int ratp_send_complete(struct ratp *ratp, const uint8_t *data, size_t len, void (*complete)(void *ctx, int status), void *complete_ctx); int ratp_poll(struct ratp *ratp); bool ratp_closed(struct ratp *ratp); diff --git a/lib/ratp.c b/lib/ratp.c index 4c5c748..7801cae 100644 --- a/lib/ratp.c +++ b/lib/ratp.c @@ -1734,11 +1734,12 @@ * * Return: 0 if successful, a negative error code otherwise. */ -int ratp_send_complete(struct ratp *ratp, const void *data, size_t len, +int ratp_send_complete(struct ratp *ratp, const uint8_t *data, size_t len, void (*complete)(void *ctx, int status), void *complete_ctx) { struct ratp_internal *ri = ratp->internal; struct ratp_message *msg; + int sent = 0; if (!ri || ri->state != RATP_STATE_ESTABLISHED) return -ENETDOWN; @@ -1754,11 +1755,12 @@ msg = xzalloc(sizeof(*msg)); msg->buf = xzalloc(sizeof(struct ratp_header) + now + 2); msg->len = now; - memcpy(msg->buf + sizeof(struct ratp_header), data, now); + memcpy(msg->buf + sizeof(struct ratp_header), data + sent, now); list_add_tail(&msg->list, &ri->sendmsg); len -= now; + sent += now; } msg->eor = 1; diff --git a/net/net.c b/net/net.c index d218554..63f42fa 100644 --- a/net/net.c +++ b/net/net.c @@ -149,7 +149,7 @@ struct eth_device *edev; for_each_netdev(edev) { - if (!edev->ipaddr) + if (!edev->ipaddr || !edev->ifup) continue; if ((dest & edev->netmask) == (edev->ipaddr & edev->netmask)) { diff --git a/scripts/dtc/.gitignore b/scripts/dtc/.gitignore index cdabdc9..80f6b50 100644 --- a/scripts/dtc/.gitignore +++ b/scripts/dtc/.gitignore @@ -2,3 +2,4 @@ dtc-lexer.lex.c dtc-parser.tab.c dtc-parser.tab.h +fdtget