mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2025-12-10 07:44:50 +01:00
peripheral_manager: DG400 support, improved sx9512/shift register and exposed config options
This commit is contained in:
parent
fb4b3fd74a
commit
238aaa3ee5
22 changed files with 1907 additions and 543 deletions
|
|
@ -53,6 +53,7 @@ define Package/peripheral_manager/install
|
|||
|
||||
$(INSTALL_DIR) $(1)/sbin
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/peripheral_manager $(1)/sbin/
|
||||
$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/gpio_test $(1)/sbin/
|
||||
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/etc/init.d/* $(1)/etc/init.d/
|
||||
endef
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ peripheral_manager_SOURCES = \
|
|||
|
||||
if BRCM_BOARD
|
||||
|
||||
bin_PROGRAMS += vox_test
|
||||
bin_PROGRAMS += vox_test gpio_test
|
||||
|
||||
peripheral_manager_SOURCES += \
|
||||
src/gpio_led.c \
|
||||
|
|
@ -38,8 +38,12 @@ peripheral_manager_SOURCES += \
|
|||
src/gpio_button.h \
|
||||
src/gpio.c \
|
||||
src/gpio.h \
|
||||
src/gpio_shift_register.c \
|
||||
src/gpio_shift_register.h \
|
||||
src/touch_sx9512.c \
|
||||
src/touch_sx9512.h \
|
||||
src/sx9512.c \
|
||||
src/sx9512.h \
|
||||
src/vox.h \
|
||||
src/vox.c \
|
||||
src/prox_px3220.c
|
||||
|
|
@ -48,6 +52,20 @@ vox_test_SOURCES = \
|
|||
src/vox_test.c \
|
||||
src/gpio.c \
|
||||
src/gpio.h
|
||||
|
||||
gpio_test_SOURCES = \
|
||||
src/gpio_test.c \
|
||||
src/gpio.c \
|
||||
src/gpio.h \
|
||||
src/gpio_shift_register.c \
|
||||
src/gpio_shift_register.h \
|
||||
src/smbus.c \
|
||||
src/smbus.h \
|
||||
src/i2c.c \
|
||||
src/i2c.h \
|
||||
src/sx9512.c \
|
||||
src/sx9512.h
|
||||
|
||||
endif
|
||||
|
||||
peripheral_manager_LDADD = $(UCI_LIB) $(UBOX_LIB) $(UBUS_LIB) -lm
|
||||
|
|
|
|||
|
|
@ -8,6 +8,23 @@
|
|||
#include "touch_sx9512.h"
|
||||
#include "prox_px3220.h"
|
||||
|
||||
|
||||
static struct ubus_context *global_ubus_ctx;
|
||||
static struct blob_buf bblob;
|
||||
|
||||
|
||||
void button_ubus_interface_event(struct ubus_context *ubus_ctx, char *button, button_state_t pressed)
|
||||
{
|
||||
char s[UBUS_BUTTON_NAME_PREPEND_LEN+BUTTON_MAX_NAME_LEN];
|
||||
s[0]=0;
|
||||
strcat(s, UBUS_BUTTON_NAME_PREPEND);
|
||||
strcat(s, button);
|
||||
blob_buf_init(&bblob, 0);
|
||||
blobmsg_add_string(&bblob, "action", pressed ? "pressed" : "released");
|
||||
ubus_send_event(ubus_ctx, s, bblob.head);
|
||||
}
|
||||
|
||||
|
||||
/* used to map in the driver buttons to a function button */
|
||||
struct button_drv_list {
|
||||
struct list_head list;
|
||||
|
|
@ -21,6 +38,7 @@ struct function_button {
|
|||
char *name;
|
||||
int dimming;
|
||||
char *hotplug;
|
||||
char *hotplug_long;
|
||||
int minpress;
|
||||
int longpress; /* negative value means valid if mintime < time < abs(longpress ) */
|
||||
/* positive value means valid if time > longpreass */
|
||||
|
|
@ -40,20 +58,18 @@ static LIST_HEAD(drv_buttons_list);
|
|||
/* list containing all function buttons read from config file */
|
||||
static LIST_HEAD(buttons);
|
||||
|
||||
static struct button_drv *get_drv_button(char *name);
|
||||
//static struct function_button *get_button(char *name);
|
||||
|
||||
void button_add( struct button_drv *drv)
|
||||
{
|
||||
struct drv_button_list *drv_node = malloc(sizeof(struct drv_button_list));
|
||||
|
||||
DBG(1,"called with led name [%s]", drv->name);
|
||||
DBG(1,"called with button name [%s]", drv->name);
|
||||
drv_node->drv = drv;
|
||||
|
||||
list_add(&drv_node->list, &drv_buttons_list);
|
||||
}
|
||||
|
||||
static struct button_drv *get_drv_button(char *name)
|
||||
static struct button_drv *get_drv_button(const char *name)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &drv_buttons_list) {
|
||||
|
|
@ -65,7 +81,7 @@ static struct button_drv *get_drv_button(char *name)
|
|||
}
|
||||
|
||||
#if 0
|
||||
static struct function_button *get_button(char *name)
|
||||
static struct function_button *get_button(const char *name)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &buttons) {
|
||||
|
|
@ -77,6 +93,82 @@ static struct function_button *get_button(char *name)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
//! Read state for single button
|
||||
static button_state_t read_button_state(const char *name)
|
||||
{
|
||||
struct list_head *i;
|
||||
#ifdef HAVE_BOARD_H
|
||||
/* sx9512 driver needs to read out all buttons at once */
|
||||
/* so call it once at beginning of scanning inputs */
|
||||
sx9512_check();
|
||||
/* same for px3220 */
|
||||
px3220_check();
|
||||
#endif
|
||||
list_for_each(i, &buttons) {
|
||||
struct list_head *j;
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
if(!strcmp(node->name, name)) {
|
||||
button_state_t state=BUTTON_ERROR;
|
||||
list_for_each(j, &node->drv_list) {
|
||||
struct button_drv_list *drv_node = list_entry(j, struct button_drv_list, list);
|
||||
if(drv_node->drv) {
|
||||
if(drv_node->drv->func->get_state(drv_node->drv))
|
||||
return BUTTON_PRESSED;
|
||||
else
|
||||
state=BUTTON_RELEASED;
|
||||
}
|
||||
}
|
||||
return state;
|
||||
}
|
||||
}
|
||||
return BUTTON_ERROR;
|
||||
}
|
||||
|
||||
struct button_status {
|
||||
char name[BUTTON_MAX_NAME_LEN];
|
||||
button_state_t state;
|
||||
};
|
||||
|
||||
struct button_status_all {
|
||||
int n;
|
||||
struct button_status status[BUTTON_MAX];
|
||||
};
|
||||
|
||||
|
||||
//! Read states for all buttons
|
||||
static struct button_status_all * read_button_states(void)
|
||||
{
|
||||
static struct button_status_all p;
|
||||
p.n=0;
|
||||
struct list_head *i;
|
||||
#ifdef HAVE_BOARD_H
|
||||
/* sx9512 driver needs to read out all buttons at once */
|
||||
/* so call it once at beginning of scanning inputs */
|
||||
sx9512_check();
|
||||
/* same for px3220 */
|
||||
px3220_check();
|
||||
#endif
|
||||
list_for_each(i, &buttons) {
|
||||
struct list_head *j;
|
||||
button_state_t state=BUTTON_ERROR;
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
strcpy(p.status[p.n].name, node->name);
|
||||
list_for_each(j, &node->drv_list) {
|
||||
struct button_drv_list *drv_node = list_entry(j, struct button_drv_list, list);
|
||||
if(drv_node->drv) {
|
||||
if(drv_node->drv->func->get_state(drv_node->drv))
|
||||
state=BUTTON_PRESSED;
|
||||
else
|
||||
state=BUTTON_RELEASED;
|
||||
}
|
||||
}
|
||||
p.status[p.n].state = state;
|
||||
p.n++;
|
||||
}
|
||||
return &p;
|
||||
}
|
||||
|
||||
static void dump_drv_list(void)
|
||||
{
|
||||
struct list_head *i;
|
||||
|
|
@ -105,6 +197,32 @@ static void dump_buttons_list(void)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//! Run the hotplug command associated with function button
|
||||
//! @retval 0 ok
|
||||
static int button_hotplug_cmd(const char *name, bool longpress)
|
||||
{
|
||||
struct list_head *i;
|
||||
list_for_each(i, &buttons) {
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
if(!strcmp(node->name, name)) {
|
||||
char str[512];
|
||||
char *hotplug = node->hotplug;
|
||||
if(longpress && node->hotplug_long)
|
||||
hotplug = node->hotplug_long;
|
||||
if(!hotplug)
|
||||
return 1;
|
||||
DBG(1, "send key %s [%s] to system %s", node->name, hotplug, longpress ? "(longpress)" : "");
|
||||
snprintf(str, 512, "ACTION=register INTERFACE=%s /sbin/hotplug-call button &", hotplug);
|
||||
system(str);
|
||||
syslog(LOG_INFO, "%s",str);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int timer_started(struct button_drv_list *button_drv)
|
||||
{
|
||||
if (button_drv->pressed_time.tv_sec == 0 )
|
||||
|
|
@ -124,36 +242,26 @@ static void timer_stop(struct button_drv_list *button_drv)
|
|||
button_drv->pressed_time.tv_nsec = 0;
|
||||
}
|
||||
|
||||
static int timer_valid(struct button_drv_list *button_drv, int mtimeout, int longpress)
|
||||
|
||||
static button_press_type_t timer_valid(struct button_drv_list *button_drv, int mtimeout, int longpress)
|
||||
{
|
||||
struct timespec now;
|
||||
int sec;
|
||||
int nsec;
|
||||
int time_elapsed;
|
||||
|
||||
if (timer_started(button_drv)) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
sec = now.tv_sec - button_drv->pressed_time.tv_sec;
|
||||
nsec = now.tv_nsec - button_drv->pressed_time.tv_nsec;
|
||||
if ( mtimeout < (sec*1000 + nsec/1000000)) {
|
||||
if (longpress == 0)
|
||||
return 1;
|
||||
|
||||
if (longpress < 0) {
|
||||
longpress = -1 * longpress;
|
||||
if ( longpress > (sec*1000 + nsec/1000000)) {
|
||||
return 1;
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( longpress < (sec*1000 + nsec/1000000)) {
|
||||
return 1;
|
||||
}
|
||||
time_elapsed = sec*1000 + nsec/1000000;
|
||||
if ( mtimeout < time_elapsed) {
|
||||
if (longpress && (longpress < time_elapsed))
|
||||
return BUTTON_PRESS_LONG;
|
||||
return BUTTON_PRESS_SHORT;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return BUTTON_PRESS_NONE;
|
||||
}
|
||||
|
||||
#define BUTTON_TIMEOUT 100
|
||||
|
|
@ -163,6 +271,7 @@ static struct uloop_timeout button_inform_timer = { .cb = button_handler };
|
|||
static void button_handler(struct uloop_timeout *timeout)
|
||||
{
|
||||
struct list_head *i;
|
||||
int r;
|
||||
// DBG(1, "");
|
||||
|
||||
#ifdef HAVE_BOARD_H
|
||||
|
|
@ -186,37 +295,25 @@ static void button_handler(struct uloop_timeout *timeout)
|
|||
if (drv_node->drv) {
|
||||
button_state_t st = drv_node->drv->func->get_state(drv_node->drv);
|
||||
|
||||
if (st == PRESSED ) {
|
||||
if (st == BUTTON_PRESSED ) {
|
||||
if (! timer_started(drv_node)) {
|
||||
timer_start(drv_node);
|
||||
DBG(1, " %s pressed", drv_node->drv->name);
|
||||
button_ubus_interface_event(global_ubus_ctx, node->name, BUTTON_PRESSED);
|
||||
}
|
||||
|
||||
if ( timer_valid(drv_node, node->minpress, 0)) {
|
||||
led_pressindicator_set();
|
||||
}
|
||||
if(timer_valid(drv_node, node->minpress, 0))
|
||||
led_pressindicator_set();
|
||||
}
|
||||
|
||||
if (st == RELEASED ) {
|
||||
if (st == BUTTON_RELEASED ) {
|
||||
if (timer_started(drv_node)) {
|
||||
DBG(1, " %s released", drv_node->drv->name);
|
||||
|
||||
if ( timer_valid(drv_node, node->minpress, node->longpress) ) {
|
||||
char str[512];
|
||||
|
||||
if(node->dimming)
|
||||
led_dimming();
|
||||
|
||||
DBG(1, "send key %s [%s]to system", node->name, node->hotplug);
|
||||
snprintf(str,
|
||||
512,
|
||||
"ACTION=register INTERFACE=%s /sbin/hotplug-call button &",
|
||||
node->hotplug);
|
||||
system(str);
|
||||
syslog(LOG_INFO, "%s",str);
|
||||
} else {
|
||||
// DBG(1, " %s not valid", drv_node->drv->name);
|
||||
}
|
||||
if((r=timer_valid(drv_node, node->minpress, node->longpress))) {
|
||||
button_ubus_interface_event(global_ubus_ctx, node->name, BUTTON_RELEASED);
|
||||
if(node->dimming)
|
||||
led_dimming();
|
||||
button_hotplug_cmd(node->name, r==BUTTON_PRESS_LONG);
|
||||
}
|
||||
}
|
||||
timer_stop(drv_node);
|
||||
}
|
||||
|
|
@ -227,58 +324,103 @@ static void button_handler(struct uloop_timeout *timeout)
|
|||
uloop_timeout_set(&button_inform_timer, BUTTON_TIMEOUT);
|
||||
}
|
||||
|
||||
/* in order to support long press there is a need to go over every function button
|
||||
and find any driver button that is part of a longpress function.
|
||||
if found then the longpress time for that button needs to be filled in (but negative)
|
||||
on any other function button that has the same driver button. This to prevent two
|
||||
function buttons to trigger on one driver button release.
|
||||
*/
|
||||
|
||||
/* Find functions that use driver (drv) that has a zero longpress time and set it to time */
|
||||
static void longpress_set(int max_time,struct button_drv *drv) {
|
||||
struct list_head *i;
|
||||
list_for_each(i, &buttons) {
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
struct list_head *j;
|
||||
list_for_each(j, &node->drv_list) {
|
||||
struct button_drv_list *drv_node = list_entry(j, struct button_drv_list, list);
|
||||
if(drv_node->drv == drv){
|
||||
if (node->longpress == 0) {
|
||||
node->longpress = max_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* find any use of longpress and set all other to negative longpress time to indicate min max time
|
||||
for a valid press
|
||||
*/
|
||||
static void longpress_find(void) {
|
||||
struct list_head *i;
|
||||
list_for_each(i, &buttons) {
|
||||
struct function_button *node = list_entry(i, struct function_button, list);
|
||||
struct list_head *j;
|
||||
list_for_each(j, &node->drv_list) {
|
||||
struct button_drv_list *drv_node = list_entry(j, struct button_drv_list, list);
|
||||
if(drv_node->drv != NULL){
|
||||
if (node->longpress > 0) {
|
||||
DBG(1,"%13s drv button name = [%s]","",drv_node->drv->name);
|
||||
DBG(1,"%13s longpress = %d","",node->longpress);
|
||||
longpress_set(node->longpress * -1, drv_node->drv);
|
||||
}
|
||||
}
|
||||
}
|
||||
static int button_state_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
blob_buf_init(&bblob, 0);
|
||||
button_state_t state = read_button_state(obj->name+UBUS_BUTTON_NAME_PREPEND_LEN);
|
||||
switch(read_button_state(obj->name+UBUS_BUTTON_NAME_PREPEND_LEN)) {
|
||||
case BUTTON_RELEASED:
|
||||
blobmsg_add_string(&bblob, "state", "released");
|
||||
break;
|
||||
case BUTTON_PRESSED:
|
||||
blobmsg_add_string(&bblob, "state", "pressed");
|
||||
break;
|
||||
default:
|
||||
blobmsg_add_string(&bblob, "state", "error");
|
||||
}
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int button_press_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
button_hotplug_cmd(obj->name+UBUS_BUTTON_NAME_PREPEND_LEN, 0);
|
||||
blob_buf_init(&bblob, 0);
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int button_press_long_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
button_hotplug_cmd(obj->name+UBUS_BUTTON_NAME_PREPEND_LEN, 1);
|
||||
blob_buf_init(&bblob, 0);
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int buttons_state_method(struct ubus_context *ubus_ctx, struct ubus_object *obj,
|
||||
struct ubus_request_data *req, const char *method, struct blob_attr *msg)
|
||||
{
|
||||
int i;
|
||||
static struct button_status_all *p;
|
||||
p = read_button_states();
|
||||
blob_buf_init(&bblob, 0);
|
||||
for(i=0;i < p->n; i++) {
|
||||
switch(p->status[i].state) {
|
||||
case BUTTON_RELEASED:
|
||||
blobmsg_add_string(&bblob, p->status[i].name, "released");
|
||||
break;
|
||||
case BUTTON_PRESSED:
|
||||
blobmsg_add_string(&bblob, p->status[i].name, "pressed");
|
||||
break;
|
||||
default:
|
||||
blobmsg_add_string(&bblob, p->status[i].name, "error");
|
||||
}
|
||||
}
|
||||
ubus_send_reply(ubus_ctx, req, bblob.head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct ubus_method button_methods[] = {
|
||||
// { .name = "status", .handler = button_status_method },
|
||||
{ .name = "state", .handler = button_state_method },
|
||||
{ .name = "press", .handler = button_press_method },
|
||||
{ .name = "press_long", .handler = button_press_long_method },
|
||||
};
|
||||
|
||||
static struct ubus_object_type button_object_type = UBUS_OBJECT_TYPE("button", button_methods);
|
||||
|
||||
|
||||
static const struct ubus_method buttons_methods[] = {
|
||||
{ .name = "state", .handler = buttons_state_method },
|
||||
};
|
||||
|
||||
static struct ubus_object_type buttons_object_type = UBUS_OBJECT_TYPE("buttons", buttons_methods);
|
||||
|
||||
static struct ubus_object buttons_object = { .name = "buttons", .type = &buttons_object_type, .methods = buttons_methods, .n_methods = ARRAY_SIZE(buttons_methods), };
|
||||
|
||||
|
||||
void button_init( struct server_ctx *s_ctx)
|
||||
{
|
||||
struct ucilist *node;
|
||||
LIST_HEAD(buttonnames);
|
||||
int default_minpress = 0;
|
||||
char *s;
|
||||
int i,r;
|
||||
|
||||
global_ubus_ctx=s_ctx->ubus_ctx;
|
||||
|
||||
/* register buttons object with ubus */
|
||||
if((r=ubus_add_object(s_ctx->ubus_ctx, &buttons_object)))
|
||||
DBG(1,"Failed to add object: %s", ubus_strerror(r));
|
||||
|
||||
/* read out default global options */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , "button_map", "minpress");
|
||||
|
|
@ -328,6 +470,13 @@ void button_init( struct server_ctx *s_ctx)
|
|||
function->hotplug = s;
|
||||
}
|
||||
|
||||
/* read out hotplug option for longpress */
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw" , function->name, "hotplug_long");
|
||||
DBG(1, "hotplug_long = [%s]", s);
|
||||
if (s){
|
||||
function->hotplug_long = s;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&function->drv_list);
|
||||
|
||||
{
|
||||
|
|
@ -362,11 +511,23 @@ void button_init( struct server_ctx *s_ctx)
|
|||
}
|
||||
|
||||
list_add(&function->list, &buttons);
|
||||
|
||||
/* register each button with ubus */
|
||||
struct ubus_object *ubo;
|
||||
ubo = malloc(sizeof(struct ubus_object));
|
||||
memset(ubo, 0, sizeof(struct ubus_object));
|
||||
char name[UBUS_BUTTON_NAME_PREPEND_LEN+BUTTON_MAX_NAME_LEN];
|
||||
snprintf(name, UBUS_BUTTON_NAME_PREPEND_LEN+BUTTON_MAX_NAME_LEN, "%s%s", UBUS_BUTTON_NAME_PREPEND, node->val);
|
||||
ubo->name = strdup(name);
|
||||
ubo->methods = button_methods;
|
||||
ubo->n_methods = ARRAY_SIZE(button_methods);
|
||||
ubo->type = &button_object_type;
|
||||
if((r=ubus_add_object(s_ctx->ubus_ctx, ubo)))
|
||||
DBG(1,"Failed to add object: %s", ubus_strerror(r));
|
||||
}
|
||||
|
||||
uloop_timeout_set(&button_inform_timer, BUTTON_TIMEOUT);
|
||||
|
||||
longpress_find();
|
||||
dump_drv_list();
|
||||
dump_buttons_list();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,15 +2,27 @@
|
|||
#define BUTTON_H
|
||||
#include "server.h"
|
||||
|
||||
#define BUTTON_MAX 32
|
||||
#define BUTTON_MAX_NAME_LEN 16
|
||||
#define UBUS_BUTTON_NAME_PREPEND "button."
|
||||
#define UBUS_BUTTON_NAME_PREPEND_LEN sizeof(UBUS_BUTTON_NAME_PREPEND)
|
||||
|
||||
typedef enum {
|
||||
RELEASED,
|
||||
PRESSED,
|
||||
BUTTON_RELEASED,
|
||||
BUTTON_PRESSED,
|
||||
BUTTON_ERROR,
|
||||
} button_state_t;
|
||||
|
||||
typedef enum {
|
||||
BUTTON_PRESS_NONE,
|
||||
BUTTON_PRESS_SHORT,
|
||||
BUTTON_PRESS_LONG,
|
||||
} button_press_type_t;
|
||||
|
||||
struct button_drv;
|
||||
|
||||
struct button_drv_func {
|
||||
button_state_t (*get_state)(struct button_drv *); /* Get led state, on,off,flash ... */
|
||||
button_state_t (*get_state)(struct button_drv *); /* Get button state, on,off ... */
|
||||
};
|
||||
|
||||
struct button_drv {
|
||||
|
|
|
|||
|
|
@ -6,22 +6,24 @@
|
|||
#include "gpio.h"
|
||||
#include "log.h"
|
||||
|
||||
#define DEVFILE_BRCM_BOARD "/dev/brcmboard"
|
||||
|
||||
static int brcmboard = -1;
|
||||
|
||||
void gpio_open_ioctl( void ) {
|
||||
|
||||
int board_ioctl_init(void) {
|
||||
if (brcmboard == -1){
|
||||
brcmboard = open("/dev/brcmboard", O_RDWR);
|
||||
brcmboard = open(DEVFILE_BRCM_BOARD, O_RDWR);
|
||||
if ( brcmboard == -1 ) {
|
||||
DBG(1,"failed to open: /dev/brcmboard\n");
|
||||
return;
|
||||
syslog(LOG_ERR, "failed to open: %s", DEVFILE_BRCM_BOARD);
|
||||
return 1;
|
||||
}
|
||||
DBG(1, "fd %d allocated\n", brcmboard);
|
||||
}
|
||||
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int board_ioctl(int ioctl_id, int action, int hex, char* string_buf, int string_buf_len, int offset) {
|
||||
BOARD_IOCTL_PARMS IoctlParms = {0};
|
||||
|
||||
|
|
@ -32,8 +34,20 @@ int board_ioctl(int ioctl_id, int action, int hex, char* string_buf, int string_
|
|||
IoctlParms.buf = (char*)"";
|
||||
|
||||
if ( ioctl(brcmboard, ioctl_id, &IoctlParms) < 0 ) {
|
||||
syslog(LOG_INFO, "ioctl: %d failed", ioctl_id);
|
||||
exit(1);
|
||||
syslog(LOG_ERR, "ioctl: %d failed", ioctl_id);
|
||||
return(-255);
|
||||
}
|
||||
return IoctlParms.result;
|
||||
}
|
||||
|
||||
|
||||
gpio_state_t gpio_get_state(gpio_t gpio)
|
||||
{
|
||||
return board_ioctl(BOARD_IOCTL_GET_GPIO, 0, 0, NULL, gpio, 0);
|
||||
}
|
||||
|
||||
|
||||
void gpio_set_state(gpio_t gpio, gpio_state_t state)
|
||||
{
|
||||
board_ioctl(BOARD_IOCTL_SET_GPIO, 0, 0, NULL, gpio, state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,17 @@
|
|||
#include <sys/ioctl.h>
|
||||
#include <board.h>
|
||||
|
||||
void gpio_open_ioctl(void);
|
||||
typedef int gpio_t;
|
||||
|
||||
typedef enum {
|
||||
GPIO_STATE_LOW,
|
||||
GPIO_STATE_HIGH,
|
||||
} gpio_state_t;
|
||||
|
||||
int board_ioctl_init(void);
|
||||
int board_ioctl(int ioctl_id, int action, int hex, char* string_buf, int string_buf_len, int offset);
|
||||
#define gpio_init() board_ioctl_init()
|
||||
gpio_state_t gpio_get_state(gpio_t gpio);
|
||||
void gpio_set_state(gpio_t gpio, gpio_state_t state);
|
||||
|
||||
#endif /* GPIO_H */
|
||||
|
|
|
|||
|
|
@ -8,31 +8,31 @@
|
|||
|
||||
void gpio_button_init(struct server_ctx *s_ctx);
|
||||
|
||||
struct gpio_data {
|
||||
struct gpio_button_data {
|
||||
int addr;
|
||||
int active;
|
||||
int state;
|
||||
struct button_drv button;
|
||||
};
|
||||
|
||||
static button_state_t gpio_get_state(struct button_drv *drv)
|
||||
static button_state_t gpio_button_get_state(struct button_drv *drv)
|
||||
{
|
||||
// DBG(1, "state for %s", drv->name);
|
||||
struct gpio_data *p = (struct gpio_data *)drv->priv;
|
||||
struct gpio_button_data *p = (struct gpio_button_data *)drv->priv;
|
||||
int value;
|
||||
|
||||
value = board_ioctl( BOARD_IOCTL_GET_GPIO, 0, 0, NULL, p->addr, 0);
|
||||
|
||||
if(p->active)
|
||||
p->state = value ? PRESSED : RELEASED;
|
||||
p->state = !!value;
|
||||
else
|
||||
p->state = value ? RELEASED : PRESSED;
|
||||
p->state = !value;
|
||||
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static struct button_drv_func func = {
|
||||
.get_state = gpio_get_state,
|
||||
.get_state = gpio_button_get_state,
|
||||
};
|
||||
|
||||
void gpio_button_init(struct server_ctx *s_ctx) {
|
||||
|
|
@ -43,13 +43,13 @@ void gpio_button_init(struct server_ctx *s_ctx) {
|
|||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"gpio_buttons", "buttons", &buttons);
|
||||
list_for_each_entry(node, &buttons, list) {
|
||||
struct gpio_data *data;
|
||||
struct gpio_button_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct gpio_data));
|
||||
memset(data,0,sizeof(struct gpio_data));
|
||||
data = malloc(sizeof(struct gpio_button_data));
|
||||
memset(data,0,sizeof(struct gpio_button_data));
|
||||
|
||||
data->button.name = node->val;
|
||||
|
||||
|
|
@ -76,5 +76,5 @@ void gpio_button_init(struct server_ctx *s_ctx) {
|
|||
button_add(&data->button);
|
||||
}
|
||||
|
||||
gpio_open_ioctl();
|
||||
gpio_init();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,24 +9,26 @@
|
|||
#include "log.h"
|
||||
#include "server.h"
|
||||
#include "gpio.h"
|
||||
#include "gpio_shift_register.h"
|
||||
|
||||
gpio_shift_register_t led_gpio_shift_register;
|
||||
|
||||
void gpio_led_init(struct server_ctx *s_ctx);
|
||||
|
||||
typedef enum {
|
||||
UNKNOWN,
|
||||
LOW,
|
||||
HI,
|
||||
UNKNOWN,
|
||||
} active_t;
|
||||
|
||||
typedef enum {
|
||||
MODE_UNKNOWN,
|
||||
DIRECT,
|
||||
SHIFTREG2,
|
||||
SHIFTREG3,
|
||||
SHIFTREG_BRCM,
|
||||
SHIFTREG_GPIO,
|
||||
} gpio_mode_t;
|
||||
|
||||
struct gpio_data {
|
||||
struct gpio_led_data {
|
||||
int addr;
|
||||
active_t active;
|
||||
int state;
|
||||
|
|
@ -34,66 +36,30 @@ struct gpio_data {
|
|||
struct led_drv led;
|
||||
};
|
||||
|
||||
#define SR_MAX 16
|
||||
static int shift_register_state[SR_MAX];
|
||||
|
||||
static void shift_register3_set(int address, int bit_val) {
|
||||
int i;
|
||||
|
||||
if (address>=SR_MAX-1) {
|
||||
DBG(1,"address index %d too large\n", address);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update internal register copy
|
||||
shift_register_state[address] = bit_val;
|
||||
|
||||
// pull down shift register load (load gpio 23)
|
||||
board_ioctl(BOARD_IOCTL_SET_GPIO, 0, 0, NULL, 23, 0);
|
||||
|
||||
// clock in bits
|
||||
for (i=0 ; i<SR_MAX ; i++) {
|
||||
//set clock low
|
||||
board_ioctl( BOARD_IOCTL_SET_GPIO, 0, 0, NULL, 0, 0);
|
||||
//place bit on data line
|
||||
board_ioctl( BOARD_IOCTL_SET_GPIO, 0, 0, NULL, 1, shift_register_state[SR_MAX-1-i]);
|
||||
//set clock high
|
||||
board_ioctl( BOARD_IOCTL_SET_GPIO, 0, 0, NULL, 0, 1);
|
||||
}
|
||||
|
||||
// issue shift register load
|
||||
board_ioctl( BOARD_IOCTL_SET_GPIO, 0, 0, NULL, 23, 1);
|
||||
}
|
||||
|
||||
static int gpio_set_state(struct led_drv *drv, led_state_t state)
|
||||
static int gpio_led_set_state(struct led_drv *drv, led_state_t state)
|
||||
{
|
||||
struct gpio_data *p = (struct gpio_data *)drv->priv;
|
||||
struct gpio_led_data *p = (struct gpio_led_data *)drv->priv;
|
||||
int bit_val = 0;
|
||||
|
||||
if (state == OFF) {
|
||||
if (p->active == HI)
|
||||
bit_val = 0;
|
||||
else if (p->active == LOW)
|
||||
bit_val = 1;
|
||||
|
||||
}else if (state == ON) {
|
||||
if (p->active == HI)
|
||||
bit_val = 1;
|
||||
else if (p->active == LOW)
|
||||
bit_val = 0;
|
||||
if(state) {
|
||||
if(p->active)
|
||||
bit_val=1;
|
||||
} else {
|
||||
if(!p->active)
|
||||
bit_val=1;
|
||||
}
|
||||
|
||||
p->state = state;
|
||||
|
||||
switch (p->mode) {
|
||||
case DIRECT :
|
||||
case DIRECT:
|
||||
board_ioctl( BOARD_IOCTL_SET_GPIO, 0, 0, NULL, p->addr, bit_val);
|
||||
break;
|
||||
case SHIFTREG2:
|
||||
case SHIFTREG_BRCM:
|
||||
board_ioctl( BOARD_IOCTL_LED_CTRL, 0, 0, NULL, p->addr, bit_val);
|
||||
break;
|
||||
case SHIFTREG3:
|
||||
shift_register3_set(p->addr, bit_val);
|
||||
case SHIFTREG_GPIO:
|
||||
gpio_shift_register_cached_set(&led_gpio_shift_register, p->addr, bit_val);
|
||||
break;
|
||||
default:
|
||||
DBG(1,"access mode not supported [%d,%s]", p->mode, p->led.name);
|
||||
|
|
@ -102,35 +68,50 @@ static int gpio_set_state(struct led_drv *drv, led_state_t state)
|
|||
return p->state;
|
||||
}
|
||||
|
||||
static led_state_t gpio_get_state(struct led_drv *drv)
|
||||
static led_state_t gpio_led_get_state(struct led_drv *drv)
|
||||
{
|
||||
struct gpio_data *p = (struct gpio_data *)drv->priv;
|
||||
struct gpio_led_data *p = (struct gpio_led_data *)drv->priv;
|
||||
DBG(1, "state for %s", drv->name);
|
||||
|
||||
return p->state;
|
||||
}
|
||||
|
||||
static struct led_drv_func func = {
|
||||
.set_state = gpio_set_state,
|
||||
.get_state = gpio_get_state,
|
||||
.set_state = gpio_led_set_state,
|
||||
.get_state = gpio_led_get_state,
|
||||
};
|
||||
|
||||
void gpio_led_init(struct server_ctx *s_ctx) {
|
||||
|
||||
LIST_HEAD(leds);
|
||||
struct ucilist *node;
|
||||
int gpio_shiftreg_clk=0, gpio_shiftreg_dat=1, gpio_shiftreg_mask=2, gpio_shiftreg_bits=0;
|
||||
char *s;
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "gpio_shiftreg_clk")))
|
||||
gpio_shiftreg_clk = strtol(s,0,0);
|
||||
DBG(1, "gpio_shiftreg_clk = [%d]", gpio_shiftreg_clk);
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "gpio_shiftreg_dat")))
|
||||
gpio_shiftreg_dat = strtol(s,0,0);
|
||||
DBG(1, "gpio_shiftreg_dat = [%d]", gpio_shiftreg_dat);
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "gpio_shiftreg_mask")))
|
||||
gpio_shiftreg_mask = strtol(s,0,0);
|
||||
DBG(1, "gpio_shiftreg_mask = [%d]", gpio_shiftreg_mask);
|
||||
if((s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "gpio_shiftreg_bits")))
|
||||
gpio_shiftreg_bits = strtol(s,0,0);
|
||||
DBG(1, "gpio_shiftreg_bits = [%d]", gpio_shiftreg_bits);
|
||||
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw" ,"gpio_leds", "leds", &leds);
|
||||
list_for_each_entry(node,&leds,list){
|
||||
struct gpio_data *data;
|
||||
struct gpio_led_data *data;
|
||||
const char *s;
|
||||
|
||||
DBG(1, "value = [%s]",node->val);
|
||||
|
||||
data = malloc(sizeof(struct gpio_data));
|
||||
memset(data,0,sizeof(struct gpio_data));
|
||||
data = malloc(sizeof(struct gpio_led_data));
|
||||
memset(data,0,sizeof(struct gpio_led_data));
|
||||
|
||||
data->led.name = node->val;
|
||||
|
||||
|
|
@ -147,9 +128,9 @@ void gpio_led_init(struct server_ctx *s_ctx) {
|
|||
if (!strncasecmp("direct",s,3))
|
||||
data->mode = DIRECT;
|
||||
else if (!strncasecmp("sr",s,5))
|
||||
data->mode = SHIFTREG2;
|
||||
data->mode = SHIFTREG_BRCM;
|
||||
else if (!strncasecmp("csr",s,4))
|
||||
data->mode = SHIFTREG3;
|
||||
data->mode = SHIFTREG_GPIO;
|
||||
else
|
||||
DBG(1, "Mode %s : Not supported!", s);
|
||||
}
|
||||
|
|
@ -167,5 +148,6 @@ void gpio_led_init(struct server_ctx *s_ctx) {
|
|||
data->led.priv = data;
|
||||
led_add(&data->led);
|
||||
}
|
||||
gpio_open_ioctl();
|
||||
gpio_init();
|
||||
gpio_shift_register_init(&led_gpio_shift_register, gpio_shiftreg_clk, gpio_shiftreg_dat, gpio_shiftreg_mask, gpio_shiftreg_bits);
|
||||
}
|
||||
|
|
|
|||
48
peripheral_manager/src/src/gpio_shift_register.c
Normal file
48
peripheral_manager/src/src/gpio_shift_register.c
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#include "gpio_shift_register.h"
|
||||
#include <stdlib.h>
|
||||
#include "log.h"
|
||||
|
||||
int gpio_shift_register_init(gpio_shift_register_t *p, gpio_t gpio_clk, gpio_t gpio_dat, gpio_t gpio_mask, int size)
|
||||
{
|
||||
p->clk=gpio_clk;
|
||||
p->dat=gpio_dat;
|
||||
p->mask=gpio_mask;
|
||||
p->size=size;
|
||||
p->state_cache=0;
|
||||
gpio_set_state(p->clk, 0);
|
||||
gpio_set_state(p->dat, 0);
|
||||
gpio_set_state(p->mask, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gpio_shift_register_set(gpio_shift_register_t *p, int state)
|
||||
{
|
||||
int i;
|
||||
if(!p->size)
|
||||
return;
|
||||
gpio_set_state(p->mask, 0); //mask low
|
||||
for(i=p->size; i; i--) {
|
||||
gpio_set_state(p->clk, 0); //clk low
|
||||
gpio_set_state(p->dat, (state>>(i-1)) & 1); //place bit
|
||||
gpio_set_state(p->clk, 1); //clk high
|
||||
}
|
||||
gpio_set_state(p->mask, 1); //mask high / sreg load
|
||||
p->state_cache=state; //update internal register copy
|
||||
}
|
||||
|
||||
|
||||
void gpio_shift_register_cached_set(gpio_shift_register_t *p, shift_register_index_t index, gpio_state_t state)
|
||||
{
|
||||
if(!p->size)
|
||||
return;
|
||||
if(!(index < p->size)) {
|
||||
syslog(LOG_ERR, "index %d out of bounds", index);
|
||||
return;
|
||||
}
|
||||
//update internal register copy
|
||||
if(state)
|
||||
p->state_cache |= (1<<index);
|
||||
else
|
||||
p->state_cache &= ~(1<<index);
|
||||
gpio_shift_register_set(p, p->state_cache);
|
||||
}
|
||||
20
peripheral_manager/src/src/gpio_shift_register.h
Normal file
20
peripheral_manager/src/src/gpio_shift_register.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef GPIO_SHIFT_REGISTER_H
|
||||
#define GPIO_SHIFT_REGISTER_H
|
||||
|
||||
#include "gpio.h"
|
||||
|
||||
typedef int shift_register_index_t;
|
||||
|
||||
typedef struct {
|
||||
gpio_t clk;
|
||||
gpio_t dat;
|
||||
gpio_t mask;
|
||||
int size;
|
||||
int state_cache;
|
||||
} gpio_shift_register_t;
|
||||
|
||||
int gpio_shift_register_init(gpio_shift_register_t *p, gpio_t gpio_clk, gpio_t gpio_dat, gpio_t gpio_mask, int size);
|
||||
void gpio_shift_register_set(gpio_shift_register_t *p, int state);
|
||||
void gpio_shift_register_cached_set(gpio_shift_register_t *p, shift_register_index_t address, gpio_state_t bit_val);
|
||||
|
||||
#endif
|
||||
376
peripheral_manager/src/src/gpio_test.c
Executable file
376
peripheral_manager/src/src/gpio_test.c
Executable file
|
|
@ -0,0 +1,376 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
//#include <libgen.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <error.h>
|
||||
#include <errno.h>
|
||||
//#include <limits.h>
|
||||
//#include <sys/types.h>
|
||||
//#include <sys/stat.h>
|
||||
//#include <syslog.h>
|
||||
//#include <config.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include "smbus.h"
|
||||
#include "i2c.h"
|
||||
#include "log.h"
|
||||
#include "gpio.h"
|
||||
#include "gpio_shift_register.h"
|
||||
#include "sx9512.h"
|
||||
|
||||
#define DEV_I2C "/dev/i2c-0"
|
||||
|
||||
int verbose, debug_level;
|
||||
|
||||
|
||||
#define CMDS \
|
||||
X(NONE, "none", 0, 0, "", "") \
|
||||
X(GPIO_GET, "gpio_get", 1, 1, "Get pin state", "<pin>") \
|
||||
X(GPIO_SET, "gpio_set", 2, 2, "Set pin state", "<pin> <state>") \
|
||||
X(SH_SET, "sh_set", 5, 5, "Set shift register state", "<clk> <dat> <mask> <size> <state>") \
|
||||
X(SMBUS_READ, "smbus_read", 3, 3, "Read from I2C/SMBUS device", "<addr> <reg> <len>") \
|
||||
X(SMBUS_WRITE, "smbus_write", 3, 3, "Write to I2C/SMBUS device", "<addr> <reg> <hex_data>") \
|
||||
X(SX9512_BUTTON, "sx9512_button", 0, 0, "Read SX9512 buttons (endless loop)", "") \
|
||||
X(SX9512_READ, "sx9512_read", 0, 0, "Look at configuration data (compare to default)", "") \
|
||||
X(SX9512_INIT, "sx9512_init", 0, 1, "Init SX9512 config to device defaults", "[device]") \
|
||||
X(SX9512_NVM_LOAD, "sx9512_nvm_load", 0, 0, "SX9512 load values from NVM", "") \
|
||||
X(SX9512_NVM_STORE, "sx9512_nvm_store", 0, 0, "SX9512 store config to NVM", "") \
|
||||
X(SX9512_RESET, "sx9512_reset", 0, 0, "Send reset command to SX9512", "")
|
||||
|
||||
|
||||
#define X(id, str, min_arg, max_arg, desc, arg_desc) CMD_##id,
|
||||
enum { CMDS CMDS_AMOUNT } cmd;
|
||||
#undef X
|
||||
|
||||
struct cmd {
|
||||
const char *str;
|
||||
int min_arg, max_arg;
|
||||
const char *desc, *arg_desc;
|
||||
};
|
||||
|
||||
#define X(id, str, min_arg, max_arg, desc, arg_desc) { str, min_arg, max_arg, desc, arg_desc },
|
||||
const struct cmd cmd_data[] = { CMDS };
|
||||
#undef X
|
||||
|
||||
|
||||
#define SX9512_DEVCFGS \
|
||||
X(NONE, "none" ) \
|
||||
X(DEFAULT, "default") \
|
||||
X(CLEAR, "clear" ) \
|
||||
X(CG300, "cg300" ) \
|
||||
X(CG301, "cg301" ) \
|
||||
X(EG300, "eg300" ) \
|
||||
X(DG400, "dg400" )
|
||||
|
||||
#define X(a, b) SX9512_DEVCFG_##a,
|
||||
enum sx9512_devcfg { SX9512_DEVCFGS SX9512_DEVCFG_AMOUNT };
|
||||
#undef X
|
||||
|
||||
#define X(a, b) b,
|
||||
const char *sx9512_devcfg_str[] = { SX9512_DEVCFGS };
|
||||
#undef X
|
||||
|
||||
|
||||
static enum sx9512_devcfg sx9512_devcfg_str_to_id(const char *s)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i<SX9512_DEVCFG_AMOUNT; i++) {
|
||||
if(!strcmp(s, sx9512_devcfg_str[i]))
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void print_usage(char *prg_name)
|
||||
{
|
||||
int i;
|
||||
char tmp[64];
|
||||
printf("Usage: %s [options...] <cmd> <arg(s)>\n", prg_name);
|
||||
printf("Options:\n");
|
||||
printf(" -v, --verbose Verbose output\n");
|
||||
printf(" -h, --help Show this help screen.\n");
|
||||
printf("Commands:\n");
|
||||
for(i=0;i<CMDS_AMOUNT;i++) {
|
||||
sprintf(tmp, "%s %s", cmd_data[i].str, cmd_data[i].arg_desc);
|
||||
printf(" %-40.40s %s\n", tmp, cmd_data[i].desc);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, j, ch, r, fd=0;
|
||||
int pin, state;
|
||||
int pin_clk, pin_dat, pin_mask;
|
||||
gpio_shift_register_t p;
|
||||
int addr=0, s, n, l;
|
||||
enum sx9512_devcfg devcfg=0;
|
||||
uint8_t tmp[32];
|
||||
char *str_value=0, *eptr, str_hex[3];
|
||||
struct sx9512_reg_nvm nvm, nvm_def;
|
||||
while(1) {
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
ch = getopt_long(argc, argv, "vh", long_options, &option_index);
|
||||
if(ch == -1)
|
||||
break;
|
||||
switch (ch) {
|
||||
case 'v':
|
||||
verbose=1;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
//i=argc-optind;
|
||||
if((argc-optind)<1) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: need cmd");
|
||||
}
|
||||
for(i=0;i<CMDS_AMOUNT;i++) {
|
||||
if(!strcmp(argv[optind], cmd_data[i].str))
|
||||
cmd=i;
|
||||
}
|
||||
if(!cmd) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: bad cmd %s", argv[optind]);
|
||||
}
|
||||
optind++;
|
||||
if((argc-optind)<cmd_data[cmd].min_arg) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: too few arguments");
|
||||
}
|
||||
if((argc-optind)>cmd_data[cmd].max_arg) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: too many arguments");
|
||||
}
|
||||
switch(cmd) {
|
||||
case CMD_GPIO_GET:
|
||||
case CMD_GPIO_SET:
|
||||
case CMD_SH_SET:
|
||||
gpio_init();
|
||||
break;
|
||||
case CMD_SMBUS_READ:
|
||||
case CMD_SMBUS_WRITE:
|
||||
addr=strtol(argv[optind],NULL,16);
|
||||
optind++;
|
||||
if(verbose)
|
||||
printf("Open I2C device %s\n", DEV_I2C);
|
||||
fd = open(DEV_I2C, O_RDWR);
|
||||
if(fd < 0)
|
||||
error(-1, errno, "could not open %s", DEV_I2C);
|
||||
if(verbose)
|
||||
printf("Set I2C addr=%02x\n", addr);
|
||||
if(ioctl(fd, I2C_SLAVE, addr) < 0) {
|
||||
error(0, errno, "could not set address %x for i2c chip", addr);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case CMD_SX9512_BUTTON:
|
||||
case CMD_SX9512_READ:
|
||||
case CMD_SX9512_INIT:
|
||||
case CMD_SX9512_NVM_LOAD:
|
||||
case CMD_SX9512_NVM_STORE:
|
||||
case CMD_SX9512_RESET:
|
||||
if((fd=sx9512_init(DEV_I2C, SX9512_I2C_ADDRESS, NULL))<0)
|
||||
error(-1, errno, "could not init SX9512");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch(cmd) {
|
||||
case CMD_GPIO_GET:
|
||||
pin=strtol(argv[optind],0,0);
|
||||
if(verbose)
|
||||
printf("Get gpio %d state\n", pin);
|
||||
r=gpio_get_state(pin);
|
||||
if(verbose)
|
||||
printf("state=%d\n", r);
|
||||
return(r);
|
||||
case CMD_GPIO_SET:
|
||||
pin=strtol(argv[optind],0,0);
|
||||
optind++;
|
||||
state=strtol(argv[optind],0,0);
|
||||
if(state!=0 && state!=1) {
|
||||
print_usage(argv[0]);
|
||||
error(-1, errno, "Error: bad state %d", state);
|
||||
}
|
||||
if(verbose)
|
||||
printf("Set gpio %d state to %d\n", pin, state);
|
||||
gpio_set_state(pin, state);
|
||||
break;
|
||||
case CMD_SH_SET:
|
||||
pin_clk=strtol(argv[optind],NULL,0);
|
||||
optind++;
|
||||
pin_dat=strtol(argv[optind],NULL,0);
|
||||
optind++;
|
||||
pin_mask=strtol(argv[optind],NULL,0);
|
||||
optind++;
|
||||
s=strtol(argv[optind],NULL,0);
|
||||
optind++;
|
||||
state=strtol(argv[optind],NULL,16);
|
||||
if(verbose)
|
||||
printf("Set shift register (clk=%d, dat=%d, mask=%d, size=%d) state to %X\n", pin_clk, pin_dat, pin_mask, s, state);
|
||||
gpio_shift_register_init(&p, pin_clk, pin_dat, pin_mask, s);
|
||||
gpio_shift_register_set(&p, state);
|
||||
break;
|
||||
case CMD_SMBUS_READ:
|
||||
s=strtol(argv[optind],NULL,16);
|
||||
optind++;
|
||||
n=strtol(argv[optind],NULL,0);
|
||||
if(s+n>256)
|
||||
n=256-s;
|
||||
if(verbose)
|
||||
printf("smbus read start (addr=%02x, reg=%02x, len=%d)\n", addr, s, n);
|
||||
for(i=s; i<(s+n); i+=32) {
|
||||
l=n-(i-s);
|
||||
if(l>32)
|
||||
l=32;
|
||||
if(verbose)
|
||||
printf("smbus read (reg=%02x, len=%d)\n", i, l);
|
||||
r=i2c_smbus_read_i2c_block_data(fd, i, l, (__u8 *)&tmp);
|
||||
if(r<0) {
|
||||
error(0, errno, "I2C read error (%d)", r);
|
||||
close(fd);
|
||||
return(-1);
|
||||
}
|
||||
printf("%02X:", i/32);
|
||||
for(j=0; j<l; j++)
|
||||
printf("%02x", tmp[j]);
|
||||
printf("\n");
|
||||
}
|
||||
close(fd);
|
||||
if(n==1)
|
||||
return(tmp[0]);
|
||||
break;
|
||||
case CMD_SMBUS_WRITE:
|
||||
s=strtol(argv[optind],NULL,16);
|
||||
optind++;
|
||||
str_value = argv[optind];
|
||||
n=strlen(str_value);
|
||||
if(n%2)
|
||||
error(-1, errno, "Error: odd length hex value %s", str_value);
|
||||
n>>=1;
|
||||
if(s+n>256)
|
||||
n=256-s;
|
||||
if(verbose)
|
||||
printf("smbus write start (addr=%02x, reg=%02x, len=%d, val=%s)\n", addr, s, n, str_value);
|
||||
for(i=0; i<n; i+=32) {
|
||||
l=n-i;
|
||||
if(l>32)
|
||||
l=32;
|
||||
str_hex[2]=0;
|
||||
for(j=0; j<l; j++) {
|
||||
str_hex[0]=str_value[(i+j)<<1];
|
||||
str_hex[1]=str_value[((i+j)<<1)+1];
|
||||
tmp[j]=strtol(str_hex, &eptr,16);
|
||||
if((errno != 0 && tmp[j] == 0) || eptr==str_hex)
|
||||
error(-1, errno, "hex conversion error at %d (%s)", j, str_hex);
|
||||
}
|
||||
if(verbose)
|
||||
printf("smbus write (reg=%02x, len=%d, val=%.*s)\n", s+i, l, l*2, str_value+(i*2));
|
||||
r=i2c_smbus_write_i2c_block_data(fd, s+i, l, tmp);
|
||||
if(r<0) {
|
||||
error(0, errno, "I2C write error (%d)", r);
|
||||
close(fd);
|
||||
return(-1);
|
||||
}
|
||||
printf("%02X:", i/32);
|
||||
for(j=0; j<l; j++)
|
||||
printf("%02x ", tmp[j]);
|
||||
printf("\n");
|
||||
}
|
||||
close(fd);
|
||||
break;
|
||||
case CMD_SX9512_BUTTON:
|
||||
while(1) {
|
||||
if(verbose)
|
||||
printf("Start reading buttons from SX9512\n");
|
||||
struct sx9512_touch_state touch_state;
|
||||
if(sx9512_read_status_cached(fd, &touch_state))
|
||||
error(-1, errno, "I2C read error");
|
||||
//printf("[state %02X]\n", touch_state.state);
|
||||
if(touch_state.touched)
|
||||
printf("[touch %02X]\n", touch_state.touched);
|
||||
if(touch_state.released)
|
||||
printf("[release %02X]\n", touch_state.released);
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
}
|
||||
break;
|
||||
case CMD_SX9512_READ:
|
||||
if(verbose)
|
||||
printf("Read SX9512 registers (and compare to defaults)\n");
|
||||
sx9512_reg_nvm_init_defaults(&nvm_def, 0xff, 0xff);
|
||||
if(sx9512_reg_nvm_read(fd, &nvm))
|
||||
error(-1, errno, "while reading nvm registers");
|
||||
s=sizeof(nvm);
|
||||
for(i=0; i<s; i++)
|
||||
printf("%02x: %02x (%02x)0 %s\n", SX9512_REG_NVM_AREA_START+i, ((uint8_t *)&nvm)[i], ((uint8_t *)&nvm_def)[i], sx9512_reg_name(SX9512_REG_NVM_AREA_START+i));
|
||||
break;
|
||||
case CMD_SX9512_INIT:
|
||||
if((argc-optind)==1)
|
||||
devcfg = sx9512_devcfg_str_to_id(argv[optind]);
|
||||
switch(devcfg) {
|
||||
case SX9512_DEVCFG_DEFAULT:
|
||||
sx9512_reg_nvm_init_defaults(&nvm, 0xff, 0xff);
|
||||
break;
|
||||
case SX9512_DEVCFG_CLEAR:
|
||||
memset(&nvm, 0, sizeof(nvm));
|
||||
break;
|
||||
case SX9512_DEVCFG_CG300:
|
||||
sx9512_reg_nvm_init_cg300(&nvm);
|
||||
break;
|
||||
case SX9512_DEVCFG_CG301:
|
||||
sx9512_reg_nvm_init_cg301(&nvm);
|
||||
break;
|
||||
case SX9512_DEVCFG_EG300:
|
||||
sx9512_reg_nvm_init_eg300(&nvm);
|
||||
break;
|
||||
case SX9512_DEVCFG_DG400:
|
||||
sx9512_reg_nvm_init_dg400(&nvm);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Error: bad device arg, valid options are:\n");
|
||||
for(i=0;i<SX9512_DEVCFG_AMOUNT;i++)
|
||||
fprintf(stderr, "%s ", sx9512_devcfg_str[i]);
|
||||
fprintf(stderr, "\n");
|
||||
return -1;
|
||||
}
|
||||
if(verbose)
|
||||
printf("Init SX9512 registers to %s\n", sx9512_devcfg_str[devcfg]);
|
||||
if(sx9512_reg_nvm_write(fd, &nvm))
|
||||
error(-1, errno, "while writing nvm registers");
|
||||
break;
|
||||
case CMD_SX9512_NVM_LOAD:
|
||||
if(sx9512_reg_nvm_load(fd))
|
||||
error(-1, errno, "while loading nvm registers");
|
||||
break;
|
||||
case CMD_SX9512_NVM_STORE:
|
||||
if(sx9512_reg_nvm_store(fd))
|
||||
error(-1, errno, "while storing nvm registers");
|
||||
break;
|
||||
case CMD_SX9512_RESET:
|
||||
if(sx9512_reset(fd))
|
||||
error(-1, errno, "while trying to reset");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
fflush(stdout);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -26,32 +26,31 @@ void dump_i2c(int fd,int start,int stop)
|
|||
}
|
||||
}
|
||||
|
||||
int i2c_open_dev (const char *bus, int addr, unsigned long needed)
|
||||
int i2c_open_dev (const char *bus, int addr, unsigned long funcs_needed)
|
||||
{
|
||||
int fd = open(bus, O_RDWR);
|
||||
if (fd < 0) {
|
||||
syslog(LOG_INFO,"%s: could not open /dev/i2c-0\n",__func__);
|
||||
syslog(LOG_INFO,"%s: could not open %s\n",__func__, bus);
|
||||
return -1;
|
||||
}
|
||||
if (ioctl(fd, I2C_SLAVE, addr) < 0) {
|
||||
syslog(LOG_INFO,"%s: could not set address %x for i2c chip\n",
|
||||
__func__, addr);
|
||||
error:
|
||||
error:
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
if (needed) {
|
||||
if(funcs_needed) {
|
||||
unsigned long funcs;
|
||||
if (ioctl(fd, I2C_FUNCS, &funcs) < 0) {
|
||||
syslog(LOG_INFO,"%s: could not get I2C_FUNCS\n",__func__);
|
||||
goto error;
|
||||
}
|
||||
if ( (funcs & needed) != needed) {
|
||||
if((funcs & funcs_needed) != funcs_needed) {
|
||||
syslog(LOG_INFO,"%s: lacking I2C capabilities, have %lx, need %lx\n",
|
||||
__func__, funcs, needed);
|
||||
__func__, funcs, funcs_needed);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@
|
|||
#define I2C_H
|
||||
|
||||
void dump_i2c(int fd,int start,int stop);
|
||||
int i2c_open_dev (const char *bus, int addr, unsigned long needed);
|
||||
int i2c_open_dev (const char *bus, int addr, unsigned long functions_needed);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
struct i2c_reg_tab {
|
||||
char addr;
|
||||
char value;
|
||||
char range;
|
||||
char range; /* if set registers starting from addr to addr+range will be set to the same value */
|
||||
};
|
||||
|
||||
struct button_data {
|
||||
|
|
@ -61,7 +61,6 @@ static const struct i2c_reg_tab i2c_init_tab_vox25[]={
|
|||
int dev;
|
||||
int shadow_proximity;
|
||||
|
||||
|
||||
void do_init_tab(const struct i2c_reg_tab *tab, int len );
|
||||
|
||||
|
||||
|
|
@ -118,20 +117,18 @@ static button_state_t px3220_button_get_state(struct button_drv *drv)
|
|||
if (p->addr == 0 ){
|
||||
if (shadow_proximity & 1 ) {
|
||||
shadow_proximity &= ~0x1;
|
||||
p->state = PRESSED;
|
||||
return PRESSED;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
if (p->addr == 1 ){
|
||||
if (shadow_proximity & 2 ) {
|
||||
shadow_proximity &= ~0x2;
|
||||
p->state = PRESSED;
|
||||
return PRESSED;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
p->state = RELEASED;
|
||||
p->state = BUTTON_RELEASED;
|
||||
return p->state;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ void server_start(struct uci_context *uci_ctx, struct ubus_context *ubus_ctx)
|
|||
gpio_led_init(&server);
|
||||
gpio_button_init(&server);
|
||||
|
||||
sx9512_init(&server);
|
||||
sx9512_handler_init(&server);
|
||||
|
||||
px3220_init(&server);
|
||||
|
||||
|
|
|
|||
|
|
@ -75,10 +75,10 @@ static int sim_set_method(struct ubus_context *ubus_ctx, struct ubus_object *obj
|
|||
struct sim_data *p = (struct sim_data *)bt->priv;
|
||||
|
||||
if(!strcasecmp("pressed", (char *)blobmsg_data(tb[SIM_STATE]))){
|
||||
p->state = PRESSED;
|
||||
p->state = BUTTON_PRESSED;
|
||||
}
|
||||
if(!strcasecmp("released", (char *)blobmsg_data(tb[SIM_STATE]))){
|
||||
p->state = RELEASED;
|
||||
p->state = BUTTON_RELEASED;
|
||||
}
|
||||
}else
|
||||
DBG(1," button = %s not found",(char *)blobmsg_data(tb[SIM_NAME]));
|
||||
|
|
@ -104,7 +104,7 @@ static int sim_status_method(struct ubus_context *ubus_ctx, struct ubus_object *
|
|||
const char *state;
|
||||
struct sim_data *p = (struct sim_data *)node->drv->priv;
|
||||
|
||||
if(p->state == RELEASED)
|
||||
if(p->state == BUTTON_RELEASED)
|
||||
state = "Released";
|
||||
else
|
||||
state = "Pressed";
|
||||
|
|
|
|||
347
peripheral_manager/src/src/sx9512.c
Executable file
347
peripheral_manager/src/src/sx9512.c
Executable file
|
|
@ -0,0 +1,347 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <error.h>
|
||||
#include <errno.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include "sx9512.h"
|
||||
#include "smbus.h"
|
||||
#include "i2c.h"
|
||||
#include "gpio.h"
|
||||
|
||||
|
||||
#define X(name, reserved, default) { #name, reserved, default },
|
||||
const struct sx9512_reg_data sx9512_reg_data[] = { SX9512_REGS };
|
||||
#undef X
|
||||
|
||||
|
||||
//! init the sx9512 and optionally program the registers
|
||||
|
||||
//! @param addr I2C address (0=0x2c)
|
||||
//! @param nvm compare and if different program the registers and flash the NVM with these contents
|
||||
//! @return file descriptor for SX9512 I2C device
|
||||
//! @retval -1 error
|
||||
int sx9512_init(const char *dev, int addr, struct sx9512_reg_nvm *nvm)
|
||||
{
|
||||
int fd, i;
|
||||
struct sx9512_reg_nvm nvm_read;
|
||||
if(!addr)
|
||||
addr=SX9512_I2C_ADDRESS;
|
||||
if((fd=i2c_open_dev(dev, addr, I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE))<0)
|
||||
return -1;
|
||||
/*fd = open(dev, O_RDWR);
|
||||
if(fd < 0) {
|
||||
error(0, errno, "could not open %s", dev);
|
||||
return -1;
|
||||
}
|
||||
if(ioctl(fd, I2C_SLAVE, addr) < 0) {
|
||||
error(0, errno, "could not set address %x for i2c chip", SX9512_I2C_ADDRESS);
|
||||
close(fd);
|
||||
return -1;
|
||||
}*/
|
||||
if(nvm) {
|
||||
if(sx9512_reg_nvm_read(fd, &nvm_read)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
for(i=0;(unsigned int)i<sizeof(struct sx9512_reg_nvm);i++) {
|
||||
if(sx9512_reg_reserved(i+SX9512_REG_NVM_AREA_START))
|
||||
continue;
|
||||
if(((uint8_t *)nvm)[i] != ((uint8_t *)&nvm_read)[i]) {
|
||||
fprintf(stderr, "sx9512_init: register mismatch, setting default values and burning to NVM\n");
|
||||
if(sx9512_reg_nvm_write(fd, nvm)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
sx9512_reg_nvm_store(fd); //store to NVM
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
const char *sx9512_reg_name(sx9512_reg_t reg)
|
||||
{
|
||||
return sx9512_reg_data[reg].name;
|
||||
}
|
||||
|
||||
|
||||
//! SX9512 check if reg is reserved
|
||||
int sx9512_reg_reserved(sx9512_reg_t reg)
|
||||
{
|
||||
if(reg==SX9512_REG_I2C_SOFT_RESET)
|
||||
return 0;
|
||||
if(reg>=SX9512_REGS_AMOUNT)
|
||||
return 1;
|
||||
return sx9512_reg_data[reg].reserved;
|
||||
}
|
||||
|
||||
|
||||
//! send reset command
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reset(int fd)
|
||||
{
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_I2C_SOFT_RESET, 0xde)<0)
|
||||
return -1;
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_I2C_SOFT_RESET, 0x00)<0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! send reset command but retain LED values
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reset_restore_led_state(int fd)
|
||||
{
|
||||
int r;
|
||||
uint8_t p[4];
|
||||
if((r=i2c_smbus_read_i2c_block_data(fd, SX9512_REG_LED1_ON, 4, (__u8 *)&p))<0)
|
||||
return r;
|
||||
if(sx9512_reset(fd))
|
||||
return -1;
|
||||
if((r=i2c_smbus_write_i2c_block_data(fd, SX9512_REG_LED1_ON, 4, (__u8 *)&p))<0)
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! read interrupt reg
|
||||
|
||||
//! @retval -1 error
|
||||
int sx9512_read_interrupt(int fd)
|
||||
{
|
||||
int r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_IRQ_SRC))<0)
|
||||
return -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//! read touch reg
|
||||
|
||||
//! @retval -1 error
|
||||
int sx9512_read_buttons(int fd)
|
||||
{
|
||||
int r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_TOUCH_STATUS))<0)
|
||||
return -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//! read prox reg
|
||||
|
||||
//! @retval -1 error
|
||||
int sx9512_read_proximity(int fd)
|
||||
{
|
||||
int r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_PROX_STATUS))<0)
|
||||
return -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//! read status regs
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_read_status(int fd, struct sx9512_reg_status *status)
|
||||
{
|
||||
//REG_IRQ_SRC not working if using block read for some reason.
|
||||
//if(i2c_smbus_read_i2c_block_data(fd, SX9512_REG_IRQ_SRC, sizeof(struct sx9512_reg_status), (uint8_t *)status)<0)
|
||||
//return -1;
|
||||
int r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_IRQ_SRC))<0)
|
||||
return -1;
|
||||
((uint8_t *)status)[0]=r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_TOUCH_STATUS))<0)
|
||||
return -1;
|
||||
((uint8_t *)status)[1]=r;
|
||||
if((r=i2c_smbus_read_byte_data(fd, SX9512_REG_PROX_STATUS))<0)
|
||||
return -1;
|
||||
((uint8_t *)status)[2]=r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! read status cached
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_read_status_cached(int fd, struct sx9512_touch_state *touch_state)
|
||||
{
|
||||
static uint8_t last_state=0;
|
||||
struct sx9512_reg_status status;
|
||||
touch_state->touched=0;
|
||||
touch_state->released=0;
|
||||
if(sx9512_read_status(fd, &status))
|
||||
error(-1, errno, "I2C read error");
|
||||
touch_state->state=status.touch_status | !!((*(uint8_t *)&status.prox_status) & 0xc0);
|
||||
if(*(uint8_t *)&status.irq_src) {
|
||||
if(status.irq_src.touch || status.irq_src.prox_near)
|
||||
touch_state->touched = (last_state ^ touch_state->state) & touch_state->state;
|
||||
if(status.irq_src.release || status.irq_src.prox_far)
|
||||
touch_state->released = (last_state ^ touch_state->state) & last_state;
|
||||
}
|
||||
last_state=touch_state->state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! send cmd to load values from NVM to RAM
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reg_nvm_load(int fd)
|
||||
{
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_NVM_CTRL, 0x08)<0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! send cmd to store RAM to NVM
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reg_nvm_store(int fd)
|
||||
{
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_NVM_CTRL, 0x50)<0)
|
||||
return -1;
|
||||
if(i2c_smbus_write_byte_data(fd, SX9512_REG_NVM_CTRL, 0xa0)<0)
|
||||
return -1;
|
||||
//Wait 500ms then power off/on
|
||||
sleep(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! read whole NVM region
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reg_nvm_read(int fd, struct sx9512_reg_nvm *p)
|
||||
{
|
||||
int r, s, i, rl;
|
||||
s=sizeof(struct sx9512_reg_nvm);
|
||||
for(i=0; i<s; i+=32) {
|
||||
rl=s-i;
|
||||
if(rl>32)
|
||||
rl=32;
|
||||
if((r=i2c_smbus_read_i2c_block_data(fd, SX9512_REG_NVM_AREA_START+i, rl, (uint8_t *)p+i))<0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! write whole NVM region
|
||||
|
||||
//! @retval 0 ok
|
||||
int sx9512_reg_nvm_write(int fd, struct sx9512_reg_nvm *p)
|
||||
{
|
||||
int r, s, i, rl;
|
||||
s=sizeof(struct sx9512_reg_nvm);
|
||||
for(i=0; i<s; i+=32) {
|
||||
rl=s-i;
|
||||
if(rl>32)
|
||||
rl=32;
|
||||
if((r=i2c_smbus_write_i2c_block_data(fd, SX9512_REG_NVM_AREA_START+i, rl, (uint8_t *)p+i))<0)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//! init NVM struct
|
||||
void sx9512_reg_nvm_init(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
memset(p, 0, sizeof(struct sx9512_reg_nvm));
|
||||
p->cap_sense_op.set_to_0x14=0x14;
|
||||
}
|
||||
|
||||
|
||||
//! init NVM struct to defaults
|
||||
void sx9512_reg_nvm_init_defaults(struct sx9512_reg_nvm *p, uint8_t capsense_channels, uint8_t led_channels)
|
||||
{
|
||||
int i;
|
||||
sx9512_reg_nvm_init(p);
|
||||
p->irq_mask.touch=1;
|
||||
p->irq_mask.release=1;
|
||||
p->irq_mask.prox_near=1;
|
||||
p->irq_mask.prox_far=1;
|
||||
if(led_channels) {
|
||||
p->led_map[0]=0x00;
|
||||
p->led_map[1]=led_channels;
|
||||
p->led_pwm_freq=0x10;
|
||||
p->led_idle=0xff;
|
||||
p->led1_on=0xff;
|
||||
p->led2_on=0xff;
|
||||
p->led_pwr_idle=0xff;
|
||||
p->led_pwr_on=0xff;
|
||||
}
|
||||
p->cap_sense_enable=capsense_channels;
|
||||
for(i=0;i<SX9512_CHANNELS+1;i++) {
|
||||
p->cap_sense_range[i].ls_control=0x01;
|
||||
p->cap_sense_range[i].delta_cin_range=0x03;
|
||||
p->cap_sense_thresh[i]=0x04;
|
||||
}
|
||||
p->cap_sense_thresh[0]=0x02;
|
||||
p->cap_sense_op.auto_compensation=0;
|
||||
p->cap_sense_op.proximity_bl0=1;
|
||||
p->cap_sense_op.proximity_combined_channels=0;
|
||||
p->cap_sense_mode.raw_filter=0x03;
|
||||
p->cap_sense_mode.touch_reporting=1;
|
||||
p->cap_sense_mode.cap_sense_digital_gain=0;
|
||||
p->cap_sense_mode.cap_sense_report_mode=0;
|
||||
p->cap_sense_debounce.cap_sense_prox_near_debounce=0;
|
||||
p->cap_sense_debounce.cap_sense_prox_far_debounce=0;
|
||||
p->cap_sense_debounce.cap_sense_touch_debounce=0;
|
||||
p->cap_sense_debounce.cap_sense_release_debounce=1;
|
||||
p->cap_sense_neg_comp_thresh=0x80;
|
||||
p->cap_sense_pos_comp_thresh=0x80;
|
||||
p->cap_sense_pos_filt.cap_sense_prox_hyst=0;
|
||||
p->cap_sense_pos_filt.cap_sense_pos_comp_debounce=2;
|
||||
p->cap_sense_pos_filt.cap_sense_avg_pos_filt_coef=7;
|
||||
p->cap_sense_neg_filt.cap_sense_touch_hyst=0;
|
||||
p->cap_sense_neg_filt.cap_sense_neg_comp_debounce=2;
|
||||
p->cap_sense_neg_filt.cap_sense_avg_neg_filt_coef=5;
|
||||
p->spo_chan_map=0xff;
|
||||
}
|
||||
|
||||
|
||||
void sx9512_reg_nvm_init_cg300(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
int i;
|
||||
sx9512_reg_nvm_init_defaults(p, 0x0f, 0x3c);
|
||||
p->led_map[0]=0x01;
|
||||
p->led_map[1]=0x3c;
|
||||
for(i=0;i<SX9512_CHANNELS+1;i++) {
|
||||
p->cap_sense_range[i].delta_cin_range=0x01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sx9512_reg_nvm_init_cg301(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
int i;
|
||||
sx9512_reg_nvm_init_defaults(p, 0x3b, 0x7f);
|
||||
p->led_map[1]=0x7f;
|
||||
for(i=0;i<SX9512_CHANNELS+1;i++) {
|
||||
p->cap_sense_range[i].delta_cin_range=0x01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sx9512_reg_nvm_init_eg300(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
sx9512_reg_nvm_init_defaults(p, 0x0f, 0xff);
|
||||
}
|
||||
|
||||
|
||||
void sx9512_reg_nvm_init_dg400(struct sx9512_reg_nvm *p)
|
||||
{
|
||||
sx9512_reg_nvm_init_defaults(p, 0x3f, 0x00);
|
||||
}
|
||||
605
peripheral_manager/src/src/sx9512.h
Executable file
605
peripheral_manager/src/src/sx9512.h
Executable file
|
|
@ -0,0 +1,605 @@
|
|||
#ifndef _SX9512_H
|
||||
#define _SX9512_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define BIT_ORDER_BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#define SX9512_I2C_ADDRESS 0x2b
|
||||
#define SX9512B_I2C_ADDRESS 0x2d
|
||||
#define SX9512_CHANNELS 8
|
||||
|
||||
#define SX9512_REG_NVM_AREA_START 0x07
|
||||
#define SX9512_REG_NVM_AREA_END 0x62
|
||||
|
||||
#define SX9512_REG_I2C_SOFT_RESET 0xff
|
||||
|
||||
//Name, reserved, default value
|
||||
#define SX9512_REGS \
|
||||
X(IRQ_SRC, 0, 0x00) \
|
||||
X(TOUCH_STATUS, 0, 0x00) \
|
||||
X(PROX_STATUS, 0, 0x00) \
|
||||
X(COMP_STATUS, 0, 0x00) \
|
||||
X(NVM_CTRL, 0, 0x00) \
|
||||
X(R_05, 1, 0x00) \
|
||||
X(R_06, 1, 0x00) \
|
||||
X(SPO2_MODE, 0, 0x00) \
|
||||
X(PWR_KEY, 0, 0x00) \
|
||||
X(IRQ_MASK, 0, 0x00) \
|
||||
X(R_0A, 1, 0x00) \
|
||||
X(R_0B, 1, 0x00) \
|
||||
X(LED_MAP1, 0, 0x00) \
|
||||
X(LED_MAP2, 0, 0x00) \
|
||||
X(LED_PWM_FREQ, 0, 0x00) \
|
||||
X(LED_MODE, 0, 0x00) \
|
||||
X(LED_IDLE, 0, 0x00) \
|
||||
X(LED_OFF_DELAY, 0, 0x00) \
|
||||
X(LED1_ON, 0, 0x00) \
|
||||
X(LED1_FADE, 0, 0x00) \
|
||||
X(LED2_ON, 0, 0x00) \
|
||||
X(LED2_FADE, 0, 0x00) \
|
||||
X(LED_PWR_IDLE, 0, 0x00) \
|
||||
X(LED_PWR_ON, 0, 0x00) \
|
||||
X(LED_PWR_OFF, 0, 0x00) \
|
||||
X(LED_PWR_FADE, 0, 0x00) \
|
||||
X(LED_PWR_ON_PW, 0, 0x00) \
|
||||
X(LED_PWR_MODE, 0, 0x00) \
|
||||
X(R_1C, 1, 0x00) \
|
||||
X(R_1D, 1, 0x00) \
|
||||
X(CAP_SENSE_ENABLE, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE0, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE1, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE2, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE3, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE4, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE5, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE6, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE7, 0, 0x00) \
|
||||
X(CAP_SENSE_RANGE_ALL, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH0, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH1, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH2, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH3, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH4, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH5, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH6, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH7, 0, 0x00) \
|
||||
X(CAP_SENSE_THRESH_COMB, 0, 0x00) \
|
||||
X(CAP_SENSE_OP, 0, 0x00) \
|
||||
X(CAP_SENSE_MODE, 0, 0x00) \
|
||||
X(CAP_SENSE_DEBOUNCE, 0, 0x00) \
|
||||
X(CAP_SENSE_NEG_COMP_THRESH, 0, 0x00) \
|
||||
X(CAP_SENSE_POS_COMP_THRESH, 0, 0x00) \
|
||||
X(CAP_SENSE_POS_FILT, 0, 0x00) \
|
||||
X(CAP_SENSE_NEG_FILT, 0, 0x00) \
|
||||
X(CAP_SENSE_STUCK, 0, 0x00) \
|
||||
X(CAP_SENSE_FRAME_SKIP, 0, 0x00) \
|
||||
X(CAP_SENSE_MISC, 0, 0x00) \
|
||||
X(PROX_COMB_CHAN_MASK, 0, 0x00) \
|
||||
X(R_3C, 1, 0x00) \
|
||||
X(R_3D, 1, 0x00) \
|
||||
X(SPO_CHAN_MAP, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL0, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL1, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL2, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL3, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL4, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL5, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL6, 0, 0x00) \
|
||||
X(SPO_LEVEL_BL7, 0, 0x00) \
|
||||
X(SPO_LEVEL_IDLE, 0, 0x00) \
|
||||
X(SPO_LEVEL_PROX, 0, 0x00) \
|
||||
X(R_49, 1, 0x00) \
|
||||
X(R_4A, 1, 0x00) \
|
||||
X(BUZZER_TRIGGER, 0, 0x00) \
|
||||
X(BUZZER_FREQ, 0, 0x00) \
|
||||
X(R_4D, 1, 0x00) \
|
||||
X(R_4E, 1, 0x00) \
|
||||
X(R_4F, 1, 0x00) \
|
||||
X(R_50, 1, 0x00) \
|
||||
X(R_51, 1, 0x00) \
|
||||
X(R_52, 1, 0x00) \
|
||||
X(R_53, 1, 0x00) \
|
||||
X(R_54, 1, 0x00) \
|
||||
X(R_55, 1, 0x00) \
|
||||
X(R_56, 1, 0x00) \
|
||||
X(R_57, 1, 0x00) \
|
||||
X(R_58, 1, 0x00) \
|
||||
X(R_59, 1, 0x00) \
|
||||
X(R_5A, 1, 0x00) \
|
||||
X(R_5B, 1, 0x00) \
|
||||
X(R_5C, 1, 0x00) \
|
||||
X(R_5D, 1, 0x00) \
|
||||
X(R_5E, 1, 0x00) \
|
||||
X(R_5F, 1, 0x00) \
|
||||
X(R_60, 1, 0x00) \
|
||||
X(R_61, 1, 0x00) \
|
||||
X(CAP_SENSE_CHAN_SELECT, 0, 0x00) \
|
||||
X(CAP_SENSE_USEFUL_DATA_MSB, 0, 0x00) \
|
||||
X(CAP_SENSE_USEFUL_DATA_LSB, 0, 0x00) \
|
||||
X(CAP_SENSE_AVERAGE_DATA_MSB, 0, 0x00) \
|
||||
X(CAP_SENSE_AVERAGE_DATA_LSB, 0, 0x00) \
|
||||
X(CAP_SENSE_DIFF_DATA_MSB, 0, 0x00) \
|
||||
X(CAP_SENSE_DIFF_DATA_LSB, 0, 0x00) \
|
||||
X(CAP_SENSE_COMP_MSB, 0, 0x00) \
|
||||
X(CAP_SENSE_COMP_LSB, 0, 0x00)
|
||||
|
||||
|
||||
#define X(name, reserved, default) SX9512_REG_##name,
|
||||
typedef enum { SX9512_REGS SX9512_REGS_AMOUNT } sx9512_reg_t;
|
||||
#undef X
|
||||
|
||||
|
||||
struct sx9512_reg_data {
|
||||
const char *name;
|
||||
uint8_t reserved, default_value;
|
||||
};
|
||||
|
||||
|
||||
//! Interrupt source
|
||||
|
||||
//! The Irq Source register will indicate that the specified event has occurred since the last read of this register. If the
|
||||
//! NIRQ function is selected for SPO2 then it will indicate the occurrence of any of these events that are not masked
|
||||
//! out in register 0x09.
|
||||
//! The Irq mask in register 0x09 will prevent an Irq from being indicated by the NIRQ pin but it will not prevent the
|
||||
//! IRQ from being noted in this register.
|
||||
struct sx9512_reg_irq_src {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t reset:1;
|
||||
uint8_t touch:1;
|
||||
uint8_t release:1;
|
||||
uint8_t prox_near:1; //!< proximity on
|
||||
uint8_t prox_far:1; //!< proximity off
|
||||
uint8_t compensation_done:1; //!< write 1 to trigger compensation on all channels
|
||||
uint8_t conversion_done:1;
|
||||
uint8_t :1;
|
||||
#else
|
||||
uint8_t :1;
|
||||
uint8_t conversion_done:1;
|
||||
uint8_t compensation_done:1; //!< write 1 to trigger compensation on all channels
|
||||
uint8_t prox_far:1; //!< proximity off
|
||||
uint8_t prox_near:1; //!< proximity on
|
||||
uint8_t release:1;
|
||||
uint8_t touch:1;
|
||||
uint8_t reset:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! Proximity status
|
||||
struct sx9512_reg_prox_status {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t prox_bl0:1; //!< proximity detected on BL0
|
||||
uint8_t prox_multi:1; //!< proximity detected on combined channels
|
||||
uint8_t prox_multi_comp_pending:1; //!< compensation pending for combined channel prox sensing
|
||||
uint8_t :5;
|
||||
#else
|
||||
uint8_t :5;
|
||||
uint8_t prox_multi_comp_pending:1; //!< compensation pending for combined channel prox sensing
|
||||
uint8_t prox_multi:1; //!< proximity detected on combined channels
|
||||
uint8_t prox_bl0:1; //!< proximity detected on BL0
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! NVM Control
|
||||
|
||||
//! The NVM Area field indicates which of the user NVM areas are currently programmed and active (1, 2 or 3). The
|
||||
//! NVM Read bit gives the ability to manually request that the contents of the NVM be transferred to the registers
|
||||
//! and NVM Burn field gives the ability to burn the current registers to the next available NVM area.
|
||||
//! Normally, the transfer of data from the NVM to the registers is done automatically on power up and upon a reset
|
||||
//! but occasionally a user might want to force a read manually.
|
||||
//! Registers 0x07 through 0x62 are stored to NVM and loaded from NVM.
|
||||
//! After writing 0xA0 (ie NVM burn), wait for at least 500ms and then power off-on the IC for changes to be effective.
|
||||
//! Caution, there are only three user areas and attempts to burn values beyond user area 3 will be ignored.
|
||||
struct sx9512_reg_nvm_ctrl {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t nvm_burn:4; //!< write 0x50 followed by 0xA0 to initiate transfer of reg 0x07-0x62 to NVM
|
||||
uint8_t nvm_read:1; //!< trigger NVM read to registers
|
||||
uint8_t nvm_area:3; //!< indicates current active NVM area
|
||||
#else
|
||||
uint8_t nvm_area:3; //!< indicates current active NVM area
|
||||
uint8_t nvm_read:1; //!< trigger NVM read to registers
|
||||
uint8_t nvm_burn:4; //!< write 0x50 followed by 0xA0 to initiate transfer of reg 0x07-0x62 to NVM
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! SPO2 Mode Control
|
||||
|
||||
//! The SPO2 Config field will specify the functionality of the SPO pin. When selected as NIRQ, the open drain output
|
||||
//! will go low whenever a non-masked Irq occurs and the NIRQ will go back high after a register 0x00 is read over
|
||||
//! the I2C. When selected as Buzzer, the SPO2 pin will drive a 2 phase 2 frequency signal onto an external buzzer
|
||||
//! for each specified event (see Buzzer section). When selected as SPO2, pin operates as an analog output similar
|
||||
//! to SPO1 (see SPO section). If selected as TV power state, the pin is driven from the system PMIC with a high
|
||||
//! (SPO2 = SVDD) indicating that the system power is on and a low (SPO2 = GND) when the system power is off.
|
||||
//! The TV Power State bit reads back the current state of SPO2 if SPO2 is selected for TV power state, otherwise
|
||||
//! the system should write to this bit to indicate the current system power state. The SX9512/12B/13/13B needs to
|
||||
//! know the current state in able to correctly process some of the LED modes for the Power Button (see LED
|
||||
//! modes).
|
||||
struct sx9512_reg_spo2_mode {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t :1;
|
||||
uint8_t spo2_config:2; //!< set function of SPO2 pin
|
||||
uint8_t tv_power_state:1; //!< if SPO2 set to TV power state input then TV power state indicated by this bit.
|
||||
uint8_t :4;
|
||||
#else
|
||||
uint8_t :4;
|
||||
uint8_t tv_power_state:1; //!< if SPO2 set to TV power state input then TV power state indicated by this bit.
|
||||
uint8_t spo2_config:2; //!< set function of SPO2 pin
|
||||
uint8_t :1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! Interrupt Request Mask
|
||||
|
||||
//! Set which Irqs will trigger an NIRQ (if enabled on SPO2) and report in reg 0x00
|
||||
//! 0=Disable IRQ
|
||||
//! 1=Enable IRQ
|
||||
struct sx9512_reg_irq_mask {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t reset:1;
|
||||
uint8_t touch:1;
|
||||
uint8_t release:1;
|
||||
uint8_t prox_near:1; //!< proximity on
|
||||
uint8_t prox_far:1; //!< proximity off
|
||||
uint8_t compensation_done:1;
|
||||
uint8_t :2;
|
||||
#else
|
||||
uint8_t :2;
|
||||
uint8_t compensation_done:1;
|
||||
uint8_t prox_far:1; //!< proximity off
|
||||
uint8_t prox_near:1; //!< proximity on
|
||||
uint8_t release:1;
|
||||
uint8_t touch:1;
|
||||
uint8_t reset:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! LED Mode
|
||||
struct sx9512_reg_led_mode {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t led_fade_repeat:4;
|
||||
uint8_t :1;
|
||||
uint8_t led_fading:1;
|
||||
uint8_t led_mode:2;
|
||||
#else
|
||||
uint8_t led_mode:2;
|
||||
uint8_t led_fading:1;
|
||||
uint8_t :1;
|
||||
uint8_t led_fade_repeat:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! LED off delay
|
||||
struct sx9512_reg_led_off_delay {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t led_engine1_delay_off_time:4;
|
||||
uint8_t led_engine2_delay_off_time:4;
|
||||
#else
|
||||
uint8_t led_engine2_delay_off_time:4;
|
||||
uint8_t led_engine1_delay_off_time:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! LED Engine fade in/out timing
|
||||
struct sx9512_reg_led_fade {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t led_engine_fade_in_time:4;
|
||||
uint8_t led_engine_fade_out_time:4;
|
||||
#else
|
||||
uint8_t led_engine_fade_out_time:4;
|
||||
uint8_t led_engine_fade_in_time:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! LED power button mode
|
||||
struct sx9512_reg_led_pwr_mode {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t power_led_off_mode:1;
|
||||
uint8_t power_led_max_level:1;
|
||||
uint8_t power_led_breath_max:1;
|
||||
uint8_t power_led_waveform:1;
|
||||
uint8_t :2;
|
||||
uint8_t power_button_enable:1;
|
||||
uint8_t led_touch_poarity_invert:1;
|
||||
#else
|
||||
uint8_t led_touch_poarity_invert:1;
|
||||
uint8_t power_button_enable:1;
|
||||
uint8_t :2;
|
||||
uint8_t power_led_waveform:1;
|
||||
uint8_t power_led_breath_max:1;
|
||||
uint8_t power_led_max_level:1;
|
||||
uint8_t power_led_off_mode:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense delta Cin range and LS control
|
||||
struct sx9512_reg_cap_sense_range {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t ls_control:2;
|
||||
uint8_t :4;
|
||||
uint8_t delta_cin_range:2;
|
||||
#else
|
||||
uint8_t delta_cin_range:2;
|
||||
uint8_t :4;
|
||||
uint8_t ls_control:2;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense auto compensation, proximity on BL0 and combined channel proximity
|
||||
struct sx9512_reg_cap_sense_op {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t auto_compensation:1;
|
||||
uint8_t proximity_bl0:1;
|
||||
uint8_t proximity_combined_channels:1;
|
||||
uint8_t set_to_0x14:5;
|
||||
#else
|
||||
uint8_t set_to_0x14:5;
|
||||
uint8_t proximity_combined_channels:1;
|
||||
uint8_t proximity_bl0:1;
|
||||
uint8_t auto_compensation:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense raw data filter coef, digital gain, I2C touch reporting and CapSense
|
||||
struct sx9512_reg_cap_sense_mode {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t raw_filter:3;
|
||||
uint8_t touch_reporting:1;
|
||||
uint8_t cap_sense_digital_gain:2;
|
||||
uint8_t cap_sense_report_mode:2;
|
||||
#else
|
||||
uint8_t cap_sense_report_mode:2;
|
||||
uint8_t cap_sense_digital_gain:2;
|
||||
uint8_t touch_reporting:1;
|
||||
uint8_t raw_filter:3;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense debounce
|
||||
struct sx9512_reg_cap_sense_debounce {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_prox_near_debounce:2;
|
||||
uint8_t cap_sense_prox_far_debounce:2;
|
||||
uint8_t cap_sense_touch_debounce:2;
|
||||
uint8_t cap_sense_release_debounce:2;
|
||||
#else
|
||||
uint8_t cap_sense_release_debounce:2;
|
||||
uint8_t cap_sense_touch_debounce:2;
|
||||
uint8_t cap_sense_prox_far_debounce:2;
|
||||
uint8_t cap_sense_prox_near_debounce:2;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense positive filter coef, positive auto compensation debounce and proximity hyst
|
||||
struct sx9512_reg_cap_sense_pos_filt {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_prox_hyst:3;
|
||||
uint8_t cap_sense_pos_comp_debounce:2;
|
||||
uint8_t cap_sense_avg_pos_filt_coef:3;
|
||||
#else
|
||||
uint8_t cap_sense_avg_pos_filt_coef:3;
|
||||
uint8_t cap_sense_pos_comp_debounce:2;
|
||||
uint8_t cap_sense_prox_hyst:3;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense negative filter coef, negative auto compensation debounce and touch hyst
|
||||
struct sx9512_reg_cap_sense_neg_filt {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_touch_hyst:3;
|
||||
uint8_t cap_sense_neg_comp_debounce:2;
|
||||
uint8_t cap_sense_avg_neg_filt_coef:3;
|
||||
#else
|
||||
uint8_t cap_sense_avg_neg_filt_coef:3;
|
||||
uint8_t cap_sense_neg_comp_debounce:2;
|
||||
uint8_t cap_sense_touch_hyst:3;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense stuck-at timer and periodic compensation timer
|
||||
struct sx9512_reg_cap_sense_stuck {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_stuck_at_timer:4;
|
||||
uint8_t cap_sense_periodic_comp:4;
|
||||
#else
|
||||
uint8_t cap_sense_periodic_comp:4;
|
||||
uint8_t cap_sense_stuck_at_timer:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense frame skip setting from active and sleep
|
||||
struct sx9512_reg_cap_sense_frame_skip {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t cap_sense_active_frame_skip:4;
|
||||
uint8_t cap_sense_sleep_frame_skip:4;
|
||||
#else
|
||||
uint8_t cap_sense_sleep_frame_skip:4;
|
||||
uint8_t cap_sense_active_frame_skip:4;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! CapSense sleep enable, auto compensation channels threshold, inactive BL control
|
||||
struct sx9512_reg_cap_sense_misc {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t :2;
|
||||
uint8_t comp_chan_num_thresh:2;
|
||||
uint8_t cap_sense_sleep_mode_enable:1;
|
||||
uint8_t :1;
|
||||
uint8_t cap_sense_inactive_bl_mode:2;
|
||||
#else
|
||||
uint8_t cap_sense_inactive_bl_mode:2;
|
||||
uint8_t :1;
|
||||
uint8_t cap_sense_sleep_mode_enable:1;
|
||||
uint8_t comp_chan_num_thresh:2;
|
||||
uint8_t :2;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! SPO analog output for proximity
|
||||
struct sx9512_reg_spo_level_prox {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t spo_report_prox:1;
|
||||
uint8_t spo_prox_channel_mapping:1;
|
||||
uint8_t spo_level_prox:6;
|
||||
#else
|
||||
uint8_t spo_level_prox:6;
|
||||
uint8_t spo_prox_channel_mapping:1;
|
||||
uint8_t spo_report_prox:1;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! Buzzer trigger event selection
|
||||
struct sx9512_reg_buzzer_trigger {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t :3;
|
||||
uint8_t buzzer_near:1;
|
||||
uint8_t buzzer_far:1;
|
||||
uint8_t buzzer_touch:1;
|
||||
uint8_t buzzer_release:1;
|
||||
uint8_t buzzer_idle_level:1;
|
||||
#else
|
||||
uint8_t buzzer_idle_level:1;
|
||||
uint8_t buzzer_release:1;
|
||||
uint8_t buzzer_touch:1;
|
||||
uint8_t buzzer_far:1;
|
||||
uint8_t buzzer_near:1;
|
||||
uint8_t :3;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
//! Buzzer duration frequency
|
||||
struct sx9512_reg_buzzer_freq {
|
||||
#ifdef BIT_ORDER_BIG_ENDIAN
|
||||
uint8_t buzzer_phase1_duration:2;
|
||||
uint8_t buzzer_phase1_freq:2;
|
||||
uint8_t buzzer_phase2_duration:2;
|
||||
uint8_t buzzer_phase2_freq:2;
|
||||
#else
|
||||
uint8_t buzzer_phase2_freq:2;
|
||||
uint8_t buzzer_phase2_duration:2;
|
||||
uint8_t buzzer_phase1_freq:2;
|
||||
uint8_t buzzer_phase1_duration:2;
|
||||
#endif
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
struct sx9512_reg_nvm {
|
||||
struct sx9512_reg_spo2_mode spo2_mode; //!< SPO2 mode control
|
||||
uint8_t pwr_key; //!< Power key control
|
||||
struct sx9512_reg_irq_mask irq_mask; //!< Interrupt request mask
|
||||
uint8_t reserved_0a[2];
|
||||
uint8_t led_map[2]; //!< LED map for engine 1/2
|
||||
uint8_t led_pwm_freq; //!< LED PWM frequency
|
||||
struct sx9512_reg_led_mode led_mode; //!< LED mode
|
||||
uint8_t led_idle; //!< LED idle level
|
||||
struct sx9512_reg_led_off_delay led_off_delay; //!< LED off delay
|
||||
uint8_t led1_on; //!< LED engine 1 on level
|
||||
struct sx9512_reg_led_fade led1_fade; //!< LED engine 1 fade in/out time
|
||||
uint8_t led2_on; //!< LED engine 2 on level
|
||||
struct sx9512_reg_led_fade led2_fade; //!< LED engine 2 fade in/out time
|
||||
uint8_t led_pwr_idle; //!< LED power button idle level
|
||||
uint8_t led_pwr_on; //!< LED power button on level
|
||||
uint8_t led_pwr_off; //!< LED power button off level
|
||||
uint8_t led_pwr_fade; //!< LED power button fade in/out time
|
||||
uint8_t led_pwr_on_pw; //!< LED power on pulse width
|
||||
struct sx9512_reg_led_pwr_mode led_pwr_mode; //!< LED power button mode
|
||||
uint8_t reserved_1c[2];
|
||||
uint8_t cap_sense_enable; //!< CapSense enable
|
||||
struct sx9512_reg_cap_sense_range cap_sense_range[9]; //!< CapSense delta Cin range and LS control chan 0-7
|
||||
//struct sx9512_reg_cap_sense_range cap_sense_range_all; //!< CapSense delta Cin range and LS control for prox sensor (combined channels)
|
||||
uint8_t cap_sense_thresh[9]; //!< CapSense detection threshold for chan 0-7
|
||||
//uint8_t cap_sense_thesh_comb; //!< CapSense detection threshold for prox sensor (combined channels)
|
||||
struct sx9512_reg_cap_sense_op cap_sense_op; //!< CapSense auto compensation, proximity on BL0 and combined channel proximity enable
|
||||
struct sx9512_reg_cap_sense_mode cap_sense_mode; //!< CapSense raw data filter coef, digital gain, I2C touch reporting and CapSense reporting
|
||||
struct sx9512_reg_cap_sense_debounce cap_sense_debounce; //!< CapSense debounce
|
||||
uint8_t cap_sense_neg_comp_thresh; //!< CapSense negative auto compensation threshold
|
||||
uint8_t cap_sense_pos_comp_thresh; //!< CapSense positive auto compensation threshold
|
||||
struct sx9512_reg_cap_sense_pos_filt cap_sense_pos_filt; //!< CapSense positive filter coef, positive auto compensation debounce and proximity hyst
|
||||
struct sx9512_reg_cap_sense_neg_filt cap_sense_neg_filt; //!< CapSense negative filter coef, negative auto compensation debounce and touch hyst
|
||||
struct sx9512_reg_cap_sense_stuck cap_sense_stuck; //!< CapSense stuck-at timer and periodic compensation timer
|
||||
struct sx9512_reg_cap_sense_frame_skip cap_sense_frame_skip; //!< CapSense frame skip setting from active and sleep
|
||||
struct sx9512_reg_cap_sense_misc cap_sense_misc; //!< CapSense sleep enable, auto compensation channels threshold, inactive BL control
|
||||
uint8_t prox_comb_chan_mask; //!< Proximity combined channel mode channel mapping
|
||||
uint8_t reserved_3c[2];
|
||||
uint8_t spo_chan_map; //!< SPO channel mapping
|
||||
uint8_t spo_level_bl[8]; //!< SPO analog output levels
|
||||
uint8_t spo_level_idle; //!< SPO analog output level for idle
|
||||
struct sx9512_reg_spo_level_prox spo_level_prox; //!< SPO analog output for proximity
|
||||
uint8_t reserved_49[2];
|
||||
struct sx9512_reg_buzzer_trigger buzzer_trigger; //!< Buzzer trigger event selection
|
||||
struct sx9512_reg_buzzer_freq buzzer_freq; //!< Buzzer duration frequency
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
struct sx9512_reg {
|
||||
struct sx9512_reg_irq_src irq_src; //!< Interrupt source
|
||||
uint8_t touch_status; //!< Touch status
|
||||
struct sx9512_reg_prox_status prox_status; //!< Proximity status
|
||||
uint8_t comp_status; //!< Compensation status
|
||||
struct sx9512_reg_nvm_ctrl nvm_ctrl; //!< NVM control
|
||||
struct sx9512_reg_nvm nvm; //!< Non-volatile memory
|
||||
uint8_t cap_sense_chan_select; //!< CapSense channel select for readback
|
||||
uint16_t cap_sense_useful_data; //!< CapSense useful data
|
||||
uint16_t cap_sense_average_data; //!< CapSense average data
|
||||
uint16_t cap_sense_diff_data; //!< CapSense diff data
|
||||
uint16_t cap_sense_comp; //!< CapSense compensation DAC value
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
struct sx9512_reg_status {
|
||||
struct sx9512_reg_irq_src irq_src; //!< Interrupt source
|
||||
uint8_t touch_status; //!< Touch status
|
||||
struct sx9512_reg_prox_status prox_status; //!< Proximity status
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
struct sx9512_touch_state {
|
||||
uint8_t state;
|
||||
uint8_t touched;
|
||||
uint8_t released;
|
||||
};
|
||||
|
||||
|
||||
int sx9512_init(const char *dev, int addr, struct sx9512_reg_nvm *nvm);
|
||||
const char *sx9512_reg_name(sx9512_reg_t reg);
|
||||
int sx9512_reg_reserved(sx9512_reg_t reg);
|
||||
int sx9512_reset(int fd);
|
||||
int sx9512_reset_restore_led_state(int fd);
|
||||
int sx9512_read_interrupt(int fd);
|
||||
int sx9512_read_buttons(int fd);
|
||||
int sx9512_read_proximity(int fd);
|
||||
int sx9512_read_status(int fd, struct sx9512_reg_status *status);
|
||||
int sx9512_read_status_cached(int fd, struct sx9512_touch_state *touch_state);
|
||||
int sx9512_reg_nvm_load(int fd);
|
||||
int sx9512_reg_nvm_store(int fd);
|
||||
int sx9512_reg_nvm_read(int fd, struct sx9512_reg_nvm *p);
|
||||
int sx9512_reg_nvm_write(int fd, struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init(struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init_defaults(struct sx9512_reg_nvm *p, uint8_t capsense_channels, uint8_t led_channels);
|
||||
void sx9512_reg_nvm_init_cg300(struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init_cg301(struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init_eg300(struct sx9512_reg_nvm *p);
|
||||
void sx9512_reg_nvm_init_dg400(struct sx9512_reg_nvm *p);
|
||||
|
||||
#endif
|
||||
|
|
@ -21,13 +21,6 @@
|
|||
#include "touch_sx9512.h"
|
||||
#include "gpio.h"
|
||||
|
||||
/* register names, from page 29, */
|
||||
#define SX9512_IRQSRC 0
|
||||
#define SX9512_TOUCHSTATUS 1
|
||||
#define SX9512_PROXSTATUS 2
|
||||
#define SX9512_LEDMAP1 0xC
|
||||
#define SX9512_LEDMAP2 0xD
|
||||
|
||||
#define SX9512_IRQ_RESET 1<<7
|
||||
#define SX9512_IRQ_TOUCH 1<<6
|
||||
#define SX9512_IRQ_RELEASE 1<<5
|
||||
|
|
@ -36,21 +29,11 @@
|
|||
#define SX9512_IRQ_COM 1<<2
|
||||
#define SX9512_IRQ_CONV 1<<1
|
||||
|
||||
/* CG300 config:
|
||||
|
||||
BL0: Proximity
|
||||
BL1: Wireless button
|
||||
BL2: WPS button, WPS LED
|
||||
BL3: Dect button, Dect LED
|
||||
BL4: Internet green LED
|
||||
BL5: Internet red LED
|
||||
BL6, BL7: Unused.
|
||||
*/
|
||||
|
||||
struct i2c_reg_tab {
|
||||
char addr;
|
||||
char value;
|
||||
char range;
|
||||
char range; /* if set registers starting from addr to addr+range will be set to the same value */
|
||||
};
|
||||
|
||||
struct i2c_touch{
|
||||
|
|
@ -60,9 +43,6 @@ struct i2c_touch{
|
|||
int shadow_proximity;
|
||||
int addr;
|
||||
int irq_button;
|
||||
const struct i2c_reg_tab *init_tab;
|
||||
int init_tab_len;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct led_data {
|
||||
|
|
@ -76,274 +56,12 @@ struct sx9512_list{
|
|||
struct led_data *drv;
|
||||
};
|
||||
|
||||
|
||||
/* holds all leds that is configured to be used. needed for reset */
|
||||
static LIST_HEAD(sx9512_leds);
|
||||
|
||||
static struct i2c_touch *i2c_touch_current; /* pointer to current active table */
|
||||
|
||||
//static void do_init_tab( struct i2c_touch *i2c_touch);
|
||||
//static struct i2c_touch * i2c_init(struct uci_context *uci_ctx, const char* i2c_dev_name, struct i2c_touch* i2c_touch_list, int len);
|
||||
|
||||
static struct i2c_touch i2c_touch_current; /* pointer to current active table */
|
||||
static int sx9512_led_set_state(struct led_drv *drv, led_state_t state);
|
||||
static led_state_t sx9512_led_get_state(struct led_drv *drv);
|
||||
static int sx9512_set_state(struct led_data *p, led_state_t state);
|
||||
|
||||
|
||||
/*addr,value,range*/
|
||||
static const struct i2c_reg_tab i2c_init_tab_cg300[]={
|
||||
{0xFF, 0xDE, 0x00 }, /* Reset chip */
|
||||
{0xFF, 0x00, 0x00 }, /* Reset chip */
|
||||
|
||||
{0x04, 0x00, 0x00 }, /* NVM Control */
|
||||
{0x07, 0x00, 0x00 }, /* SPO2, set as interrupt */
|
||||
{0x08, 0x00, 0x00 }, /* Power key ctrl */
|
||||
{0x09, 0x78, 0x00 }, /* Irq MASK */
|
||||
{0x0C, 0x01, 0x00 }, /* LED map 1, BL0 (why?) */
|
||||
{0x0D, 0x3c, 0x00 }, /* LED map 2 BL2 -> BL5*/
|
||||
{0x0E, 0x10, 0x00 }, /* LED Pwm Frq */
|
||||
{0x0F, 0x00, 0x00 }, /* LED Mode */
|
||||
{0x10, 0xFF, 0x00 }, /* Led Idle LED on */
|
||||
{0x11, 0x00, 0x00 }, /* Led 1 off delay */
|
||||
{0x12, 0xFF, 0x00 }, /* Led 1 on */
|
||||
{0x13, 0x00, 0x00 }, /* Led 1 fade */
|
||||
{0x14, 0xFF, 0x00 }, /* Led 2 on */
|
||||
{0x15, 0x00, 0x00 }, /* Led 2 fade */
|
||||
{0x16, 0xFF, 0x00 }, /* Led Pwr Idle */
|
||||
{0x17, 0xFF, 0x00 }, /* Led Pwr On */
|
||||
{0x18, 0x00, 0x00 }, /* Led Pwr Off */
|
||||
{0x19, 0x00, 0x00 }, /* Led Pwr fade */
|
||||
{0x1A, 0x00, 0x00 }, /* Led Pwr On Pw */
|
||||
{0x1B, 0x00, 0x00 }, /* Disable BL7 as power button */
|
||||
{0x1E, 0x0F, 0x00 }, /* Cap sens enabled, bl0-bl3 */
|
||||
{0x1F, 0x43, 0x00 }, /* Cap sens BL0 */
|
||||
{0x20, 0x41, 0x07 }, /* Cap sens range 20-27 BL1->BL7 */
|
||||
{0x28, 0x02, 0x00 }, /* Cap sens thresh BL 0 */
|
||||
{0x29, 0x04, 0x07 }, /* Cap sens thresh 28-30 */
|
||||
{0x31, 0x54, 0x00 }, /* Cap sens Op */
|
||||
{0x32, 0x70, 0x00 }, /* Cap Sens Mode, filter 1-1/8, report all */
|
||||
{0x33, 0x01, 0x00 }, /* Cap Sens Debounce */
|
||||
{0x34, 0x80, 0x00 }, /* Cap Sens Neg Comp Thresh */
|
||||
{0x35, 0x80, 0x00 }, /* Cap Sens Pos Comp Thresh */
|
||||
{0x36, 0x17, 0x00 }, /* Cap Sens Pos Filt, hyst 2, debounce 4, 1-1/128 */
|
||||
{0x37, 0x15, 0x00 }, /* Cap Sens Neg Filt, hyst 2, debounce 4, 1-1/32 */
|
||||
{0x38, 0x00, 0x00 }, /* Cap Sens */
|
||||
{0x39, 0x00, 0x00 }, /* Cap Sens Frame Skip */
|
||||
{0x3A, 0x00, 0x00 }, /* Cap Sens Misc */
|
||||
{0x3B, 0x00, 0x00 }, /* Prox Comb Chan Mask */
|
||||
{0x3E, 0xFF, 0x00 }, /* SPO Chan Map */
|
||||
{0x00, 0x04, 0x00 }, /* Trigger compensation */
|
||||
};
|
||||
|
||||
/* CG301 config:
|
||||
|
||||
BL0: Proximity, Status white LED
|
||||
BL1: Service button, Service white LED
|
||||
BL2: Service red LED
|
||||
BL3: Pair button, Pair white LED
|
||||
BL4: Cancel button, Cancel red LED
|
||||
BL5: Communication button, Communication white LED
|
||||
BL6: Communication red LED
|
||||
BL7: Unused.
|
||||
*/
|
||||
|
||||
static const struct i2c_reg_tab i2c_init_tab_cg301[]={
|
||||
{0xFF, 0xDE, 0x00 }, /* Reset chip */
|
||||
{0xFF, 0x00, 0x00 }, /* Reset chip */
|
||||
|
||||
{0x04, 0x00, 0x00 }, /* NVM Control */
|
||||
{0x07, 0x00, 0x00 }, /* SPO2, set as interrupt */
|
||||
{0x08, 0x00, 0x00 }, /* Power key ctrl */
|
||||
{0x09, 0x78, 0x00 }, /* Irq MASK, touch+release+near+far */
|
||||
{0x0C, 0x00, 0x00 }, /* LED map 1, none */
|
||||
{0x0D, 0x7f, 0x00 }, /* LED map 2, BL0 -> BL6 */
|
||||
{0x0E, 0x10, 0x00 }, /* LED Pwm Frq */
|
||||
{0x0F, 0x00, 0x00 }, /* LED Mode */
|
||||
{0x10, 0xFF, 0x00 }, /* Led Idle LED on */
|
||||
{0x11, 0x00, 0x00 }, /* Led 1 off delay */
|
||||
{0x12, 0xFF, 0x00 }, /* Led 1 on */
|
||||
{0x13, 0x00, 0x00 }, /* Led 1 fade */
|
||||
{0x14, 0xFF, 0x00 }, /* Led 2 on */
|
||||
{0x15, 0x00, 0x00 }, /* Led 2 fade */
|
||||
{0x16, 0xFF, 0x00 }, /* Led Pwr Idle */
|
||||
{0x17, 0xFF, 0x00 }, /* Led Pwr On */
|
||||
{0x18, 0x00, 0x00 }, /* Led Pwr Off */
|
||||
{0x19, 0x00, 0x00 }, /* Led Pwr fade */
|
||||
{0x1A, 0x00, 0x00 }, /* Led Pwr On Pw */
|
||||
{0x1B, 0x00, 0x00 }, /* Disable BL7 as power button */
|
||||
{0x1E, 0x3b, 0x00 }, /* Cap sens enabled, bl0,bl1,bl3-bl5 */
|
||||
{0x1F, 0x43, 0x00 }, /* Cap sens range BL0 */
|
||||
{0x20, 0x41, 0x07 }, /* Cap sens range BL1->BL7 [20-27] */
|
||||
{0x28, 0x02, 0x00 }, /* Cap sens thresh BL0 */
|
||||
{0x29, 0x04, 0x07 }, /* Cap sens thresh BL1->BL7 [29-30] */
|
||||
{0x31, 0x54, 0x00 }, /* Cap sens Op */
|
||||
{0x32, 0x70, 0x00 }, /* Cap Sens Mode, filter 1-1/8, report all */
|
||||
{0x33, 0x01, 0x00 }, /* Cap Sens Debounce */
|
||||
{0x34, 0x80, 0x00 }, /* Cap Sens Neg Comp Thresh */
|
||||
{0x35, 0x80, 0x00 }, /* Cap Sens Pos Comp Thresh */
|
||||
{0x36, 0x17, 0x00 }, /* Cap Sens Pos Filt, hyst 2, debounce 4, 1-1/128 */
|
||||
{0x37, 0x15, 0x00 }, /* Cap Sens Neg Filt, hyst 2, debounce 4, 1-1/32 */
|
||||
{0x38, 0x00, 0x00 }, /* Cap Sens */
|
||||
{0x39, 0x00, 0x00 }, /* Cap Sens Frame Skip */
|
||||
{0x3A, 0x00, 0x00 }, /* Cap Sens Misc */
|
||||
{0x3B, 0x00, 0x00 }, /* Prox Comb Chan Mask */
|
||||
{0x3E, 0xFF, 0x00 }, /* SPO Chan Map */
|
||||
{0x00, 0x04, 0x00 }, /* Trigger compensation */
|
||||
};
|
||||
|
||||
/* EG300 config:
|
||||
|
||||
BL0: Proximity, WAN green LED
|
||||
BL1: Wireless button, WAN yellow LED
|
||||
BL2: WPS button, WPS LED
|
||||
BL3: Dect button, Dect LED
|
||||
BL4: Internet green LED
|
||||
BL5: Internet red LED
|
||||
BL6: Ethernet LED
|
||||
BL7: Voice LED
|
||||
|
||||
Only the led 1 and led2 maps differ from CG300.
|
||||
*/
|
||||
|
||||
static const struct i2c_reg_tab i2c_init_tab_eg300[]={
|
||||
{0xFF, 0xDE, 0x00 }, /* Reset chip */
|
||||
{0xFF, 0x00, 0x00 }, /* Reset chip */
|
||||
|
||||
{0x04, 0x00, 0x00 }, /* NVM Control */
|
||||
{0x07, 0x00, 0x00 }, /* SPO2, set as interrupt */
|
||||
{0x08, 0x00, 0x00 }, /* Power key ctrl */
|
||||
{0x09, 0x78, 0x00 }, /* Irq MASK */
|
||||
{0x0C, 0x00, 0x00 }, /* LED map 1, none */
|
||||
{0x0D, 0xff, 0x00 }, /* LED map 2, all */
|
||||
{0x0E, 0x10, 0x00 }, /* LED Pwm Frq */
|
||||
{0x0F, 0x00, 0x00 }, /* LED Mode */
|
||||
{0x10, 0xFF, 0x00 }, /* Led Idle LED on */
|
||||
{0x11, 0x00, 0x00 }, /* Led 1 off delay */
|
||||
{0x12, 0xFF, 0x00 }, /* Led 1 on */
|
||||
{0x13, 0x00, 0x00 }, /* Led 1 fade */
|
||||
{0x14, 0xFF, 0x00 }, /* Led 2 on */
|
||||
{0x15, 0x00, 0x00 }, /* Led 2 fade */
|
||||
{0x16, 0xFF, 0x00 }, /* Led Pwr Idle */
|
||||
{0x17, 0xFF, 0x00 }, /* Led Pwr On */
|
||||
{0x18, 0x00, 0x00 }, /* Led Pwr Off */
|
||||
{0x19, 0x00, 0x00 }, /* Led Pwr fade */
|
||||
{0x1A, 0x00, 0x00 }, /* Led Pwr On Pw */
|
||||
{0x1B, 0x00, 0x00 }, /* Disable BL7 as power button */
|
||||
{0x1E, 0x0F, 0x00 }, /* Cap sens enabled, bl0-bl3 */
|
||||
{0x1F, 0x43, 0x00 }, /* Cap sens BL0 */
|
||||
{0x20, 0x43, 0x07 }, /* Cap sens range 20-27 BL1->BL7 */
|
||||
{0x28, 0x02, 0x00 }, /* Cap sens thresh BL 0 */
|
||||
{0x29, 0x04, 0x07 }, /* Cap sens thresh 28-30 */
|
||||
{0x31, 0x54, 0x00 }, /* Cap sens Op */
|
||||
{0x32, 0x70, 0x00 }, /* Cap Sens Mode, filter 1-1/8, report all */
|
||||
{0x33, 0x01, 0x00 }, /* Cap Sens Debounce */
|
||||
{0x34, 0x80, 0x00 }, /* Cap Sens Neg Comp Thresh */
|
||||
{0x35, 0x80, 0x00 }, /* Cap Sens Pos Comp Thresh */
|
||||
{0x36, 0x17, 0x00 }, /* Cap Sens Pos Filt, hyst 2, debounce 4, 1-1/128 */
|
||||
{0x37, 0x15, 0x00 }, /* Cap Sens Neg Filt, hyst 2, debounce 4, 1-1/32 */
|
||||
{0x38, 0x00, 0x00 }, /* Cap Sens */
|
||||
{0x39, 0x00, 0x00 }, /* Cap Sens Frame Skip */
|
||||
{0x3A, 0x00, 0x00 }, /* Cap Sens Misc */
|
||||
{0x3B, 0x00, 0x00 }, /* Prox Comb Chan Mask */
|
||||
{0x3E, 0xFF, 0x00 }, /* SPO Chan Map */
|
||||
{0x00, 0x04, 0x00 }, /* Trigger compensation */
|
||||
};
|
||||
|
||||
static struct i2c_touch i2c_touch_list[] = {
|
||||
{.addr = 0x2b,
|
||||
.name = "CG300",
|
||||
.irq_button = 1,
|
||||
.init_tab = i2c_init_tab_cg300,
|
||||
.init_tab_len = sizeof(i2c_init_tab_cg300)/sizeof(struct i2c_reg_tab),
|
||||
},
|
||||
|
||||
{.addr = 0x2b,
|
||||
.name = "CG301",
|
||||
.irq_button = 1,
|
||||
.init_tab = i2c_init_tab_cg301,
|
||||
.init_tab_len = sizeof(i2c_init_tab_cg301)/sizeof(struct i2c_reg_tab),
|
||||
},
|
||||
|
||||
{.addr = 0x2b,
|
||||
.name = "DG200",
|
||||
.irq_button = 1,
|
||||
.init_tab = i2c_init_tab_eg300,
|
||||
.init_tab_len = sizeof(i2c_init_tab_eg300)/sizeof(struct i2c_reg_tab),
|
||||
},
|
||||
|
||||
{.addr = 0x2b,
|
||||
.name = "EG300",
|
||||
.irq_button = 1,
|
||||
.init_tab = i2c_init_tab_eg300,
|
||||
.init_tab_len = sizeof(i2c_init_tab_eg300)/sizeof(struct i2c_reg_tab),
|
||||
}
|
||||
};
|
||||
|
||||
static void do_init_tab( struct i2c_touch *i2c_touch)
|
||||
{
|
||||
const struct i2c_reg_tab *tab;
|
||||
int i;
|
||||
|
||||
tab = i2c_touch->init_tab;
|
||||
|
||||
for (i = 0 ; i < i2c_touch->init_tab_len ; i++){
|
||||
int y;
|
||||
int ret;
|
||||
for ( y = 0 ; y <= tab[i].range; y++ ){
|
||||
DBG(3,"%s: addr %02X = %02X ",__func__,(unsigned char)tab[i].addr+y, (unsigned char)tab[i].value);
|
||||
ret = i2c_smbus_write_byte_data(i2c_touch->dev, tab[i].addr+y, tab[i].value);
|
||||
if (ret < 0){
|
||||
perror("write to i2c dev\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
// dump_i2c(i2c_touch->dev,0,13);
|
||||
}
|
||||
|
||||
|
||||
struct i2c_touch * i2c_init(struct uci_context *uci_ctx, const char* i2c_dev_name, struct i2c_touch* touch_list, int len)
|
||||
{
|
||||
const char *p;
|
||||
int i;
|
||||
struct i2c_touch *i2c_touch;
|
||||
|
||||
p = ucix_get_option(uci_ctx, "hw", "board", "hardware");
|
||||
if (p == 0){
|
||||
syslog(LOG_INFO, "%s: Missing Hardware identifier in configuration. I2C is not started\n",__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
i2c_touch = NULL;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!strcmp(touch_list[i].name, p)) {
|
||||
DBG(1,"I2C hardware platform %s found.\n", p);
|
||||
i2c_touch = &touch_list[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!i2c_touch) {
|
||||
DBG(1,"No I2C hardware found: %s.\n", p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
i2c_touch->dev = i2c_open_dev(i2c_dev_name, i2c_touch->addr,
|
||||
I2C_FUNC_SMBUS_READ_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE);
|
||||
|
||||
if (i2c_touch->dev < 0) {
|
||||
syslog(LOG_INFO,"%s: could not open i2c touch device\n",__func__);
|
||||
i2c_touch->dev = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DBG(1,"Opened device and selected address %x \n", i2c_touch->addr);
|
||||
|
||||
do_init_tab(i2c_touch);
|
||||
|
||||
return i2c_touch;
|
||||
}
|
||||
|
||||
extern struct uloop_timeout i2c_touch_reset_timer;
|
||||
|
||||
|
||||
|
|
@ -355,7 +73,8 @@ struct uloop_timeout i2c_touch_reset_timer = { .cb = sx9512_reset_handler };
|
|||
static void sx9512_reset_handler(struct uloop_timeout *timeout)
|
||||
{
|
||||
struct list_head *i;
|
||||
do_init_tab(i2c_touch_current);
|
||||
//do_init_tab(i2c_touch_current);
|
||||
sx9512_reset_restore_led_state(i2c_touch_current.dev);
|
||||
|
||||
list_for_each(i, &sx9512_leds) {
|
||||
struct sx9512_list *node = list_entry(i, struct sx9512_list, list);
|
||||
|
|
@ -371,7 +90,7 @@ static int sx9512_set_state(struct led_data *p, led_state_t state)
|
|||
int ret;
|
||||
int bit = 1 << p->addr;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current->dev, SX9512_LEDMAP2);
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current.dev, SX9512_REG_LED_MAP2);
|
||||
if (ret < 0 )
|
||||
syslog(LOG_ERR, "Could not read from i2c device, LedMap2 register\n");
|
||||
|
||||
|
|
@ -386,7 +105,7 @@ static int sx9512_set_state(struct led_data *p, led_state_t state)
|
|||
|
||||
p->state = state;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(i2c_touch_current->dev, SX9512_LEDMAP2, ret);
|
||||
ret = i2c_smbus_write_byte_data(i2c_touch_current.dev, SX9512_REG_LED_MAP2, ret);
|
||||
if (ret < 0 ) {
|
||||
syslog(LOG_ERR, "Could not write to i2c device, LedMap2 register\n");
|
||||
return -1;
|
||||
|
|
@ -399,7 +118,7 @@ static int sx9512_led_set_state(struct led_drv *drv, led_state_t state)
|
|||
{
|
||||
struct led_data *p = (struct led_data *)drv->priv;
|
||||
|
||||
if (!i2c_touch_current || !i2c_touch_current->dev)
|
||||
if (!i2c_touch_current.dev)
|
||||
return -1;
|
||||
|
||||
if (p->addr > 7){
|
||||
|
|
@ -440,32 +159,32 @@ void sx9512_check(void)
|
|||
int got_irq = 0;
|
||||
int ret;
|
||||
|
||||
if (!i2c_touch_current || !i2c_touch_current->dev)
|
||||
if (!i2c_touch_current.dev)
|
||||
return;
|
||||
|
||||
if (i2c_touch_current->irq_button) {
|
||||
if (i2c_touch_current.irq_button) {
|
||||
int button;
|
||||
button = board_ioctl( BOARD_IOCTL_GET_GPIO, 0, 0, NULL, i2c_touch_current->irq_button, 0);
|
||||
button = board_ioctl( BOARD_IOCTL_GET_GPIO, 0, 0, NULL, i2c_touch_current.irq_button, 0);
|
||||
if (button == 0)
|
||||
got_irq = 1;
|
||||
}
|
||||
if ( got_irq ) {
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current->dev, SX9512_IRQSRC);
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current.dev, SX9512_REG_IRQ_SRC);
|
||||
if (ret < 0 )
|
||||
syslog(LOG_ERR, "Could not read from i2c device, irq status register\n");
|
||||
i2c_touch_current->shadow_irq = ret;
|
||||
i2c_touch_current.shadow_irq = ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current->dev, SX9512_TOUCHSTATUS);
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current.dev, SX9512_REG_TOUCH_STATUS);
|
||||
if (ret < 0 )
|
||||
syslog(LOG_ERR, "Could not read from i2c device, touch register\n");
|
||||
i2c_touch_current->shadow_touch = ret;
|
||||
i2c_touch_current.shadow_touch = ret;
|
||||
|
||||
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current->dev, SX9512_PROXSTATUS);
|
||||
ret = i2c_smbus_read_byte_data(i2c_touch_current.dev, SX9512_REG_PROX_STATUS);
|
||||
if (ret < 0 )
|
||||
syslog(LOG_ERR, "Could not read from i2c device, proximity register\n");
|
||||
i2c_touch_current->shadow_proximity = ret;
|
||||
i2c_touch_current.shadow_proximity = ret;
|
||||
}
|
||||
#if 0
|
||||
DEBUG_PRINT("%02x %02x %02x: irq ->",
|
||||
|
|
@ -498,8 +217,8 @@ void sx9512_check(void)
|
|||
button address 8 proximity BL0 NEAR
|
||||
button address 9 proximity BL0 FAR
|
||||
|
||||
return RELEASED = no action on this button
|
||||
return PRESSED = button pressed
|
||||
return BUTTON_RELEASED = no action on this button
|
||||
return BUTTON_PRESSED = button pressed
|
||||
return -1 = error
|
||||
*/
|
||||
|
||||
|
|
@ -508,49 +227,45 @@ static button_state_t sx9512_button_get_state(struct button_drv *drv)
|
|||
struct button_data *p = (struct button_data *)drv->priv;
|
||||
int bit = 1 << p->addr;
|
||||
|
||||
if (!i2c_touch_current || !i2c_touch_current->dev)
|
||||
if (!i2c_touch_current.dev)
|
||||
return -1;
|
||||
|
||||
if (p->addr < 8) {
|
||||
if ( bit & i2c_touch_current->shadow_touch ) {
|
||||
i2c_touch_current->shadow_touch = i2c_touch_current->shadow_touch & ~bit;
|
||||
p->state = PRESSED;
|
||||
return PRESSED;
|
||||
if ( bit & i2c_touch_current.shadow_touch ) {
|
||||
i2c_touch_current.shadow_touch = i2c_touch_current.shadow_touch & ~bit;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
|
||||
/* if the button was already pressed and we don't have a release irq report it as still pressed */
|
||||
if( p->state == PRESSED){
|
||||
if (! (i2c_touch_current->shadow_irq & SX9512_IRQ_RELEASE) ) {
|
||||
return PRESSED;
|
||||
if( p->state == BUTTON_PRESSED){
|
||||
if (! (i2c_touch_current.shadow_irq & SX9512_IRQ_RELEASE) ) {
|
||||
return BUTTON_PRESSED;
|
||||
}
|
||||
}
|
||||
p->state = RELEASED;
|
||||
return RELEASED;
|
||||
return p->state = BUTTON_RELEASED;
|
||||
|
||||
/* proximity NEAR */
|
||||
}else if (p->addr == 8 ) {
|
||||
bit = 1<<7;
|
||||
if( i2c_touch_current->shadow_irq & SX9512_IRQ_NEAR ) {
|
||||
i2c_touch_current->shadow_irq &= ~SX9512_IRQ_NEAR;
|
||||
if ( bit & i2c_touch_current->shadow_proximity ) {
|
||||
i2c_touch_current->shadow_proximity = i2c_touch_current->shadow_proximity & ~bit;
|
||||
p->state = PRESSED;
|
||||
return PRESSED;
|
||||
if( i2c_touch_current.shadow_irq & SX9512_IRQ_NEAR ) {
|
||||
i2c_touch_current.shadow_irq &= ~SX9512_IRQ_NEAR;
|
||||
if ( bit & i2c_touch_current.shadow_proximity ) {
|
||||
i2c_touch_current.shadow_proximity = i2c_touch_current.shadow_proximity & ~bit;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
}
|
||||
return RELEASED;
|
||||
return BUTTON_RELEASED;
|
||||
|
||||
/* proximity FAR */
|
||||
}else if (p->addr == 9) {
|
||||
if( i2c_touch_current->shadow_irq & SX9512_IRQ_FAR ) {
|
||||
i2c_touch_current->shadow_irq &= ~SX9512_IRQ_FAR;
|
||||
p->state = PRESSED;
|
||||
return PRESSED;
|
||||
if( i2c_touch_current.shadow_irq & SX9512_IRQ_FAR ) {
|
||||
i2c_touch_current.shadow_irq &= ~SX9512_IRQ_FAR;
|
||||
return p->state = BUTTON_PRESSED;
|
||||
}
|
||||
return RELEASED;
|
||||
return BUTTON_RELEASED;
|
||||
}else {
|
||||
DBG(1,"Button address out of range %d\n",p->addr);
|
||||
return RELEASED;
|
||||
return BUTTON_RELEASED;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -631,30 +346,88 @@ static void sx9512_led_init(struct server_ctx *s_ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
void sx9512_init(struct server_ctx *s_ctx) {
|
||||
|
||||
struct list_head *i;
|
||||
|
||||
DBG(1, "");
|
||||
|
||||
i2c_touch_current = i2c_init(s_ctx->uci_ctx,
|
||||
"/dev/i2c-0",
|
||||
i2c_touch_list,
|
||||
sizeof(i2c_touch_list)/sizeof(i2c_touch_list[0]));
|
||||
|
||||
if (i2c_touch_current != 0) {
|
||||
|
||||
sx9512_button_init(s_ctx);
|
||||
sx9512_led_init(s_ctx);
|
||||
|
||||
/* Force set of initial state for leds. */
|
||||
list_for_each(i, &sx9512_leds) {
|
||||
struct sx9512_list *node = list_entry(i, struct sx9512_list, list);
|
||||
sx9512_set_state(node->drv, node->drv->state);
|
||||
}
|
||||
|
||||
/* start reset timer */
|
||||
uloop_timeout_set(&i2c_touch_reset_timer, I2C_RESET_TIME);
|
||||
void sx9512_handler_init(struct server_ctx *s_ctx)
|
||||
{
|
||||
char *s, *sx9512_i2c_device;
|
||||
int i, fd, sx9512_i2c_address, sx9512_irq_pin, sx9512_active_capsense_channels, sx9512_active_led_channels;
|
||||
struct sx9512_reg_nvm nvm;
|
||||
struct list_head *il;
|
||||
|
||||
if(!(sx9512_i2c_device = ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_i2c_device"))) {
|
||||
DBG(0, "Error: option is missing: sx9512_i2c_device");
|
||||
return;
|
||||
}
|
||||
DBG(1, "sx9512_i2c_device = [%s]", sx9512_i2c_device);
|
||||
|
||||
if(!(s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_i2c_address"))) {
|
||||
DBG(0, "Warning: option is missing: sx9512_i2c_address, setting to default (%02X)", SX9512_I2C_ADDRESS);
|
||||
sx9512_i2c_address = SX9512_I2C_ADDRESS;
|
||||
} else
|
||||
sx9512_i2c_address = strtol(s,0,16);
|
||||
DBG(1, "sx9512_i2c_address = [%02X]", sx9512_i2c_address);
|
||||
|
||||
if(!(s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_irq_pin"))) {
|
||||
DBG(0, "Error: option is missing: sx9512_irq_pin");
|
||||
return;
|
||||
}
|
||||
sx9512_irq_pin = strtol(s,0,0);
|
||||
DBG(1, "sx9512_irq_pin = [%d]", sx9512_irq_pin);
|
||||
|
||||
if(!(s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_active_capsense_channels"))) {
|
||||
DBG(0, "Error: option is missing: sx9512_active_capsense_channels");
|
||||
return;
|
||||
}
|
||||
sx9512_active_capsense_channels = strtol(s,0,16);
|
||||
DBG(1, "sx9512_active_capsense_channels = [%02X]", sx9512_active_capsense_channels);
|
||||
|
||||
if(!(s=ucix_get_option(s_ctx->uci_ctx, "hw", "board", "sx9512_active_led_channels"))) {
|
||||
DBG(0, "Error: option is missing: sx9512_active_led_channels");
|
||||
return;
|
||||
}
|
||||
sx9512_active_led_channels = strtol(s,0,16);
|
||||
DBG(1, "sx9512_active_led_channels = [%02X]", sx9512_active_led_channels);
|
||||
|
||||
sx9512_reg_nvm_init_defaults(&nvm, sx9512_active_capsense_channels, sx9512_active_led_channels);
|
||||
|
||||
LIST_HEAD(sx9512_init_regs);
|
||||
struct ucilist *node;
|
||||
ucix_get_option_list(s_ctx->uci_ctx, "hw","sx9512_init_regs", "regs", &sx9512_init_regs);
|
||||
list_for_each_entry(node,&sx9512_init_regs,list) {
|
||||
sx9512_reg_t reg;
|
||||
uint8_t val;
|
||||
int repeat;
|
||||
reg = strtol(node->val,0,16);
|
||||
if(sx9512_reg_reserved(reg)) {
|
||||
DBG(0, "Error: invalid sx9512 reg [%02X]", reg);
|
||||
return;
|
||||
}
|
||||
s = ucix_get_option(s_ctx->uci_ctx, "hw", node->val, "val");
|
||||
val = strtol(s,0,16);
|
||||
if(!(s = ucix_get_option(s_ctx->uci_ctx, "hw", node->val, "repeat")))
|
||||
repeat=1;
|
||||
else
|
||||
repeat=strtol(s,0,0);
|
||||
for(i=0;i<repeat;i++) {
|
||||
DBG(1, "sx9512_init_reg[%02X:%s=%02X]", reg, sx9512_reg_name(reg), val);
|
||||
((uint8_t *)&nvm)[reg-SX9512_REG_NVM_AREA_START] = val;
|
||||
reg++;
|
||||
}
|
||||
}
|
||||
|
||||
if((fd = sx9512_init(sx9512_i2c_device, sx9512_i2c_address, &nvm))<1)
|
||||
return;
|
||||
i2c_touch_current.dev=fd;
|
||||
i2c_touch_current.addr=sx9512_i2c_address;
|
||||
i2c_touch_current.irq_button=sx9512_irq_pin;
|
||||
|
||||
sx9512_button_init(s_ctx);
|
||||
sx9512_led_init(s_ctx);
|
||||
/* Force set of initial state for leds. */
|
||||
list_for_each(il, &sx9512_leds) {
|
||||
struct sx9512_list *node = list_entry(il, struct sx9512_list, list);
|
||||
sx9512_set_state(node->drv, node->drv->state);
|
||||
}
|
||||
/* start reset timer */
|
||||
uloop_timeout_set(&i2c_touch_reset_timer, I2C_RESET_TIME);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,9 @@
|
|||
#define TOUCH_SX9512_H
|
||||
|
||||
#include "server.h"
|
||||
#include "sx9512.h"
|
||||
|
||||
void sx9512_init(struct server_ctx *);
|
||||
void sx9512_handler_init(struct server_ctx *);
|
||||
void sx9512_check(void);
|
||||
|
||||
#endif /* TOUCH_SX9512_H */
|
||||
|
|
|
|||
|
|
@ -171,6 +171,6 @@ void vox_init(struct server_ctx *s_ctx) {
|
|||
/* arg 4 is the spi mode encoded in a string pointer */
|
||||
/* mode is decribed i/bcm963xx/shared/opensource/include/bcm963xx/bcmSpiRes.h */
|
||||
board_ioctl(BOARD_IOCTL_SPI_INIT, SPI_SLAVE_SELECT, 0, (char*)0, 0, 391000);
|
||||
gpio_open_ioctl();
|
||||
board_ioctl_init();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
int ch;
|
||||
|
||||
gpio_open_ioctl();
|
||||
board_ioctl_init();
|
||||
/* arg 4 is the spi mode encoded in a string pointer */
|
||||
/* mode is decribed i/bcm963xx/shared/opensource/include/bcm963xx/bcmSpiRes.h */
|
||||
board_ioctl(BOARD_IOCTL_SPI_INIT, SPI_SLAVE_SELECT, 0, (char *)0, 0, 391000);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue