mirror of
https://github.com/brain-hackers/u-boot-brain
synced 2024-08-23 18:38:51 +09:00
![Tom Rini](/assets/img/avatar_default.png)
When U-Boot started using SPDX tags we were among the early adopters and there weren't a lot of other examples to borrow from. So we picked the area of the file that usually had a full license text and replaced it with an appropriate SPDX-License-Identifier: entry. Since then, the Linux Kernel has adopted SPDX tags and they place it as the very first line in a file (except where shebangs are used, then it's second line) and with slightly different comment styles than us. In part due to community overlap, in part due to better tag visibility and in part for other minor reasons, switch over to that style. This commit changes all instances where we have a single declared license in the tag as both the before and after are identical in tag contents. There's also a few places where I found we did not have a tag and have introduced one. Signed-off-by: Tom Rini <trini@konsulko.com>
171 lines
3.4 KiB
C
171 lines
3.4 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (C) 2015 Stefan Roese <sr@denx.de>
|
|
*/
|
|
|
|
#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 freq_last = -1;
|
|
static int mask_last = -1;
|
|
static int idx_last = -1;
|
|
static int mode_last;
|
|
|
|
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 or status_led.c
|
|
*/
|
|
void __led_init(led_id_t id, int state)
|
|
{
|
|
}
|
|
|
|
void __led_set(led_id_t mask, int state)
|
|
{
|
|
if (state == CONFIG_LED_STATUS_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 idx;
|
|
|
|
if ((freq == freq_last) || (mask == mask_last)) {
|
|
idx = idx_last;
|
|
mode = mode_last;
|
|
} else {
|
|
/* Toggle blink index */
|
|
if (idx_last == 0) {
|
|
idx = 1;
|
|
mode = PCA9551_LED_STATE_BLINK1;
|
|
} else {
|
|
idx = 0;
|
|
mode = PCA9551_LED_STATE_BLINK0;
|
|
}
|
|
|
|
idx_last = idx;
|
|
mode_last = mode;
|
|
}
|
|
freq_last = freq;
|
|
mask_last = mask;
|
|
|
|
rate.psc = ((freq * 38) / 1000) - 1;
|
|
rate.pwm = 128; /* 50% duty cycle */
|
|
|
|
pca9551_led_set_blink_rate(idx, rate);
|
|
pca9551_led_set_state(mask, mode);
|
|
}
|