forked from hd-zero/hdzero-goggle
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
288 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,261 @@ | ||
#include "i2c_ext.h" | ||
|
||
#include <fcntl.h> | ||
#include <linux/i2c-dev.h> | ||
#include <linux/i2c.h> | ||
#include <memory.h> | ||
#include <stdint.h> | ||
#include <stdio.h> | ||
#include <sys/ioctl.h> | ||
|
||
#define IIC_PORTS 4 | ||
static char *IIC_DEVS[IIC_PORTS] = { | ||
"/dev/i2c-0", | ||
"/dev/i2c-1", | ||
"/dev/i2c-2", | ||
"/dev/i2c-3", | ||
}; | ||
|
||
int i2c_fd; | ||
bool i2c_report_once = false; | ||
i2c_ext_mode_t mode; | ||
arg_t arg; | ||
|
||
void i2c_ext_init(uint8_t port) { | ||
i2c_fd = open(IIC_DEVS[port], O_RDONLY); | ||
|
||
if (port < 0 || port >= IIC_PORTS) { | ||
printf("Port %d contains an invalid range [0=N/A,1=Right,2=Main,3=Left]", port); | ||
return; | ||
} else if (i2c_fd < 0) { | ||
if (!i2c_report_once) { | ||
i2c_report_once = true; | ||
printf("Device %d:%s is not available [0=N/A,1=Right,2=Main,3=Left]", port, IIC_DEVS[port]); | ||
} | ||
return; | ||
} | ||
} | ||
|
||
static int i2c_write_ext(i2c_ext_mode_t mode, uint8_t slave_address, uint32_t reg_address, uint32_t reg_val) { | ||
struct i2c_rdwr_ioctl_data work_queue; | ||
struct i2c_msg msgs; | ||
uint8_t obuf[8]; | ||
const uint8_t alen = (mode >> 2) + 1; | ||
const uint8_t dlen = (mode & 3) + 1; | ||
const uint8_t len = alen + dlen; | ||
int i; | ||
int ret; | ||
|
||
work_queue.nmsgs = 1; | ||
work_queue.msgs = &msgs; | ||
msgs.buf = obuf; | ||
|
||
(work_queue.msgs[0]).len = len; | ||
(work_queue.msgs[0]).flags = I2C_SMBUS_WRITE; | ||
|
||
(work_queue.msgs[0]).addr = slave_address; | ||
|
||
for (i = 0; i < alen; i++) { | ||
(work_queue.msgs[0]).buf[i] = (reg_address >> (i << 3)) & 0xff; | ||
} | ||
|
||
for (i = 0; i < dlen; i++) { | ||
(work_queue.msgs[0]).buf[i + alen] = (reg_val >> (i << 3)) & 0xff; | ||
} | ||
|
||
ret = ioctl(i2c_fd, I2C_RDWR, (unsigned long)&work_queue); | ||
if (ret < 0) { | ||
printf("iic_write[%x.%x]<-%x failed.", slave_address, reg_address, reg_val); | ||
ret = 0; | ||
} | ||
return ret; | ||
} | ||
|
||
static void i2c_read_ext(i2c_ext_mode_t mode, uint32_t slave_address, uint32_t reg_address) { | ||
struct i2c_rdwr_ioctl_data work_queue; | ||
struct i2c_msg msgs[2]; | ||
const uint8_t alen = (mode >> 2) + 1; | ||
const uint8_t dlen = (mode & 3) + 1; | ||
const uint8_t len = alen + dlen; | ||
int i, j; | ||
int ret; | ||
uint8_t reg_data[4]; | ||
|
||
reg_data[0] = (uint8_t)(reg_address & 0xff); | ||
reg_data[1] = (uint8_t)((reg_address >> 8) & 0xff); | ||
reg_data[2] = (uint8_t)((reg_address >> 16) & 0xff); | ||
reg_data[3] = (uint8_t)((reg_address >> 24) & 0xff); | ||
|
||
work_queue.nmsgs = 2; | ||
work_queue.msgs = msgs; | ||
|
||
(work_queue.msgs[0]).len = alen; | ||
(work_queue.msgs[0]).flags = I2C_SMBUS_WRITE; | ||
(work_queue.msgs[0]).addr = (uint8_t)slave_address; | ||
(work_queue.msgs[0]).buf = reg_data; | ||
|
||
(work_queue.msgs[1]).len = dlen; | ||
(work_queue.msgs[1]).flags = I2C_SMBUS_READ; | ||
(work_queue.msgs[1]).addr = (uint8_t)slave_address; | ||
(work_queue.msgs[1]).buf = reg_data; | ||
ret = ioctl(i2c_fd, I2C_RDWR, (unsigned long)&work_queue); | ||
|
||
if (ret < 0) { | ||
printf("\r\ni2c_read[%x.%x] failed.", slave_address, reg_address); | ||
} else { | ||
printf("\r\n0x%08x: 0x", reg_address); | ||
for (i = 0; i < dlen; i++) { | ||
printf("%02x", reg_data[i]); | ||
} | ||
} | ||
} | ||
|
||
void display_usage(void) { | ||
printf("\r\nusage:\r\n"); | ||
printf("\r\n i2c_ext -p[port] -m[mode] -w/r [device address] [reg address] [reg value]"); | ||
printf("\r\n -p: i2c bus port"); | ||
printf("\r\n 0: None "); | ||
printf("\r\n 1: Right "); | ||
printf("\r\n 2: Main "); | ||
printf("\r\n 3: Left "); | ||
printf("\r\n -m: mode"); | ||
printf("\r\n 0: A8D8 "); | ||
printf("\r\n 1: A8D16 "); | ||
printf("\r\n 2: A8D24 "); | ||
printf("\r\n 3: A8D32 "); | ||
printf("\r\n 4: A16D8 "); | ||
printf("\r\n 5: A16D16"); | ||
printf("\r\n 6: A16D24"); | ||
printf("\r\n 7: A16D32"); | ||
printf("\r\n -w/r: write or read"); | ||
printf("\r\n -w: write"); | ||
printf("\r\n -r: read"); | ||
printf("\r\n [slave address(7 bits)]"); | ||
printf("\r\n eg 64: means 0x64"); | ||
printf("\r\n [reg address(hex)]"); | ||
printf("\r\n eg ff: means ff"); | ||
printf("\r\n [reg value(hex)]"); | ||
printf("\r\n reg_value for write"); | ||
printf("\r\n length for read"); | ||
printf("\r\n eg 6: 0x06"); | ||
printf("\r\n"); | ||
} | ||
|
||
void arg_error(char cmd) { | ||
printf("\r\n-%c:error", cmd); | ||
} | ||
|
||
int is_hex_string(char c) { | ||
if (c >= '0' && c <= '9') { | ||
return c - '0'; | ||
} else if (c >= 'A' && c <= 'F') { | ||
return c - 'A' + 10; | ||
} else if (c >= 'a' && c <= 'f') { | ||
return c - 'a' + 10; | ||
} else { | ||
return -1; | ||
} | ||
} | ||
|
||
uint8_t parse_arg(int argc, char *argv[]) { | ||
uint8_t ret = 0; | ||
uint8_t i, j, k; | ||
char cur_op[256] = {0}; | ||
|
||
if (argc <= 1) { | ||
printf("No parameter detected"); | ||
display_usage(); | ||
ret = 1; | ||
} else { | ||
arg.data[0] = 0; | ||
arg.data[1] = 0; | ||
arg.data[2] = 0; | ||
// parse | ||
k = 0; | ||
for (i = 1; i < argc; i++) { | ||
memset(cur_op, 0, sizeof(cur_op)); | ||
memcpy(cur_op, argv[i], sizeof(cur_op)); | ||
|
||
if (cur_op[0] == '-') { | ||
switch (cur_op[1]) { | ||
case 'p': | ||
case 'P': | ||
arg.port = cur_op[2] - '0'; | ||
break; | ||
case 'm': | ||
case 'M': | ||
arg.mode = cur_op[2] - '0'; | ||
break; | ||
|
||
case 'w': | ||
case 'W': | ||
arg.is_write = 1; | ||
break; | ||
|
||
case 'r': | ||
case 'R': | ||
arg.is_write = 0; | ||
break; | ||
|
||
default: | ||
break; | ||
} | ||
} else { | ||
// parse data | ||
j = 0; | ||
while (1) { | ||
if (cur_op[j] == 0) { | ||
// string end | ||
break; | ||
} else { | ||
if (is_hex_string(cur_op[j]) < 0) { | ||
break; | ||
} else { | ||
arg.data[k] = arg.data[k] << 4; | ||
arg.data[k] += is_hex_string(cur_op[j]); | ||
} | ||
j++; | ||
} | ||
} | ||
k++; | ||
k &= 3; | ||
} | ||
} | ||
|
||
// parse result | ||
printf("\r\nmode: %d", arg.mode); | ||
printf("\r\nis_write: %d", arg.is_write); | ||
printf("\r\nslave address:0x%02x", arg.data[0]); | ||
printf("\r\nreg_addr: 0x%08x", arg.data[1]); | ||
if (arg.is_write) | ||
printf("\r\nreg_data: 0x%08x", arg.data[2]); | ||
else { | ||
printf("\r\nlen: 0x%08x", arg.data[2]); | ||
} | ||
printf("\r\n"); | ||
} | ||
|
||
return ret; | ||
} | ||
|
||
int main(int argc, char *argv[]) { | ||
if (parse_arg(argc, argv)) | ||
return 0; | ||
|
||
i2c_ext_init(arg.port); | ||
if (arg.is_write) { | ||
i2c_write_ext(arg.mode, arg.data[0], arg.data[1], arg.data[2]); | ||
i2c_read_ext(arg.mode, arg.data[0], arg.data[1]); | ||
printf("\r\n"); | ||
} else { | ||
|
||
if (arg.data[2] == 0) { | ||
arg.data[2] = 1; | ||
} | ||
|
||
for (int i = 0; i < arg.data[2]; i++) { | ||
i2c_read_ext(arg.mode, arg.data[0], (arg.data[1] + i)); | ||
} | ||
printf("\r\n"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#pragma once | ||
#include "stdbool.h" | ||
#include <stdint.h> | ||
|
||
typedef enum { | ||
A8D8 = 0, | ||
A8D16 = 1, | ||
A8D24 = 2, | ||
A8D32 = 3, | ||
A16D8 = 4, | ||
A16D16 = 5, | ||
A16D24 = 6, | ||
A16D32 = 7, | ||
} i2c_ext_mode_t; | ||
|
||
typedef struct { | ||
uint8_t port; | ||
i2c_ext_mode_t mode; | ||
bool is_write; | ||
uint32_t data[3]; | ||
} arg_t; |