incubator-nuttx/drivers/leds/lp503x.c

965 lines
29 KiB
C

/****************************************************************************
* 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 */
};
/****************************************************************************
* 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)
{
struct lp503x_dev_s *priv;
int ret;
/* Sanity check */
DEBUGASSERT(devpath != NULL && i2c != NULL);
/* Initialize the LP503X device structure */
priv = 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 */