mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
imx233: add small framework for LED
It handles GPIO and PWM based LEDs, possibly with several channels (red-green LED for example). The debug allows one to play with the setting. Currently the code supports the ZEN, ZEN X-Fi, and ZEN Mozaic. Change-Id: I8c3b66e6ba21778acdb123daabb724280a7d1a4f
This commit is contained in:
parent
759a78e5df
commit
b23b7088cb
6 changed files with 312 additions and 5 deletions
|
@ -587,6 +587,7 @@ target/arm/imx233/debug-imx233.c
|
||||||
#endif
|
#endif
|
||||||
#if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE)
|
#if !defined(BOOTLOADER) || defined(HAVE_BOOTLOADER_USB_MODE)
|
||||||
target/arm/imx233/usb-imx233.c
|
target/arm/imx233/usb-imx233.c
|
||||||
|
target/arm/imx233/led-imx233.c
|
||||||
#endif
|
#endif
|
||||||
#ifndef BOOTLOADER
|
#ifndef BOOTLOADER
|
||||||
#ifdef HAVE_IMX233_CODEC
|
#ifdef HAVE_IMX233_CODEC
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "button-imx233.h"
|
#include "button-imx233.h"
|
||||||
#include "sdmmc-imx233.h"
|
#include "sdmmc-imx233.h"
|
||||||
|
#include "led-imx233.h"
|
||||||
#include "storage.h"
|
#include "storage.h"
|
||||||
|
|
||||||
#include "regs/usbphy.h"
|
#include "regs/usbphy.h"
|
||||||
|
@ -792,6 +793,13 @@ bool dbg_hw_info_ocotp(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void get_pwm_freq_duty(int chan, int *freq, int *duty)
|
||||||
|
{
|
||||||
|
struct imx233_pwm_info_t info = imx233_pwm_get_info(chan);
|
||||||
|
*freq = imx233_clkctrl_get_freq(CLK_XTAL) * 1000 / info.cdiv / info.period;
|
||||||
|
*duty = (info.inactive - info.active) * 100 / info.period;
|
||||||
|
}
|
||||||
|
|
||||||
bool dbg_hw_info_pwm(void)
|
bool dbg_hw_info_pwm(void)
|
||||||
{
|
{
|
||||||
lcd_setfont(FONT_SYSFIXED);
|
lcd_setfont(FONT_SYSFIXED);
|
||||||
|
@ -833,14 +841,14 @@ bool dbg_hw_info_pwm(void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *prefix = "";
|
int freq, duty;
|
||||||
int freq = imx233_clkctrl_get_freq(CLK_XTAL) * 1000 / info.cdiv / info.period;
|
get_pwm_freq_duty(i, &freq, &duty);
|
||||||
|
const char *prefix = "";
|
||||||
if(freq > 1000)
|
if(freq > 1000)
|
||||||
{
|
{
|
||||||
prefix = "K";
|
prefix = "K";
|
||||||
freq /= 1000;
|
freq /= 1000;
|
||||||
}
|
}
|
||||||
int duty = (info.inactive - info.active) * 100 / info.period;
|
|
||||||
lcd_putsf(0, line++, "%d @%d %sHz, %d%% %c/%c", i, freq, prefix,
|
lcd_putsf(0, line++, "%d @%d %sHz, %d%% %c/%c", i, freq, prefix,
|
||||||
duty, info.active_state, info.inactive_state);
|
duty, info.active_state, info.inactive_state);
|
||||||
}
|
}
|
||||||
|
@ -1261,6 +1269,125 @@ bool dbg_hw_info_sdmmc(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *get_led_col(enum imx233_led_color_t col)
|
||||||
|
{
|
||||||
|
switch(col)
|
||||||
|
{
|
||||||
|
case LED_RED: return "red";
|
||||||
|
case LED_GREEN: return "green";
|
||||||
|
case LED_BLUE: return "blue";
|
||||||
|
default: return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dbg_hw_info_led(void)
|
||||||
|
{
|
||||||
|
lcd_setfont(FONT_SYSFIXED);
|
||||||
|
int cur_led = 0, cur_chan = 0;
|
||||||
|
bool nr_leds = imx233_led_get_count();
|
||||||
|
struct imx233_led_t *leds = imx233_led_get_info();
|
||||||
|
bool prev_pending = false;
|
||||||
|
bool next_pending = false;
|
||||||
|
bool editing = false;
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
int button = my_get_action(HZ / 10);
|
||||||
|
switch(button)
|
||||||
|
{
|
||||||
|
case ACT_NEXT:
|
||||||
|
if(nr_leds > 0 && !editing)
|
||||||
|
{
|
||||||
|
cur_chan++;
|
||||||
|
if(cur_chan == leds[cur_led].nr_chan)
|
||||||
|
{
|
||||||
|
cur_chan = 0;
|
||||||
|
cur_led = (cur_led + 1) % nr_leds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
next_pending = true;
|
||||||
|
break;
|
||||||
|
case ACT_PREV:
|
||||||
|
if(nr_leds > 0 && !editing)
|
||||||
|
{
|
||||||
|
cur_chan--;
|
||||||
|
if(cur_chan == -1)
|
||||||
|
{
|
||||||
|
cur_led = (cur_led + nr_leds - 1) % nr_leds;
|
||||||
|
cur_chan = leds[cur_led].nr_chan - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
prev_pending = true;
|
||||||
|
break;
|
||||||
|
case ACT_OK:
|
||||||
|
editing = !editing;
|
||||||
|
break;
|
||||||
|
case ACT_CANCEL:
|
||||||
|
lcd_setfont(FONT_UI);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lcd_clear_display();
|
||||||
|
int line = 0;
|
||||||
|
if(nr_leds == 0)
|
||||||
|
lcd_putsf(0, line++, "This device has no LED!");
|
||||||
|
for(int led = 0; led < imx233_led_get_count(); led++)
|
||||||
|
{
|
||||||
|
lcd_putsf(0, line++, "LED %d:", led);
|
||||||
|
for(int chan = 0; chan < leds[led].nr_chan; chan++)
|
||||||
|
{
|
||||||
|
/* read current configuration */
|
||||||
|
char buffer[64];
|
||||||
|
bool use_pwm = false;
|
||||||
|
int duty = 0, freq = 1;
|
||||||
|
bool on = false;
|
||||||
|
if(leds[led].chan[chan].has_pwm &&
|
||||||
|
imx233_pwm_is_enabled(leds[led].chan[chan].pwm_chan))
|
||||||
|
{
|
||||||
|
get_pwm_freq_duty(leds[led].chan[chan].pwm_chan, &freq, &duty);
|
||||||
|
/* assume active is high and inactive is low */
|
||||||
|
snprintf(buffer, sizeof(buffer), "%d Hz, %d%%", freq, duty);
|
||||||
|
use_pwm = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
on = imx233_pinctrl_get_gpio(leds[led].chan[chan].gpio_bank,
|
||||||
|
leds[led].chan[chan].gpio_pin);
|
||||||
|
snprintf(buffer, sizeof(buffer), "%s", on ? "on" : "off");
|
||||||
|
}
|
||||||
|
if(cur_led == led && cur_chan == chan)
|
||||||
|
lcd_set_foreground(editing ? LCD_RGBPACK(255, 0, 0) : LCD_RGBPACK(0, 0, 255));
|
||||||
|
lcd_putsf(0, line++, " %s: %s",
|
||||||
|
get_led_col(leds[led].chan[chan].color), buffer);
|
||||||
|
lcd_set_foreground(LCD_WHITE);
|
||||||
|
/* do edit */
|
||||||
|
if(cur_led != led || cur_chan != chan || !editing)
|
||||||
|
continue;
|
||||||
|
if(!next_pending && !prev_pending)
|
||||||
|
continue;
|
||||||
|
bool inc = next_pending;
|
||||||
|
next_pending = false;
|
||||||
|
prev_pending = false;
|
||||||
|
if(use_pwm)
|
||||||
|
{
|
||||||
|
duty += inc ? 10 : -10;
|
||||||
|
if(duty < 0)
|
||||||
|
duty = 0;
|
||||||
|
if(duty > 100)
|
||||||
|
duty = 100;
|
||||||
|
imx233_led_set_pwm(cur_led, cur_chan, freq, duty);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
imx233_led_set(cur_led, cur_chan, !on);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lcd_update();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_DUALBOOT_STUB
|
#ifdef HAVE_DUALBOOT_STUB
|
||||||
bool dbg_hw_info_dualboot(void)
|
bool dbg_hw_info_dualboot(void)
|
||||||
{
|
{
|
||||||
|
@ -1341,6 +1468,7 @@ static struct
|
||||||
{"timrot", dbg_hw_info_timrot},
|
{"timrot", dbg_hw_info_timrot},
|
||||||
{"button", dbg_hw_info_button},
|
{"button", dbg_hw_info_button},
|
||||||
{"sdmmc", dbg_hw_info_sdmmc},
|
{"sdmmc", dbg_hw_info_sdmmc},
|
||||||
|
{"led", dbg_hw_info_led},
|
||||||
#ifdef HAVE_DUALBOOT_STUB
|
#ifdef HAVE_DUALBOOT_STUB
|
||||||
{"dualboot", dbg_hw_info_dualboot},
|
{"dualboot", dbg_hw_info_dualboot},
|
||||||
#endif
|
#endif
|
||||||
|
|
100
firmware/target/arm/imx233/led-imx233.c
Normal file
100
firmware/target/arm/imx233/led-imx233.c
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 by Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include "led-imx233.h"
|
||||||
|
#include "pwm-imx233.h"
|
||||||
|
#include "pinctrl-imx233.h"
|
||||||
|
|
||||||
|
/** Target specific tables */
|
||||||
|
#if defined(CREATIVE_ZENXFI) || defined(CREATIVE_ZENMOZAIC)
|
||||||
|
/* ZEN X-Fi/Mozaic have a Red-Green LED */
|
||||||
|
static struct imx233_led_chan_t zenxfi_led_chans[] =
|
||||||
|
{
|
||||||
|
{ true, LED_RED, 2, 2, 2 }, /* red channel on B20P2 (pwm 2) */
|
||||||
|
{ true, LED_GREEN, 2, 4, 4 }, /* green channel on B20P4 (pwm 4) */
|
||||||
|
};
|
||||||
|
static struct imx233_led_t leds[] = {{2, zenxfi_led_chans}};
|
||||||
|
#elif defined(CREATIVE_ZEN)
|
||||||
|
/* ZEN has a blue LED */
|
||||||
|
static struct imx233_led_chan_t zen_led_chans[] =
|
||||||
|
{
|
||||||
|
{ true, LED_BLUE, 2, 3, 3 }, /* blue channel on B20P3 (pwm 3) */
|
||||||
|
};
|
||||||
|
static struct imx233_led_t leds[] = {{1, zen_led_chans}};
|
||||||
|
#else
|
||||||
|
#define NO_LEDS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NO_LEDS
|
||||||
|
int imx233_led_get_count(void)
|
||||||
|
{
|
||||||
|
return sizeof(leds) / sizeof(leds[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct imx233_led_t *imx233_led_get_info(void)
|
||||||
|
{
|
||||||
|
return leds;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int imx233_led_get_count(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct imx233_led_t * imx233_led_get_info(void)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void imx233_led_init(void)
|
||||||
|
{
|
||||||
|
struct imx233_led_t *leds = imx233_led_get_info();
|
||||||
|
/* turn off all channels */
|
||||||
|
for(int led = 0; led < imx233_led_get_count(); led++)
|
||||||
|
for(int chan = 0; chan < leds[led].nr_chan; chan++)
|
||||||
|
imx233_led_set(led, chan, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void imx233_led_set(int led, int chan, bool on)
|
||||||
|
{
|
||||||
|
struct imx233_led_chan_t *c = &imx233_led_get_info()[led].chan[chan];
|
||||||
|
/* if LED has a PWM, handle it using the PWM */
|
||||||
|
if(c->has_pwm)
|
||||||
|
{
|
||||||
|
/* toogle at 1KHz */
|
||||||
|
return imx233_led_set_pwm(led, chan, 1000, on ? 100 : 0);
|
||||||
|
}
|
||||||
|
/* make sure pin is configured as a GPIO */
|
||||||
|
imx233_pinctrl_setup_vpin(
|
||||||
|
VPIN_PACK(c->gpio_bank, c->gpio_pin, GPIO), "led",
|
||||||
|
PINCTRL_DRIVE_4mA, false);
|
||||||
|
imx233_pinctrl_enable_gpio(c->gpio_bank, c->gpio_pin, true);
|
||||||
|
imx233_pinctrl_set_gpio(c->gpio_bank, c->gpio_pin, on);
|
||||||
|
}
|
||||||
|
|
||||||
|
void imx233_led_set_pwm(int led, int chan, int freq, int duty)
|
||||||
|
{
|
||||||
|
struct imx233_led_chan_t *c = &imx233_led_get_info()[led].chan[chan];
|
||||||
|
if(!c->has_pwm)
|
||||||
|
panicf("led %d chan %d cannot do pwm", led, chan);
|
||||||
|
imx233_pwm_setup_simple(c->pwm_chan, freq, duty);
|
||||||
|
imx233_pwm_enable(c->pwm_chan, true);
|
||||||
|
}
|
69
firmware/target/arm/imx233/led-imx233.h
Normal file
69
firmware/target/arm/imx233/led-imx233.h
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 by Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef __LED_IMX233_H__
|
||||||
|
#define __LED_IMX233_H__
|
||||||
|
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
/** LED API
|
||||||
|
*
|
||||||
|
* The following assumes each single LED is controllable by one
|
||||||
|
* or more channels. Each channel is either controlled by a GPIO (on/off) or a
|
||||||
|
* PWM. Each channel also has a color, so it is possible to describe
|
||||||
|
* a red-green LED for example. */
|
||||||
|
|
||||||
|
/* LED channel color */
|
||||||
|
enum imx233_led_color_t
|
||||||
|
{
|
||||||
|
LED_RED,
|
||||||
|
LED_GREEN,
|
||||||
|
LED_BLUE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* LED channel */
|
||||||
|
struct imx233_led_chan_t
|
||||||
|
{
|
||||||
|
bool has_pwm; /* GPIO or PWM */
|
||||||
|
enum imx233_led_color_t color; /* color */
|
||||||
|
int gpio_bank, gpio_pin; /* GPIO bank and pin (also valid for PWM) */
|
||||||
|
int pwm_chan; /* for PWM: harware channel*/
|
||||||
|
};
|
||||||
|
|
||||||
|
/* LED */
|
||||||
|
struct imx233_led_t
|
||||||
|
{
|
||||||
|
int nr_chan; /* number of channels */
|
||||||
|
struct imx233_led_chan_t *chan; /* array of channels */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* init: all LEDs are turned off on init */
|
||||||
|
void imx233_led_init(void);
|
||||||
|
/* get number of LEDs */
|
||||||
|
int imx233_led_get_count(void);
|
||||||
|
/* return an array of LEDs */
|
||||||
|
struct imx233_led_t *imx233_led_get_info(void);
|
||||||
|
/* set LED channel on/off, it also works for PWM channel by setting the PWM to
|
||||||
|
* constantly off or constantly on */
|
||||||
|
void imx233_led_set(int led, int chan, bool on);
|
||||||
|
/* set LED PWM: control the frequency and the duty cycle percentage (0-100) */
|
||||||
|
void imx233_led_set_pwm(int led, int chan, int freq, int duty);
|
||||||
|
|
||||||
|
#endif /* __LED_IMX233_H__ */
|
|
@ -54,9 +54,18 @@ bool imx233_pwm_is_enabled(int channel)
|
||||||
void imx233_pwm_enable(int channel, bool enable)
|
void imx233_pwm_enable(int channel, bool enable)
|
||||||
{
|
{
|
||||||
if(enable)
|
if(enable)
|
||||||
|
{
|
||||||
|
/* claim pin */
|
||||||
|
imx233_pinctrl_setup_vpin(VPIN_PWM(channel), "pwm", PINCTRL_DRIVE_4mA, false);
|
||||||
BF_SET(PWM_CTRL, PWMx_ENABLE(channel));
|
BF_SET(PWM_CTRL, PWMx_ENABLE(channel));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
BF_CLR(PWM_CTRL, PWMx_ENABLE(channel));
|
BF_CLR(PWM_CTRL, PWMx_ENABLE(channel));
|
||||||
|
/* stop claiming the pin */
|
||||||
|
imx233_pinctrl_release(VPIN_UNPACK_BANK(VPIN_PWM(channel)),
|
||||||
|
VPIN_UNPACK_PIN(VPIN_PWM(channel)), "pwm");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void imx233_pwm_setup(int channel, int period, int cdiv, int active,
|
void imx233_pwm_setup(int channel, int period, int cdiv, int active,
|
||||||
|
@ -66,8 +75,6 @@ void imx233_pwm_setup(int channel, int period, int cdiv, int active,
|
||||||
bool enable = imx233_pwm_is_enabled(channel);
|
bool enable = imx233_pwm_is_enabled(channel);
|
||||||
if(enable)
|
if(enable)
|
||||||
imx233_pwm_enable(channel, false);
|
imx233_pwm_enable(channel, false);
|
||||||
/* setup pin */
|
|
||||||
imx233_pinctrl_setup_vpin(VPIN_PWM(channel), "pwm", PINCTRL_DRIVE_4mA, false);
|
|
||||||
/* watch the order ! active THEN period
|
/* watch the order ! active THEN period
|
||||||
* NOTE: the register value is period-1 */
|
* NOTE: the register value is period-1 */
|
||||||
BF_WR_ALL(PWM_ACTIVEn(channel), ACTIVE(active), INACTIVE(inactive));
|
BF_WR_ALL(PWM_ACTIVEn(channel), ACTIVE(active), INACTIVE(inactive));
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "button.h"
|
#include "button.h"
|
||||||
#include "fmradio_i2c.h"
|
#include "fmradio_i2c.h"
|
||||||
#include "powermgmt-imx233.h"
|
#include "powermgmt-imx233.h"
|
||||||
|
#include "led-imx233.h"
|
||||||
|
|
||||||
#include "regs/digctl.h"
|
#include "regs/digctl.h"
|
||||||
#include "regs/usbphy.h"
|
#include "regs/usbphy.h"
|
||||||
|
@ -202,6 +203,7 @@ void system_init(void)
|
||||||
imx233_power_init();
|
imx233_power_init();
|
||||||
imx233_i2c_init();
|
imx233_i2c_init();
|
||||||
imx233_powermgmt_init();
|
imx233_powermgmt_init();
|
||||||
|
imx233_led_init();
|
||||||
/* setup watchdog */
|
/* setup watchdog */
|
||||||
watchdog_init();
|
watchdog_init();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue