diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/Kconfig | 13 | ||||
-rw-r--r-- | drivers/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/cros_ec.c | 3 | ||||
-rw-r--r-- | drivers/misc/cros_ec_sandbox.c | 2 | ||||
-rw-r--r-- | drivers/misc/cros_ec_spi.c | 23 | ||||
-rw-r--r-- | drivers/misc/i2c_eeprom_emul.c | 1 | ||||
-rw-r--r-- | drivers/misc/pca9551_led.c | 155 | ||||
-rw-r--r-- | drivers/misc/swap_case.c | 1 |
8 files changed, 195 insertions, 4 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 0e571d9..64b07a3 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -60,3 +60,16 @@ config CONFIG_FSL_SEC_MON system states. Security Monitor can be transitioned on any security failures, like software violations or hardware security violations. + +config PCA9551_LED + bool "Enable PCA9551 LED driver" + help + Enable driver for PCA9551 LED controller. This controller + is connected via I2C. So I2C needs to be enabled. + +config PCA9551_I2C_ADDR + hex "I2C address of PCA9551 LED controller" + depends on PCA9551_LED + default 0x60 + help + The I2C address of the PCA9551 LED controller. diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 25630c3..120babc 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_SANDBOX) += swap_case.o obj-$(CONFIG_TWL4030_LED) += twl4030_led.o obj-$(CONFIG_FSL_IFC) += fsl_ifc.o obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o +obj-$(CONFIG_PCA9551_LED) += pca9551_led.o diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 982bac7..4b6ac6a 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -986,7 +986,8 @@ int cros_ec_register(struct udevice *dev) } /* Remember this device for use by the cros_ec command */ - debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id); + debug("Google Chrome EC v%d CROS-EC driver ready, id '%s'\n", + cdev->protocol_version, id); return 0; } diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index df41e82..7509612 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -459,6 +459,8 @@ static int process_cmd(struct ec_state *ec, case EC_CMD_MKBP_STATE: len = cros_ec_keyscan(ec, resp_data); break; + case EC_CMD_ENTERING_MODE: + break; default: printf(" ** Unknown EC command %#02x\n", req_hdr->command); return -1; diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c index ac2ee86..0686925 100644 --- a/drivers/misc/cros_ec_spi.c +++ b/drivers/misc/cros_ec_spi.c @@ -25,6 +25,8 @@ int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes) { struct cros_ec_dev *dev = dev_get_uclass_priv(udev); struct spi_slave *slave = dev_get_parentdata(dev->dev); + ulong start; + uint8_t byte; int rv; /* Do the transfer */ @@ -33,10 +35,25 @@ int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes) return -1; } - rv = spi_xfer(slave, max(out_bytes, in_bytes) * 8, - dev->dout, dev->din, - SPI_XFER_BEGIN | SPI_XFER_END); + rv = spi_xfer(slave, out_bytes * 8, dev->dout, NULL, SPI_XFER_BEGIN); + if (rv) + goto done; + start = get_timer(0); + while (1) { + rv = spi_xfer(slave, 8, NULL, &byte, 0); + if (byte == SPI_PREAMBLE_END_BYTE) + break; + if (rv) + goto done; + if (get_timer(start) > 100) { + rv = -ETIMEDOUT; + goto done; + } + } + rv = spi_xfer(slave, in_bytes * 8, NULL, dev->din, 0); +done: + spi_xfer(slave, 0, NULL, NULL, SPI_XFER_END); spi_release_bus(slave); if (rv) { diff --git a/drivers/misc/i2c_eeprom_emul.c b/drivers/misc/i2c_eeprom_emul.c index 7343445..4410d03 100644 --- a/drivers/misc/i2c_eeprom_emul.c +++ b/drivers/misc/i2c_eeprom_emul.c @@ -8,6 +8,7 @@ #include <common.h> #include <dm.h> +#include <errno.h> #include <fdtdec.h> #include <i2c.h> #include <malloc.h> diff --git a/drivers/misc/pca9551_led.c b/drivers/misc/pca9551_led.c new file mode 100644 index 0000000..79b1e20 --- /dev/null +++ b/drivers/misc/pca9551_led.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2015 Stefan Roese <sr@denx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <i2c.h> + +#ifndef CONFIG_PCA9551_I2C_ADDR +#error "CONFIG_PCA9551_I2C_ADDR not defined!" +#endif + +#define PCA9551_REG_INPUT 0x00 /* Input register (read only) */ +#define PCA9551_REG_PSC0 0x01 /* Frequency prescaler 0 */ +#define PCA9551_REG_PWM0 0x02 /* PWM0 */ +#define PCA9551_REG_PSC1 0x03 /* Frequency prescaler 1 */ +#define PCA9551_REG_PWM1 0x04 /* PWM1 */ +#define PCA9551_REG_LS0 0x05 /* LED0 to LED3 selector */ +#define PCA9551_REG_LS1 0x06 /* LED4 to LED7 selector */ + +#define PCA9551_CTRL_AI (1 << 4) /* Auto-increment flag */ + +#define PCA9551_LED_STATE_ON 0x00 +#define PCA9551_LED_STATE_OFF 0x01 +#define PCA9551_LED_STATE_BLINK0 0x02 +#define PCA9551_LED_STATE_BLINK1 0x03 + +struct pca9551_blink_rate { + u8 psc; /* Frequency preescaler, see PCA9551_7.pdf p. 6 */ + u8 pwm; /* Pulse width modulation, see PCA9551_7.pdf p. 6 */ +}; + +static int freq0, freq1; + +static int pca9551_led_get_state(int led, int *state) +{ + unsigned int reg; + u8 shift, buf; + int ret; + + if (led < 0 || led > 7) { + return -EINVAL; + } else if (led < 4) { + reg = PCA9551_REG_LS0; + shift = led << 1; + } else { + reg = PCA9551_REG_LS1; + shift = (led - 4) << 1; + } + + ret = i2c_read(CONFIG_PCA9551_I2C_ADDR, reg, 1, &buf, 1); + if (ret) + return ret; + + *state = (buf >> shift) & 0x03; + return 0; +} + +static int pca9551_led_set_state(int led, int state) +{ + unsigned int reg; + u8 shift, buf, mask; + int ret; + + if (led < 0 || led > 7) { + return -EINVAL; + } else if (led < 4) { + reg = PCA9551_REG_LS0; + shift = led << 1; + } else { + reg = PCA9551_REG_LS1; + shift = (led - 4) << 1; + } + mask = 0x03 << shift; + + ret = i2c_read(CONFIG_PCA9551_I2C_ADDR, reg, 1, &buf, 1); + if (ret) + return ret; + + buf = (buf & ~mask) | ((state & 0x03) << shift); + + ret = i2c_write(CONFIG_PCA9551_I2C_ADDR, reg, 1, &buf, 1); + if (ret) + return ret; + + return 0; +} + +static int pca9551_led_set_blink_rate(int idx, struct pca9551_blink_rate rate) +{ + unsigned int reg; + int ret; + + switch (idx) { + case 0: + reg = PCA9551_REG_PSC0; + break; + case 1: + reg = PCA9551_REG_PSC1; + break; + default: + return -EINVAL; + } + reg |= PCA9551_CTRL_AI; + + ret = i2c_write(CONFIG_PCA9551_I2C_ADDR, reg, 1, (u8 *)&rate, 2); + if (ret) + return ret; + + return 0; +} + +/* + * Functions referenced by cmd_led.c + */ +void __led_set(led_id_t mask, int state) +{ + if (state == STATUS_LED_OFF) + pca9551_led_set_state(mask, PCA9551_LED_STATE_OFF); + else + pca9551_led_set_state(mask, PCA9551_LED_STATE_ON); +} + +void __led_toggle(led_id_t mask) +{ + int state = 0; + + pca9551_led_get_state(mask, &state); + pca9551_led_set_state(mask, !state); +} + +void __led_blink(led_id_t mask, int freq) +{ + struct pca9551_blink_rate rate; + int mode; + int blink; + + if ((freq0 == 0) || (freq == freq0)) { + blink = 0; + mode = PCA9551_LED_STATE_BLINK0; + freq0 = freq; + } else { + blink = 1; + mode = PCA9551_LED_STATE_BLINK1; + freq1 = freq; + } + + rate.psc = ((freq * 38) / 1000) - 1; + rate.pwm = 128; /* 50% duty cycle */ + + pca9551_led_set_blink_rate(blink, rate); + pca9551_led_set_state(mask, mode); +} diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c index f6028ba..3b8aa48 100644 --- a/drivers/misc/swap_case.c +++ b/drivers/misc/swap_case.c @@ -9,6 +9,7 @@ #include <common.h> #include <dm.h> +#include <errno.h> #include <pci.h> #include <asm/test.h> #include <linux/ctype.h> |