Add LP503x RGB LED driver

style corrections

Update lp503x.h

Update lp503x.h

Update lp503x.c

Update lp503x.h

post review changes
This commit is contained in:
TimJTi 2022-12-21 16:13:48 +00:00 committed by Xiang Xiao
parent 7c8f3b4916
commit 5f7bf743c5
4 changed files with 1294 additions and 0 deletions

View file

@ -83,6 +83,55 @@ config RGBLED_LIGHTNESS_CORRECTION
correction which helps the RGB LED visually fade and blend
in a more linear, smooth, and visually appealing fashion.
config LP503X
bool "LP503X I2C LED Driver"
default n
select I2C
---help---
Enable support for the TI LP503X LED driver which can be
utilized to drive up to 36 (12 RGB) LEDs.
if LP503X
config LP503X_LOG_MODE
bool "Enable logarithmic mode (y) or linear mode (n)"
default y
---help---
Determines whether brightness scale is logarithmic or linear
config LP503X_POWER_SAVE
bool "Enable power save mode"
default y
---help---
Enable/disable automatic power saving mode
config LP503X_DITHER_MODE
bool "Enable PWM dithering"
default y
---help---
Enable/disable PWM dithering mode
config LP503X_MAX_CURRENT
bool "Enable Max current option (25.5mA (n), or 35mA (y))"
default n
---help---
Sets maximum output current to 25.5mA (default) or 35mA
config LP503X_GLOBAL_SHUTDOWN
bool "Enable global LED shutdown"
default n
---help---
When enabled (y), all LEDs will be turned off/disabled until re-enabled
config DEBUG_LP503X
bool "Enable debug support for the LP503X"
default n
---help---
Enables debug support for the LP503X
endif # LP503X
config PCA9635PW
bool "PCA9635PW I2C LED Driver"
default n

View file

@ -47,6 +47,12 @@ ifeq ($(CONFIG_RGBLED),y)
LEDVPATH = :leds
endif
ifeq ($(CONFIG_LP503X),y)
CSRCS += lp503x.c
LEDDEPATH = --dep-path leds
LEDVPATH = :leds
endif
ifeq ($(CONFIG_PCA9635PW),y)
CSRCS += pca9635pw.c
LEDDEPATH = --dep-path leds

969
drivers/leds/lp503x.c Normal file
View file

@ -0,0 +1,969 @@
/****************************************************************************
* drivers/leds/lp503x.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/kmalloc.h>
#include <nuttx/signal.h>
#include <nuttx/i2c/i2c_master.h>
#include <nuttx/leds/lp503x.h>
#if defined(CONFIG_I2C) && defined(CONFIG_LP503X)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifdef CONFIG_DEBUG_LP503X
# define lp503x_err(x, ...) _err(x, ##__VA_ARGS__)
# define lp503x_info(x, ...) _info(x, ##__VA_ARGS__)
#else
# define lp503x_err(x, ...) uerr(x, ##__VA_ARGS__)
# define lp503x_info(x, ...) uinfo(x, ##__VA_ARGS__)
#endif
/****************************************************************************
* Private Type Definitions
****************************************************************************/
enum lp503x_state
{
LP503X_STATE_UNINIT = 0,
LP503X_STATE_RESET,
LP503X_STATE_CONFIGURED,
};
struct lp503x_dev_s
{
struct i2c_master_s *i2c;
uint8_t i2c_addr;
int i2c_freq;
int count;
/* device configuration/setup data */
struct lp503x_config_s *lp503x_config;
/* current state of the lp503x device */
enum lp503x_state state;
};
/* A set of default config parameters as set in LED driver Kconfig */
struct lp503x_config_s config_default =
{
#ifdef CONFIG_LP503X_LOG_MODE
.enable_log_mode = 1,
#else
.enable_log_mode = 0,
#endif
#ifdef CONFIG_LP503X_POWER_SAVE
.enable_power_save = 1,
#else
.enable_power_save = 0,
#endif
#ifdef CONFIG_LP503X_DITHER_MODE
.enable_pwm_dithering = 1,
#else
.enable_pwm_dithering = 0,
#endif
#ifdef CONFIG_LP503X_MAX_CURRENT
.set_max_current_35ma = 1,
#else
.set_max_current_35ma = 0,
#endif
#ifdef CONFIG_LP503X_GLOBAL_SHUTDOWN
.enable_all_led_shutdown = 1,
#else
.enable_all_led_shutdown = 0,
#endif
/* all leds will default to independent control, not bank control */
.led_mode[0] = LP503X_LED_BANK_MODE_DISABLED,
.led_mode[1] = LP503X_LED_BANK_MODE_DISABLED,
.led_mode[2] = LP503X_LED_BANK_MODE_DISABLED,
.led_mode[3] = LP503X_LED_BANK_MODE_DISABLED,
.led_mode[4] = LP503X_LED_BANK_MODE_DISABLED,
.led_mode[5] = LP503X_LED_BANK_MODE_DISABLED,
.led_mode[6] = LP503X_LED_BANK_MODE_DISABLED,
.led_mode[7] = LP503X_LED_BANK_MODE_DISABLED,
.led_mode[8] = LP503X_LED_BANK_MODE_DISABLED,
.led_mode[9] = LP503X_LED_BANK_MODE_DISABLED,
.led_mode[10] = LP503X_LED_BANK_MODE_DISABLED,
.led_mode[11] = LP503X_LED_BANK_MODE_DISABLED,
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int lp503x_i2c_write_reg(struct lp503x_dev_s *priv,
uint8_t const reg_addr,
uint8_t const reg_val);
static int lp503x_i2c_read_reg(struct lp503x_dev_s *priv,
uint8_t const reg_addr,
uint8_t *regval);
static int lp503x_open(struct file *filep);
static int lp503x_close(struct file *filep);
static int lp503x_ioctl(struct file *filep, int cmd,
unsigned long arg);
#ifdef CONFIG_DEBUG_LP503X
static int lp503x_dump_registers(struct lp503x_dev_s *priv,
const char *msg);
#else
# define lp503x_dump_registers(priv, msg);
#endif
static int lp503x_reset(struct lp503x_dev_s *priv);
static int lp503x_enable(struct lp503x_dev_s *priv, bool enable);
static int lp503x_set_rgbbrightness(struct lp503x_dev_s *priv, int led,
int brightness);
static int lp503x_set_outcolour(struct lp503x_dev_s *priv, int led,
int colour);
static int lp503x_set_config(struct lp503x_dev_s *priv);
static int lp503x_set_bank_mode(struct lp503x_dev_s *priv);
static int lp503x_set_bank_colour(struct lp503x_dev_s *priv, char bank,
int brightness);
static int lp503x_set_bank_brightness(struct lp503x_dev_s *priv,
int brightness);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct file_operations g_lp503x_fileops =
{
lp503x_open, /* open */
lp503x_close, /* close */
NULL, /* read */
NULL, /* write */
NULL, /* seek */
lp503x_ioctl, /* ioctl */
NULL /* poll */
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
, NULL /* unlink */
#endif
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: lp503x_dumpregs
*
* Description:
* Dump the contents of all lp503x registers
*
* Input Parameters:
* priv - A reference to the lp503x peripheral state
* msg - Message to print before the register data
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_DEBUG_LP503X
static int lp503x_dump_registers(struct lp503x_dev_s *priv,
const char *msg)
{
uint8_t val1;
uint8_t val2;
uint8_t val3;
uint8_t val4;
int ret;
lp503x_info("lp503x Registers: %s\n", msg);
ret = lp503x_i2c_read_reg(priv, LP503X_DEVICE_CONFIG0, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_DEVICE_CONFIG1, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_LED_CONFIG0, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_LED_CONFIG1, &val4);
lp503x_info
("Dev Config0:\t%02x Dev Conf1:\t%02x \
LED Conf0:\t%02x: LED Conf1: \t %02x\n",
val1, val2, val3, val4);
ret = lp503x_i2c_read_reg(priv, LP503X_BANK_BRIGHTNESS, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_BANK_A_COLOUR, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_BANK_B_COLOUR, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_BANK_C_COLOUR, &val4);
lp503x_info
("Bank Bright:\t%02x BankA Col:\t%02x \
BankB Col:\t%02x: BankC Col:\t %02x\n",
val1, val2, val3, val4);
ret = lp503x_i2c_read_reg(priv, LP503X_LED0_BRIGHTNESS, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_LED1_BRIGHTNESS, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_LED2_BRIGHTNESS, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_LED3_BRIGHTNESS, &val4);
lp503x_info
("LED0 Bright:\t%02x LED1 Col:\t%02x \
LED2 Bright:\t%02x: LED3 Bright: %02x\n",
val1, val2, val3, val4);
ret = lp503x_i2c_read_reg(priv, LP503X_LED4_BRIGHTNESS, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_LED5_BRIGHTNESS, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_LED6_BRIGHTNESS, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_LED7_BRIGHTNESS, &val4);
lp503x_info
("LED4 Bright:\t%02x LED5 Bright:\t%02x \
LED6 Bright:\t%02x: LED7 Bright: %02x\n",
val1, val2, val3, val4);
ret = lp503x_i2c_read_reg(priv, LP503X_LED8_BRIGHTNESS, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_LED9_BRIGHTNESS, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_LED10_BRIGHTNESS, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_LED11_BRIGHTNESS, &val4);
lp503x_info
("LED8 Bright:\t%02x LED9 Bright:\t%02x \
LED10 Bright:\t%02x: LED11 Bright:%02x\n",
val1, val2, val3, val4);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT0_COLOUR, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT1_COLOUR, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT2_COLOUR, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT3_COLOUR, &val4);
lp503x_info
("Out0 Col:\t%02x Out1 Col:\t%02x \
Out2 Col:\t\t%02x Out3 Col:\t %02x\n",
val1, val2, val3, val4);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT4_COLOUR, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT5_COLOUR, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT6_COLOUR, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT7_COLOUR, &val4);
lp503x_info
("Out4 Col:\t%02x Out5 Col:\t%02x \
Out6 Col:\t\t%02x Out7 Col:\t %02x\n",
val1, val2, val3, val4);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT8_COLOUR, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT9_COLOUR, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT10_COLOUR, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT11_COLOUR, &val4);
lp503x_info
("Out8 Col:\t%02x Out9 Col:\t%02x \
Out10 Col:\t%02x Out11 Col:\t %02x\n",
val1, val2, val3, val4);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT12_COLOUR, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT13_COLOUR, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT14_COLOUR, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT15_COLOUR, &val4);
lp503x_info
("Out12 Col:\t%02x Out13 Col:\t%02x \
Out14 Col:\t%02x Out15 Col:\t %02x\n",
val1, val2, val3, val4);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT16_COLOUR, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT17_COLOUR, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT18_COLOUR, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT19_COLOUR, &val4);
lp503x_info
("Out16 Col:\t%02x Out17 Col:\t%02x \
Out18 Col:\t%02x Out19 Col:\t %02x\n",
val1, val2, val3, val4);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT20_COLOUR, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT21_COLOUR, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT22_COLOUR, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT23_COLOUR, &val4);
lp503x_info
("Out20 Col:\t%02x Out21 Col:\t%02x \
Out22 Col:\t%02x Out23 Col:\t %02x\n",
val1, val2, val3, val4);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT24_COLOUR, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT25_COLOUR, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT26_COLOUR, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT27_COLOUR, &val4);
lp503x_info
("Out24 Col:\t%02x Out25 Col:\t%02x \
Out26 Col:\t%02x Out27 Col:\t %02x\n",
val1, val2, val3, val4);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT28_COLOUR, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT29_COLOUR, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT30_COLOUR, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT31_COLOUR, &val4);
lp503x_info
("Out28 Col:\t%02x Out29 Col:\t%02x \
Out30 Col:\t%02x Out31 Col:\t %02x\n",
val1, val2, val3, val4);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT32_COLOUR, &val1);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT33_COLOUR, &val2);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT34_COLOUR, &val3);
ret = lp503x_i2c_read_reg(priv, LP503X_OUT35_COLOUR, &val4);
lp503x_info
("Out28 Col:\t%02x Out29 Col:\t%02x \
Out30 Col:\t%02x Out31 Col:\t %02x\n",
val1, val2, val3, val4);
return ret;
}
#endif
/****************************************************************************
* Name: lp503x_i2c_write_reg
*
* Description:
* Write a single byte to one of the LP503X configuration registers.
*
****************************************************************************/
static int lp503x_i2c_write_reg(struct lp503x_dev_s *priv,
uint8_t const reg_addr,
uint8_t const reg_val)
{
struct i2c_config_s config;
int ret;
/* assemble the 2 byte message comprised of reg_addr and reg_val */
uint8_t const BUFFER_SIZE = 2;
uint8_t buffer[BUFFER_SIZE];
buffer[0] = reg_addr;
buffer[1] = reg_val;
/* Setup up the I2C configuration */
config.frequency = priv->i2c_freq;
config.address = priv->i2c_addr;
config.addrlen = 7;
/* Write the register address followed by the data (no RESTART) */
ledinfo("i2c addr: 0x%02X reg addr: 0x%02X value: 0x%02X\n",
priv->i2c_addr, buffer[0], buffer[1]);
ret = i2c_write(priv->i2c, &config, buffer, BUFFER_SIZE);
if (ret < 0)
{
lederr("ERROR: i2c_write returned error code %d\n", ret);
return ret;
}
return OK;
}
/****************************************************************************
* Name: lp503x_i2c_read_reg
*
* Description:
* Read a single byte from one of the LP503X configuration registers.
*
****************************************************************************/
static int lp503x_i2c_read_reg(struct lp503x_dev_s *priv,
uint8_t const reg_addr,
uint8_t *regval)
{
struct i2c_config_s config;
int ret;
/* Setup up the I2C configuration */
config.frequency = priv->i2c_freq;
config.address = priv->i2c_addr;
config.addrlen = 7;
/* Write the register address followed by the data (no RESTART) */
ret = i2c_write(priv->i2c, &config, &reg_addr, 1);
ret = i2c_read(priv->i2c, &config, regval, 1);
return ret;
}
/****************************************************************************
* Name: lp503x_open
*
* Description:
* This function is called whenever a LP503X device is opened.
*
****************************************************************************/
static int lp503x_open(struct file *filep)
{
struct inode *inode = filep->f_inode;
struct lp503x_dev_s *priv = inode->i_private;
int ret;
ledinfo("INFO: Opening, resetting and enabling the LP503X for business\n");
/* reset and enable the device */
/* means the device was possibly never regsitered? */
if (priv->state == LP503X_STATE_UNINIT)
{
return -ENODEV;
}
else if (priv->state == LP503X_STATE_RESET)
{
ret = lp503x_enable(priv, true);
if (ret != 0)
{
lederr("ERROR: unable to enable lp503x\n");
return -EIO;
}
else
{
/* use device defaults */
priv->lp503x_config = &config_default;
}
ret = lp503x_set_config(priv);
if (ret != 0)
{
lederr("ERROR: Unable to set device config: %d\n", ret);
return -EIO;
}
priv->state = LP503X_STATE_CONFIGURED;
}
lp503x_dump_registers(priv, "File Open");
return ret;
}
/****************************************************************************
* Name: lp503x_close
*
* Description:
* This function is called whenever a LP503X device is closed.
*
****************************************************************************/
static int lp503x_close(struct file *filep)
{
int ret;
struct inode *inode = filep->f_inode;
struct lp503x_dev_s *priv = inode->i_private;
ret = lp503x_enable(priv, false);
if (ret < 0)
{
lederr("ERROR: Could not disable LP503X\n");
}
return ret;
}
/****************************************************************************
* Name: lp503x_reset
*
* Description:
* Resets all registers to default values
*
****************************************************************************/
static int lp503x_reset(struct lp503x_dev_s *priv)
{
int ret;
ret = lp503x_i2c_write_reg(priv, LP503X_RESET, LP503X_RESET_ALL_REGISTERS);
if (ret != 0)
{
return -EIO;
}
else
{
priv->state = LP503X_STATE_RESET;
return OK;
}
}
/****************************************************************************
* Name: lp503x_enable
*
* Description:
* enables or disables the entire device
*
****************************************************************************/
static int lp503x_enable(struct lp503x_dev_s *priv, bool enable)
{
int ret;
if (enable)
{
ret = lp503x_i2c_write_reg(priv, LP503X_DEVICE_CONFIG0,
LP503X_CHIP_ENABLE);
ledinfo("INFO: LP503x enabled\n");
}
else
{
ret = lp503x_i2c_write_reg(priv, LP503X_DEVICE_CONFIG0,
LP503X_CHIP_DISABLE);
ledinfo("INFO: LP503x disabled\n");
}
return ret;
}
/****************************************************************************
* Name: lp503x_set_config
*
* Description:
* configures basic operation modes of the device
*
****************************************************************************/
static int lp503x_set_config(struct lp503x_dev_s *priv)
{
int ret;
uint8_t regval;
struct lp503x_config_s *config;
config = priv->lp503x_config;
ret = lp503x_i2c_read_reg(priv, LP503X_DEVICE_CONFIG1, &regval);
if (config->enable_log_mode)
{
regval |= LP503X_CONFIG1_LOG_SCALE;
}
else
{
regval &= ~LP503X_CONFIG1_LOG_SCALE;
}
if (config->enable_power_save)
{
regval |= LP503X_CONFIG1_PWRSAVE;
}
else
{
regval &= ~LP503X_CONFIG1_PWRSAVE;
}
if (config->enable_pwm_dithering)
{
regval |= LP503X_CONFIG1_DITHERING;
}
else
{
regval &= ~LP503X_CONFIG1_DITHERING;
}
if (config->set_max_current_35ma)
{
regval |= LP503X_CONFIG1_PWRSAVE;
}
else
{
regval &= ~LP503X_CONFIG1_PWRSAVE;
}
if (config->enable_all_led_shutdown)
{
regval |= LP503X_CONFIG1_GLOBAL_OFF;
}
else
{
regval &= ~LP503X_CONFIG1_GLOBAL_OFF;
}
ret = lp503x_i2c_write_reg(priv, LP503X_DEVICE_CONFIG1, regval);
return ret;
}
/****************************************************************************
* Name: lp503x_set_bank_brightness
*
* Description:
* sets banks to the required brightness
*
****************************************************************************/
static int lp503x_set_bank_brightness(struct lp503x_dev_s *priv,
int brightness)
{
if (brightness > MAX_BRIGHTNESS)
{
return -EINVAL;
}
else
{
return lp503x_i2c_write_reg(priv, LP503X_BANK_BRIGHTNESS, brightness);
}
}
/****************************************************************************
* Name: lp503x_set_bank_colour
*
* Description:
* sets bank A, B or C led to required coloiur (mix)
*
****************************************************************************/
static int lp503x_set_bank_colour(struct lp503x_dev_s *priv, char bank,
int brightness)
{
if (brightness > MAX_BRIGHTNESS)
{
return -EINVAL;
}
else
{
if (bank == 'A')
{
return lp503x_i2c_write_reg(priv, LP503X_BANK_A_COLOUR,
brightness);
}
else if (bank == 'B')
{
return lp503x_i2c_write_reg(priv, LP503X_BANK_B_COLOUR,
brightness);
}
else if (bank == 'C')
{
return lp503x_i2c_write_reg(priv, LP503X_BANK_C_COLOUR,
brightness);
}
else
{
return -EINVAL;
}
}
}
/****************************************************************************
* Name: lp503x_set_bank_mode
*
* Description:
* enables or disables bank mode for selected LED
*
****************************************************************************/
static int lp503x_set_bank_mode(struct lp503x_dev_s *priv)
{
int ret;
int count;
int regval;
struct lp503x_config_s *config;
config = priv->lp503x_config;
regval = 0;
for (count = 0; count < 8; count++)
{
if (config->led_mode[count] == LP503X_LED_BANK_MODE_ENABLED)
{
regval |= (LP503X_LED0_BANK_ENABLE << count);
}
else
{
regval &= ~(LP503X_LED0_BANK_ENABLE << count);
}
}
ret = lp503x_i2c_write_reg(priv, LP503X_LED_CONFIG0, regval);
for (count = 8; count < 12; count++)
{
if (config->led_mode[count] == LP503X_LED_BANK_MODE_ENABLED)
{
regval |= (LP503X_LED0_BANK_ENABLE << (count - 8));
}
else
{
regval &= ~(LP503X_LED0_BANK_ENABLE << (count - 8));
}
}
ret = lp503x_i2c_write_reg(priv, LP503X_LED_CONFIG1, regval);
return ret;
}
/****************************************************************************
* Name: lp503x_set_rgbled_colour
*
* Description:
* sets RGB led to chosen html colour
*
****************************************************************************/
static int lp503x_set_rgbled_colour(struct lp503x_dev_s *priv,
int led, int colour)
{
int ret;
int regaddr;
if ((led > MAX_RGB_LEDS) || (colour > MAX_RGB_COLOUR))
{
ret = -EINVAL;
}
else
{
regaddr = LP503X_OUT0_COLOUR + (3*led);
ret = lp503x_i2c_write_reg(priv, regaddr++, (colour >> 16) & 0xff);
ret = lp503x_i2c_write_reg(priv, regaddr++, (colour >> 8) & 0xff);
ret = lp503x_i2c_write_reg(priv, regaddr, (colour >> 0) & 0xff);
ledinfo("INFO: RGB LED %d set to RGB colour %06x\n", led, colour);
}
return ret;
}
/****************************************************************************
* Name: lp503x_set_outcolour
*
* Description:
* Sets OUT brightness ("colour" of individual LED outputs
*
****************************************************************************/
static int lp503x_set_outcolour(struct lp503x_dev_s *priv, int led,
int brightness)
{
int ret;
if ((led > MAX_LEDS) || (brightness > MAX_BRIGHTNESS))
{
ret = -EINVAL;
}
else
{
ret = lp503x_i2c_write_reg(priv, LP503X_OUT0_COLOUR + led, brightness);
ledinfo("INFO: individual LED %d set to brightness %d\n", led,
brightness);
}
return ret;
}
/****************************************************************************
* Name: lp503x_set_rgbbrightness
*
* Description:
* Sets brightness of all RGB LED
*
****************************************************************************/
static int lp503x_set_rgbbrightness(struct lp503x_dev_s *priv, int led,
int brightness)
{
int ret;
if ((led > MAX_RGB_LEDS) || (brightness > MAX_BRIGHTNESS))
{
ret = -EINVAL;
}
else
{
ret = lp503x_i2c_write_reg(priv, LP503X_LED0_BRIGHTNESS + led,
brightness);
ledinfo("INFO: LED %d set to brightness %d\n", led, brightness);
}
return ret;
}
/****************************************************************************
* Name: lp503x_ioctl
*
* Description:
* This function is called whenever an ioctl call to a LP503X is
* performed.
*
****************************************************************************/
static int lp503x_ioctl(struct file *filep, int cmd,
unsigned long arg)
{
struct inode *inode = filep->f_inode;
struct lp503x_dev_s *priv = inode->i_private;
struct lp503x_config_s *config;
int ret;
const struct ioctl_arg_s *lp503x_ioctl_args = (struct ioctl_arg_s *)arg;
config = priv->lp503x_config;
ret = OK;
ledinfo("cmd: %d arg: %ld\n", cmd, arg);
switch (cmd)
{
case PWMIOC_ENABLE: /* arg is true or false */
config->enable_all_led_shutdown = lp503x_ioctl_args->param;
ret = lp503x_set_config(priv);
break;
case PWMIOC_RESET: /* no args */
lp503x_reset(priv);
break;
case PWMIOC_ENABLE_LED_BANK_MODE: /* led(0..11), mode required */
ledinfo("INFO: setting LED %d mode to %" PRIx32 "\n",
lp503x_ioctl_args->lednum,
lp503x_ioctl_args->param);
config->led_mode[lp503x_ioctl_args->lednum] =
lp503x_ioctl_args->param;
lp503x_set_bank_mode(priv);
break;
case PWMIOC_SET_BANK_MIX_COLOUR:/* bank(A/B/C),level(0-255) */
ledinfo("INFO: setting bank %c to brightness %" PRIx32 "\n",
lp503x_ioctl_args->lednum, lp503x_ioctl_args->param);
ret = lp503x_set_bank_colour(priv, lp503x_ioctl_args->lednum,
lp503x_ioctl_args->param);
break;
case PWMIOC_SET_BANK_BRIGHTNESS:
ledinfo("INFO: setting bank brightness to %" PRIx32 "\n",
lp503x_ioctl_args->param);
lp503x_set_bank_brightness(priv, lp503x_ioctl_args->param);
break;
case PWMIOC_CONFIG: /* config is struct within priv */
ledinfo("INFO: setting device config to:\n");
ledinfo("\tlog mode = %d\n", config->enable_log_mode);
ledinfo("\tpower save = %d\n", config->enable_power_save);
ledinfo("\tpwm dithering = %d\n", config->enable_pwm_dithering);
ledinfo("\tmax current = %s\n", (config->set_max_current_35ma)
? "30mA" : "25.5mA");
ledinfo("\tall leds shutdown = %d\n",
config->enable_all_led_shutdown);
ret = lp503x_set_config(priv);
break;
case PWMIOC_SET_LED_COLOUR: /* led(0..35), Colour(0..255) */
ledinfo("INFO: set LED %d to colour/brightness %" PRIx32 "\n",
lp503x_ioctl_args->lednum, lp503x_ioctl_args->param);
ret = lp503x_set_outcolour(priv, lp503x_ioctl_args->lednum,
lp503x_ioctl_args->param);
break;
case PWMIOC_SET_RGB_BRIGHTNESS: /* led(0..11), level(0..255) */
ledinfo("INFO: requested brightness level %d for led %" PRIx32 "\n",
lp503x_ioctl_args->lednum, lp503x_ioctl_args->param);
ret = lp503x_set_rgbbrightness(priv, lp503x_ioctl_args->lednum,
lp503x_ioctl_args->param);
break;
case PWMIOC_SET_RGB_COLOUR: /* led(0..11) */
ledinfo("requested led %d to be RGB colour = %" PRIx32 "\n",
lp503x_ioctl_args->lednum, lp503x_ioctl_args->param);
ret = lp503x_set_rgbled_colour(priv, lp503x_ioctl_args->lednum,
lp503x_ioctl_args->param);
break;
default: /* The used ioctl command was invalid */
lederr("ERROR: Unrecognized cmd: %d\n", cmd);
ret = -ENOTTY;
break;
}
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: lp503x_register
*
* Description:
* Register the LP503X device as 'devpath'
*
* Input Parameters:
* devpath - The full path to the driver to register. E.g., "/dev/leddrv0".
* i2c - An instance of the I2C interface to use to communicate
* with the LM92.
* lp503x_i2c_addr
* - The I2C address of the LP503X.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int lp503x_register(const char *devpath, struct i2c_master_s *i2c,
uint8_t const lp503x_i2c_addr, int const i2c_frequency)
{
int ret;
/* Sanity check */
DEBUGASSERT(devpath != NULL && i2c != NULL);
/* Initialize the LP503X device structure */
struct lp503x_dev_s *priv =
(struct lp503x_dev_s *)kmm_malloc(sizeof(struct lp503x_dev_s));
if (priv == NULL)
{
lederr("ERROR: Failed to allocate instance of lp503x_dev_s\n");
return -ENOMEM;
}
priv->i2c = i2c;
priv->i2c_addr = lp503x_i2c_addr;
priv->i2c_freq = i2c_frequency;
priv->state = LP503X_STATE_UNINIT;
/* Register the character driver */
ret = register_driver(devpath, &g_lp503x_fileops, 0222, priv);
if (ret != OK)
{
lederr("ERROR: Failed to register driver: %d\n", ret);
kmm_free(priv);
return ret;
}
else
{
ret = lp503x_reset(priv);
if (ret != OK)
{
lederr("ERROR: failed to reset lp503x device\n");
return ret;
}
priv->state = LP503X_STATE_RESET;
}
return OK;
}
#endif /* CONFIG_I2C && CONFIG_I2C_LP503X */

270
include/nuttx/leds/lp503x.h Normal file
View file

@ -0,0 +1,270 @@
/****************************************************************************
* include/nuttx/leds/lp503x.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_LEDS_LP503X_H
#define __INCLUDE_NUTTX_LEDS_LP503X_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/fs/ioctl.h>
/* Configuration
* CONFIG_I2C - Enables support for I2C drivers
* CONFIG_LP503X - Enables support for the LP503X driver
*/
#if defined(CONFIG_I2C) && defined(CONFIG_LP503X)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* I2C definitions */
#define MAX_LEDS 35
#define MAX_RGB_LEDS 11
#define MAX_BRIGHTNESS 255
#define MAX_RGB_COLOUR 0xffffff
#define LP503X_I2C_BUS_FREQ_HZ (380000)
/* LP503X Register Map */
#define LP503X_DEVICE_CONFIG0 0x00
#define LP503X_DEVICE_CONFIG1 0x01
#define LP503X_LED_CONFIG0 0x02
#define LP503X_LED_CONFIG1 0x03
#define LP503X_BANK_BRIGHTNESS 0x04
#define LP503X_BANK_A_COLOUR 0x05 /* All red LEDs */
#define LP503X_BANK_B_COLOUR 0x06 /* All green LEDs */
#define LP503X_BANK_C_COLOUR 0x07 /* All blue LEDs */
#define LP503X_LED0_BRIGHTNESS 0x08
#define LP503X_LED1_BRIGHTNESS 0x09
#define LP503X_LED2_BRIGHTNESS 0x0a
#define LP503X_LED3_BRIGHTNESS 0x0b
#define LP503X_LED4_BRIGHTNESS 0x0c
#define LP503X_LED5_BRIGHTNESS 0x0d
#define LP503X_LED6_BRIGHTNESS 0x0e
#define LP503X_LED7_BRIGHTNESS 0x0f
#define LP503X_LED8_BRIGHTNESS 0x10
#define LP503X_LED9_BRIGHTNESS 0x11
#define LP503X_LED10_BRIGHTNESS 0x12
#define LP503X_LED11_BRIGHTNESS 0x13
#define LP503X_OUT0_COLOUR 0x14
#define LP503X_OUT1_COLOUR 0x15
#define LP503X_OUT2_COLOUR 0x16
#define LP503X_OUT3_COLOUR 0x17
#define LP503X_OUT4_COLOUR 0x18
#define LP503X_OUT5_COLOUR 0x19
#define LP503X_OUT6_COLOUR 0x1a
#define LP503X_OUT7_COLOUR 0x1b
#define LP503X_OUT8_COLOUR 0x1c
#define LP503X_OUT9_COLOUR 0x1d
#define LP503X_OUT10_COLOUR 0x1e
#define LP503X_OUT11_COLOUR 0x1f
#define LP503X_OUT12_COLOUR 0x20
#define LP503X_OUT13_COLOUR 0x21
#define LP503X_OUT14_COLOUR 0x22
#define LP503X_OUT15_COLOUR 0x23
#define LP503X_OUT16_COLOUR 0x24
#define LP503X_OUT17_COLOUR 0x25
#define LP503X_OUT18_COLOUR 0x26
#define LP503X_OUT19_COLOUR 0x27
#define LP503X_OUT20_COLOUR 0x28
#define LP503X_OUT21_COLOUR 0x29
#define LP503X_OUT22_COLOUR 0x2a
#define LP503X_OUT23_COLOUR 0x2b
#define LP503X_OUT24_COLOUR 0x2c
#define LP503X_OUT25_COLOUR 0x2d
#define LP503X_OUT26_COLOUR 0x2e
#define LP503X_OUT27_COLOUR 0x2f
#define LP503X_OUT28_COLOUR 0x30
#define LP503X_OUT29_COLOUR 0x31
#define LP503X_OUT30_COLOUR 0x32
#define LP503X_OUT31_COLOUR 0x33
#define LP503X_OUT32_COLOUR 0x34
#define LP503X_OUT33_COLOUR 0x35
#define LP503X_OUT34_COLOUR 0x36
#define LP503X_OUT35_COLOUR 0x37
#define LP503X_RESET 0x38
/* LP503X Commands */
/* DEVICE_CONFIG0 */
#define LP503X_CHIP_ENABLE (0x01 << 6)
#define LP503X_CHIP_DISABLE 0
/* DEVICE_CONFIG1 */
#define LP503X_GLOBAL_OFF (0x01 << 0)
#define LP503X_MAX_CURRENT_OPTION (0x01 << 1)
#define LP503X_PWM_DITHERING_ENABLE (0x01 << 2)
#define LP503X_AUTO_INCR_ENABLE (0x01 << 3)
#define LP503X_POWER_SAVE_ENABLE (0x01 << 4)
#define LP503X_LOG_SCALE_ENABLE (0x01 << 5)
/* LED_CONFIG0 */
#define LP503X_LED_BANK_MODE_ENABLED 1
#define LP503X_LED_BANK_MODE_DISABLED 0
#define LP503X_LED0_BANK_ENABLE (0x01 << 0)
#define LP503X_LED1_BANK_ENABLE (0x01 << 1)
#define LP503X_LED2_BANK_ENABLE (0x01 << 2)
#define LP503X_LED3_BANK_ENABLE (0x01 << 3)
#define LP503X_LED4_BANK_ENABLE (0x01 << 4)
#define LP503X_LED5_BANK_ENABLE (0x01 << 5)
#define LP503X_LED6_BANK_ENABLE (0x01 << 6)
#define LP503X_LED7_BANK_ENABLE (0x01 << 7)
#define LP503X_ALL_LEDS_BANK_MODE0 0xff
/* LED_CONFIG1 */
#define LP503X_LED8_BANK_ENABLE (0x01 << 0)
#define LP503X_LED9_BANK_ENABLE (0x01 << 1)
#define LP503X_LED10_BANK_ENABLE (0x01 << 2)
#define LP503X_LED11_BANK_ENABLE (0x01 << 3)
#define LP503X_ALL_LEDS_BANK_MODE1 0x0f
/* RESET ALL REGISTERS */
#define LP503X_RESET_ALL_REGISTERS 0xff
#define LED_RED 0xff0000
#define LED_GREEN 0x00ff00
#define LED_BLUE 0x0000ff
#define LED_MAGENTA 0xff00ff
#define LED_YELLOW 0xffff33
#define LED_CYAN 0x00ffff
#define LED_WHITE 0xffffff
#define LED_ORANGE 0xffa500
/* LP503X_CONFIG1 bit definitions, disable=0, enable=1 */
#define LP503X_CONFIG1_LOG_SCALE (1 << 5) /* enable log scale not linear */
#define LP503X_CONFIG1_PWRSAVE (1 << 4) /* power save mode */
#define LP503X_CONFIG1_AUTOINC (1 << 3) /* register auto increment mode */
#define LP503X_CONFIG1_DITHERING (1 << 2) /* power saving mode */
#define LP503X_CONFIG1_MAX_CURRENT (1 << 1) /* responds to I2C subaddr1 */
#define LP503X_CONFIG1_GLOBAL_OFF (1 << 0) /* enable GLOGAL LEDs off */
/* IOCTL commands */
#define PWMIOC_ENABLE _PWMIOC(0) /* true/false */
#define PWMIOC_RESET _PWMIOC(1) /* no args */
#define PWMIOC_CONFIG _PWMIOC(2) /* lin/log
* pwm dither
* Imax
* Power Save */
#define PWMIOC_ENABLE_LED_BANK_MODE _PWMIOC(3) /* led(0..11) */
#define PWMIOC_SET_LED_COLOUR _PWMIOC(4) /* led(0..35), Colour(0..255)*/
#define PWMIOC_SET_RGB_COLOUR _PWMIOC(5) /* led(0..11), Colour HTML RGB*/
#define PWMIOC_SET_RGB_BRIGHTNESS _PWMIOC(6) /* led(0..11), level(0..255) */
#define PWMIOC_SET_BANK_MIX_COLOUR _PWMIOC(7) /* bank(A/B/C),level(0-255) */
#define PWMIOC_SET_BANK_BRIGHTNESS _PWMIOC(8) /* level(0-255) */
/****************************************************************************
* Public Types
****************************************************************************/
/* struct use to set device operating modes
* - log/lin scale
* - power save enable/disable
* - reg auto inc mode (set to FALSE (disable) for this driver
* - pwm dithering enable/disable
* - max current option
* - global LED shutdown control
*/
struct lp503x_config_s
{
bool enable_log_mode;
bool enable_power_save;
bool enable_auto_increment;
bool enable_pwm_dithering;
bool set_max_current_35ma;
bool enable_all_led_shutdown;
bool led_mode[12];
};
/* struct use for most/all ioctl calls */
struct ioctl_arg_s
{
uint8_t lednum;
uint32_t param;
};
/****************************************************************************
* Forward declarations
****************************************************************************/
struct i2c_master_s;
/****************************************************************************
* Public Types
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Name: lp503x_register
*
* Description:
* Register the LP503X device as 'devpath'
*
* Input Parameters:
* devpath - The full path to the driver to register. E.g., "/dev/leddrv0".
* i2c - An instance of the I2C interface to use to communicate
* with the LM92.
* lp503x_i2c_addr
* - The I2C address of the LP503X.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int lp503x_register(const char *devpath, struct i2c_master_s *i2c,
uint8_t const lp503x_i2c_addr, int const i2c_frequency);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* CONFIG_I2C && CONFIG_I2C_LP503X */
#endif /* __INCLUDE_NUTTX_LEDS_LP503X_H */