i2c: add support for ww_ring
This is a copy of the depthcharge ww ring driver implementation ported into coreboot. The main differences are: - direct use of the i2c driver instead of using the callback driver description - no dynamic memory allocation for the controller structures BRANCH=storm BUG=chrome-os-partner:36059 TEST=with the rest of the patches applied the LED ring gets initialized to the default pattern at coreboot start. Change-Id: I6902c8b76fc173ad2ec28b8cc94695e892df338a Signed-off-by: Patrick Georgi <pgeorgi@chromium.org> Original-Commit-Id: eda24b78f8aff311dd6296d458bdfecf26c3d65a Original-Change-Id: I5660dc3f255aab8fbe3a87041c72916a645c193b Original-Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Original-Reviewed-on: https://chromium-review.googlesource.com/257730 Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/9858 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
parent
dd78736d4e
commit
71558f5627
|
@ -6,5 +6,6 @@ source src/drivers/i2c/i2cmux2/Kconfig
|
||||||
source src/drivers/i2c/lm63/Kconfig
|
source src/drivers/i2c/lm63/Kconfig
|
||||||
source src/drivers/i2c/rtd2132/Kconfig
|
source src/drivers/i2c/rtd2132/Kconfig
|
||||||
source src/drivers/i2c/tpm/Kconfig
|
source src/drivers/i2c/tpm/Kconfig
|
||||||
source src/drivers/i2c/w83795/Kconfig
|
|
||||||
source src/drivers/i2c/w83793/Kconfig
|
source src/drivers/i2c/w83793/Kconfig
|
||||||
|
source src/drivers/i2c/w83795/Kconfig
|
||||||
|
source src/drivers/i2c/ww_ring/Kconfig
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
subdirs-y += adm1026
|
subdirs-y += adm1026
|
||||||
subdirs-y += adm1027
|
subdirs-y += adm1027
|
||||||
subdirs-y += adt7463
|
subdirs-y += adt7463
|
||||||
|
subdirs-y += at24rf08c
|
||||||
subdirs-y += i2cmux
|
subdirs-y += i2cmux
|
||||||
subdirs-y += i2cmux2
|
subdirs-y += i2cmux2
|
||||||
subdirs-y += lm63
|
subdirs-y += lm63
|
||||||
subdirs-y += rtd2132
|
subdirs-y += rtd2132
|
||||||
subdirs-y += tpm
|
subdirs-y += tpm
|
||||||
subdirs-y += w83795
|
|
||||||
subdirs-y += w83793
|
subdirs-y += w83793
|
||||||
subdirs-y += at24rf08c
|
subdirs-y += w83795
|
||||||
|
subdirs-y += ww_ring
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
config DRIVERS_I2C_WW_RING
|
||||||
|
bool
|
||||||
|
depends on CHROMEOS
|
|
@ -0,0 +1 @@
|
||||||
|
verstage-$(CONFIG_DRIVERS_I2C_WW_RING) += ww_ring.c
|
|
@ -0,0 +1,401 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Google, Inc.
|
||||||
|
*
|
||||||
|
* This software is licensed under the terms of the GNU General Public
|
||||||
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
* may be copied, distributed, and modified under those terms.
|
||||||
|
*
|
||||||
|
* 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 is a driver for the Whirlwind LED ring, which is equipped with two LED
|
||||||
|
* microcontrollers TI LP55231 (http://www.ti.com/product/lp55231), each of
|
||||||
|
* them driving three multicolor LEDs.
|
||||||
|
*
|
||||||
|
* The only connection between the ring and the main board is an i2c bus.
|
||||||
|
*
|
||||||
|
* This driver imitates a depthcharge display device. On initialization the
|
||||||
|
* driver sets up the controllers to prepare them to accept programs to run.
|
||||||
|
*
|
||||||
|
* When a certain vboot state needs to be indicated, the program for that
|
||||||
|
* state is loaded into the controllers, resulting in the state appropriate
|
||||||
|
* LED behavior.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <console/console.h>
|
||||||
|
#include <device/i2c.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "drivers/i2c/ww_ring/ww_ring.h"
|
||||||
|
|
||||||
|
/* Number of lp55321 controllers on the ring */
|
||||||
|
#define WW_RING_NUM_LED_CONTROLLERS 2
|
||||||
|
|
||||||
|
/* I2c address of the first of the controllers, the rest are contiguous. */
|
||||||
|
#define WW_RING_BASE_ADDR 0x32
|
||||||
|
|
||||||
|
/* Key lp55231 registers. */
|
||||||
|
#define LP55231_ENGCTRL1_REG 0x00
|
||||||
|
#define LP55231_ENGCTRL2_REG 0x01
|
||||||
|
#define LP55231_D1_CRT_CTRL_REG 0x26
|
||||||
|
#define LP55231_MISC_REG 0x36
|
||||||
|
#define LP55231_RESET_REG 0x3d
|
||||||
|
#define LP55231_ENG1_PROG_START 0x4c
|
||||||
|
#define LP55231_PROG_PAGE_REG 0x4f
|
||||||
|
#define LP55231_PROG_BASE_REG 0x50
|
||||||
|
|
||||||
|
/* LP55231_D1_CRT_CTRL_REG, default value, applies to all nine of them */
|
||||||
|
#define LP55231_CRT_CTRL_DEFAULT 0xaf
|
||||||
|
|
||||||
|
/* LP55231_ENGCTRL1_REG fields */
|
||||||
|
#define LP55231_ENGCTRL1_CHIP_EN 0x40
|
||||||
|
#define LP55231_ENGCTRL1_ALL_ENG_GO 0x2a
|
||||||
|
|
||||||
|
/* LP55231_MISC_REG fields. */
|
||||||
|
#define LP55231_MISC_AUTOINCR (1 << 6)
|
||||||
|
#define LP55231_MISC_PUMP_1X (1 << 3)
|
||||||
|
#define LP55231_MISC_INT_CLK (3 << 0)
|
||||||
|
|
||||||
|
/* Goes into LP55231_RESET_REG to reset the chip. */
|
||||||
|
#define LP55231_RESET_VALUE 0xff
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The controller has 192 bytes of SRAM for code/data, availabe as six 32 byte
|
||||||
|
* pages.
|
||||||
|
*/
|
||||||
|
#define LP55231_PROG_PAGE_SIZE 32
|
||||||
|
#define LP55231_PROG_PAGES 6
|
||||||
|
#define LP55231_MAX_PROG_SIZE (LP55231_PROG_PAGE_SIZE * LP55231_PROG_PAGES)
|
||||||
|
|
||||||
|
/* There are threee independent engines/cores in the controller. */
|
||||||
|
#define LP55231_NUM_OF_ENGINES 3
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure to cache data relevant to accessing one controller. I2c interface
|
||||||
|
* to use, device address on the i2c bus and a data buffer for write
|
||||||
|
* transactions. The most bytes sent at a time is the register address plus
|
||||||
|
* the program page size.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
unsigned i2c_bus;
|
||||||
|
uint8_t dev_addr;
|
||||||
|
uint8_t data_buffer[LP55231_PROG_PAGE_SIZE + 1];
|
||||||
|
} TiLp55231;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure to describe an lp55231 program: pointer to the text of the
|
||||||
|
* program, its size and load address (load addr + size sould not exceed
|
||||||
|
* LP55231_MAX_PROG_SIZE), and start addresses for all of the three
|
||||||
|
* engines.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
const uint8_t *program_text;
|
||||||
|
uint8_t program_size;
|
||||||
|
uint8_t load_addr;
|
||||||
|
uint8_t engine_start_addr[LP55231_NUM_OF_ENGINES];
|
||||||
|
} TiLp55231Program;
|
||||||
|
|
||||||
|
/* A structure to bind controller programs to a vboot state. */
|
||||||
|
typedef struct {
|
||||||
|
enum VbScreenType_t vb_screen;
|
||||||
|
const TiLp55231Program * programs[WW_RING_NUM_LED_CONTROLLERS];
|
||||||
|
} WwRingStateProg;
|
||||||
|
|
||||||
|
static void ww_ring_init(unsigned i2c_bus);
|
||||||
|
|
||||||
|
/****************************************************************/
|
||||||
|
/* LED ring program definitions for different vboot states. */
|
||||||
|
|
||||||
|
static const uint8_t blink_program_text[] = {
|
||||||
|
0x40, 0x40, 0x9D, 0x04, 0x40, 0x40, 0x7E,
|
||||||
|
0x00, 0x9D, 0x07, 0x40, 0x00, 0x9D, 0x04,
|
||||||
|
0x40, 0x00, 0x7E, 0x00, 0xA0, 0x00, 0x00,
|
||||||
|
0x00 };
|
||||||
|
|
||||||
|
static const TiLp55231Program led_blink_program = {
|
||||||
|
blink_program_text,
|
||||||
|
sizeof(blink_program_text),
|
||||||
|
0,
|
||||||
|
{0,
|
||||||
|
sizeof(blink_program_text) - 2,
|
||||||
|
sizeof(blink_program_text) - 2}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const WwRingStateProg state_programs[] = {
|
||||||
|
/*
|
||||||
|
* for test purposes the blank screen program is set to blinking, will
|
||||||
|
* be changed soon.
|
||||||
|
*/
|
||||||
|
{VB_SCREEN_BLANK, {&led_blink_program, &led_blink_program} },
|
||||||
|
/* Other vboot state programs are coming. */
|
||||||
|
};
|
||||||
|
/* */
|
||||||
|
/****************************************************************/
|
||||||
|
|
||||||
|
/* Controller descriptors. */
|
||||||
|
static TiLp55231 lp55231s[WW_RING_NUM_LED_CONTROLLERS];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* i2c transfer function for the driver. To keep things simple, the function
|
||||||
|
* repeats the transfer, if the first attempt fails. This is OK with the
|
||||||
|
* controller and makes it easier to handle errors.
|
||||||
|
*
|
||||||
|
* Note that the reset register accesses are expected to fail on writes, but
|
||||||
|
* due to a bug in the ipq806x i2c controller, the error is reported on the
|
||||||
|
* following read attempt.
|
||||||
|
*
|
||||||
|
* To work around this the driver writes and then reads the reset register,
|
||||||
|
* the transfer function ignores errors when accessing the reset register.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int ledc_transfer(TiLp55231 *ledc, struct i2c_seg *segs,
|
||||||
|
int seg_count, int reset)
|
||||||
|
{
|
||||||
|
int rv, max_attempts = 2;
|
||||||
|
|
||||||
|
while (max_attempts--) {
|
||||||
|
rv = i2c_transfer(ledc->i2c_bus, segs, seg_count);
|
||||||
|
|
||||||
|
/* Accessing reset regsiter is expected to fail. */
|
||||||
|
if (!rv || reset)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rv) {
|
||||||
|
if (!reset)
|
||||||
|
printk(BIOS_WARNING,
|
||||||
|
"%s: dev %#x, reg %#x, %s transaction error.\n",
|
||||||
|
__func__, segs->chip, segs->buf[0],
|
||||||
|
seg_count == 1 ? "write" : "read");
|
||||||
|
else
|
||||||
|
rv = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The controller is programmed to autoincrement on writes, so up to page size
|
||||||
|
* bytes can be transmitted in one write transaction.
|
||||||
|
*/
|
||||||
|
static int ledc_write(TiLp55231 *ledc, uint8_t start_addr,
|
||||||
|
const uint8_t *data, unsigned count)
|
||||||
|
{
|
||||||
|
struct i2c_seg seg;
|
||||||
|
|
||||||
|
if (count > (sizeof(ledc->data_buffer) - 1)) {
|
||||||
|
printk(BIOS_WARNING, "%s: transfer size too large (%d bytes)\n",
|
||||||
|
__func__, count);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ledc->data_buffer + 1, data, count);
|
||||||
|
ledc->data_buffer[0] = start_addr;
|
||||||
|
|
||||||
|
seg.read = 0;
|
||||||
|
seg.chip = ledc->dev_addr;
|
||||||
|
seg.buf = ledc->data_buffer;
|
||||||
|
seg.len = count + 1;
|
||||||
|
|
||||||
|
return ledc_transfer(ledc, &seg, 1, start_addr == LP55231_RESET_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To keep things simple, read is limited to one byte at a time. */
|
||||||
|
static int ledc_read(TiLp55231 *ledc, uint8_t addr, uint8_t *data)
|
||||||
|
{
|
||||||
|
struct i2c_seg seg[2];
|
||||||
|
|
||||||
|
seg[0].read = 0;
|
||||||
|
seg[0].chip = ledc->dev_addr;
|
||||||
|
seg[0].buf = &addr;
|
||||||
|
seg[0].len = 1;
|
||||||
|
|
||||||
|
seg[1].read = 1;
|
||||||
|
seg[1].chip = ledc->dev_addr;
|
||||||
|
seg[1].buf = data;
|
||||||
|
seg[1].len = 1;
|
||||||
|
|
||||||
|
return ledc_transfer(ledc, seg, ARRAY_SIZE(seg),
|
||||||
|
addr == LP55231_RESET_REG);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reset transaction is expected to result in a failing i2c command,
|
||||||
|
* no need to return a value.
|
||||||
|
*/
|
||||||
|
static void ledc_reset(TiLp55231 *ledc)
|
||||||
|
{
|
||||||
|
uint8_t data;
|
||||||
|
|
||||||
|
data = LP55231_RESET_VALUE;
|
||||||
|
ledc_write(ledc, LP55231_RESET_REG, &data, 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This read is not necessary for the chip reset, but is required to
|
||||||
|
* work around the i2c driver bug where the missing ACK on the last
|
||||||
|
* byte of the write transaction is ignored, but the next transaction
|
||||||
|
* fails.
|
||||||
|
*/
|
||||||
|
ledc_read(ledc, LP55231_RESET_REG, &data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write a program into the internal lp55231 memory. Split write transactions
|
||||||
|
* into sections fitting into memory pages.
|
||||||
|
*/
|
||||||
|
static void ledc_write_program(TiLp55231 *ledc, uint8_t load_addr,
|
||||||
|
const uint8_t *program, unsigned count)
|
||||||
|
{
|
||||||
|
uint8_t page_num = load_addr / LP55231_PROG_PAGE_SIZE;
|
||||||
|
unsigned page_offs = load_addr % LP55231_PROG_PAGE_SIZE;
|
||||||
|
|
||||||
|
if ((load_addr + count) > LP55231_MAX_PROG_SIZE) {
|
||||||
|
printk(BIOS_WARNING,
|
||||||
|
"%s: program of size %#x does not fit at addr %#x\n",
|
||||||
|
__func__, count, load_addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (count) {
|
||||||
|
unsigned segment_size = LP55231_PROG_PAGE_SIZE - page_offs;
|
||||||
|
|
||||||
|
if (segment_size > count)
|
||||||
|
segment_size = count;
|
||||||
|
|
||||||
|
ledc_write(ledc, LP55231_PROG_PAGE_REG, &page_num, 1);
|
||||||
|
ledc_write(ledc, LP55231_PROG_BASE_REG + page_offs,
|
||||||
|
program, segment_size);
|
||||||
|
|
||||||
|
count -= segment_size;
|
||||||
|
page_offs = 0;
|
||||||
|
page_num++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Run an lp55231 program on a controller. */
|
||||||
|
static void ledc_run_program(TiLp55231 *ledc,
|
||||||
|
const TiLp55231Program *program_desc)
|
||||||
|
{
|
||||||
|
uint8_t data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
data = 0;
|
||||||
|
ledc_write(ledc, LP55231_ENGCTRL2_REG, &data, 1);
|
||||||
|
data = 0x15;
|
||||||
|
ledc_write(ledc, LP55231_ENGCTRL2_REG, &data, 1);
|
||||||
|
ledc_write_program(ledc, program_desc->load_addr,
|
||||||
|
program_desc->program_text,
|
||||||
|
program_desc->program_size);
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(program_desc->engine_start_addr); i++)
|
||||||
|
ledc_write(ledc, LP55231_ENG1_PROG_START + i,
|
||||||
|
program_desc->engine_start_addr + i, 1);
|
||||||
|
|
||||||
|
data = 0;
|
||||||
|
ledc_write(ledc, LP55231_ENGCTRL2_REG, &data, 1);
|
||||||
|
data = 0x2a;
|
||||||
|
ledc_write(ledc, LP55231_ENGCTRL2_REG, &data, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize a controller to a state were it is ready to accept programs, and
|
||||||
|
* try to confirm that we are in fact talking to a lp55231
|
||||||
|
*/
|
||||||
|
static int ledc_init_validate(TiLp55231 *ledc)
|
||||||
|
{
|
||||||
|
const uint8_t ctrl1_reset[] = {
|
||||||
|
0,
|
||||||
|
LP55231_ENGCTRL1_CHIP_EN,
|
||||||
|
LP55231_ENGCTRL1_CHIP_EN | LP55231_ENGCTRL1_ALL_ENG_GO
|
||||||
|
};
|
||||||
|
uint8_t data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ledc_reset(ledc);
|
||||||
|
|
||||||
|
/* Set up all engines to run. */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(ctrl1_reset); i++)
|
||||||
|
ledc_write(ledc, LP55231_ENGCTRL1_REG, ctrl1_reset + i, 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal clock, 3.3V output (pump 1x), autoincrement on multibyte
|
||||||
|
* writes.
|
||||||
|
*/
|
||||||
|
data = LP55231_MISC_AUTOINCR |
|
||||||
|
LP55231_MISC_PUMP_1X | LP55231_MISC_INT_CLK;
|
||||||
|
ledc_write(ledc, LP55231_MISC_REG, &data, 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All nine current control registers are supposed to return the same
|
||||||
|
* value at reset.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < 9; i++) {
|
||||||
|
data = 0;
|
||||||
|
ledc_read(ledc, LP55231_D1_CRT_CTRL_REG + i, &data);
|
||||||
|
if (data != LP55231_CRT_CTRL_DEFAULT) {
|
||||||
|
printk(BIOS_WARNING,
|
||||||
|
"%s: read %#2.2x from register %#x\n", __func__,
|
||||||
|
data, LP55231_D1_CRT_CTRL_REG + i);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find a program matching screen type, and run it on both controllers, if
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
|
int ww_ring_display_pattern(unsigned i2c_bus, enum VbScreenType_t screen_type)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
static int initted;
|
||||||
|
|
||||||
|
if (!initted) {
|
||||||
|
ww_ring_init(i2c_bus);
|
||||||
|
initted = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(state_programs); i++)
|
||||||
|
if (state_programs[i].vb_screen == screen_type) {
|
||||||
|
int j;
|
||||||
|
for (j = 0; j < WW_RING_NUM_LED_CONTROLLERS; j++)
|
||||||
|
ledc_run_program(lp55231s + j,
|
||||||
|
state_programs[i].programs[j]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk(BIOS_WARNING, "%s: did not find program for screen %d\n",
|
||||||
|
__func__, screen_type);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define LP55231_I2C_BASE_ADDR 0x32
|
||||||
|
|
||||||
|
static void ww_ring_init(unsigned i2c_bus)
|
||||||
|
{
|
||||||
|
TiLp55231 *ledc;
|
||||||
|
int i, count = 0;
|
||||||
|
|
||||||
|
for (i = 0, ledc = lp55231s;
|
||||||
|
i < WW_RING_NUM_LED_CONTROLLERS;
|
||||||
|
i++, ledc++) {
|
||||||
|
|
||||||
|
ledc->i2c_bus = i2c_bus;
|
||||||
|
ledc->dev_addr = LP55231_I2C_BASE_ADDR + i;
|
||||||
|
|
||||||
|
if (!ledc_init_validate(ledc))
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk(BIOS_INFO, "WW_RING: initialized %d out of %d\n", count, i);
|
||||||
|
if (count != i)
|
||||||
|
printk(BIOS_WARNING, "WW_RING: will keep going anyway\n");
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Google, Inc.
|
||||||
|
*
|
||||||
|
* This software is licensed under the terms of the GNU General Public
|
||||||
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
* may be copied, distributed, and modified under those terms.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SRC_DRIVERS_VIDEO_WW_RING__H__
|
||||||
|
#define __SRC_DRIVERS_VIDEO_WW_RING__H__
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_CHROMEOS)
|
||||||
|
#include <vboot_api.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ww_ring_display_pattern
|
||||||
|
*
|
||||||
|
* Display pattern on the ring LEDs.
|
||||||
|
*/
|
||||||
|
int ww_ring_display_pattern(unsigned i2c_bus, enum VbScreenType_t screen_type);
|
||||||
|
|
||||||
|
#else
|
||||||
|
static inline int ww_ring_display_pattern(unsigned i2c_bus, int screen_type) { return 0;}
|
||||||
|
#endif
|
||||||
|
#endif
|
Loading…
Reference in New Issue