android13/external/sc16is752/sc16is752.c

401 lines
7.1 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <unistd.h>
#include <linux/spi/spidev.h>
#include <time.h>
#include <getopt.h>
#include <string.h>
#define CHANNEL_A 0x00
#define CHANNEL_B 0x01
#define RHR 0x00 // Recv Holding Register
#define THR 0x00 // Xmit Holding Register
#define IODir 0x0A // I/O P:ins Direction Register
#define IOState 0x0B // I/O Pins State Register
#define IOIntEna 0x0C // I/O Interrupt Enable Register
#define IOCONTROL 0x0E // I/O Pins Control Register
#define IER 0x01 // Interrupt Enable Register
#define FCR 0x02 // FIFO Control Register in WRITE Mode
#define IIR 0x02 // Interrupt Identification Register in READ Mode
#define LCR 0x03 // Line Control Register
#define MCR 0x04 // Modem Control Register
#define LSR 0x05 // Line status Register
#define MSR 0x06 // Modem Status Register
#define SPR 0x07 // ScratchPad Register
#define TCR 0x06 // Transmission Control Register
#define TLR 0x07 // Trigger Level Register
#define TXLVL 0x08 // Xmit FIFO Level Register
#define RXLVL 0x09 // Recv FIFO Level Register
#define EFCR 0x0F // Extra Features Control Register
#define DLL 0x00 // Divisor Latch LSB 0x00
#define DLH 0x01 // Divisor Latch MSB 0x01
#define EFR 0x02
#define FREQ (1843200UL)
#define BAUDRATE 9600
#define CHANNEL CHANNEL_A
#define chreg(reg) (reg << 3 | CHANNEL)
typedef unsigned char u8;
#define I2C 0x11
#define SPI 0x22
// 设备路径
char *device;
// 片选脚
char *cs = "/proc/rp_gpio/gpio4c5";
// 测试字符串
char *tx = "spi or i2c test string";
// 设备类型
u8 type;
// i2c 设备地址
u8 addr = 0x4d;
u8 read_reg(u8 reg);
void open_dev();
void write_reg(u8 reg, u8 val);
void gpio_set(int val);
int fd = -1;
int fd_gpio = -1;
struct timespec delay = {
.tv_sec = 0,
.tv_nsec = 100000
};
static inline u8 available_data()
{
return read_reg(RXLVL);
}
void write_byte(u8 val)
{
u8 lsr;
do{
lsr = read_reg(LSR);
}while((lsr & 0x20) == 0);
write_reg(THR, val);
}
u8 read_byte()
{
return read_reg(RHR);;
}
void test_connect()
{
u8 val;
write_reg(SPR, 0x77);
if((val = read_reg(SPR)) != 0x77){
printf("0x%02x != 0x77\n", val);
printf("connect failed\n");
exit(-1);
}
write_reg(SPR, 0x99);
if((val = read_reg(SPR)) != 0x99){
printf("0x%02x != 0x99\n", val);
printf("connect failed\n");
exit(-2);
}
printf("connect okay\n");
}
u8 read_reg(u8 reg)
{
reg = chreg(reg);
unsigned char val[2];
if(type == I2C){
if (write(fd, &reg, 1) != 1) {
perror("write failed");
exit(-3);
}
if (read(fd, &val[1], 1) != 1) {
perror("read failed");
exit(-4);
}
} else {
u8 buf[] = {0x80 | reg, 0xff};
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)buf,
.rx_buf = (unsigned long)val,
.len = 2,
.delay_usecs = 10,
.bits_per_word = 8,
};
if(ioctl(fd, SPI_IOC_MESSAGE(1), &tr) < 0){
perror("ioctl failed");
exit(-5);
}
}
return val[1];
}
void write_reg(u8 reg, u8 val)
{
reg = chreg(reg);
u8 buf[] = {reg, val};
if(type == I2C){
if (write(fd, buf, 2) != 2) {
perror("Failed to write to the i2c bus.");
exit(-6);
}
} else {
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)buf,
// .rx_buf = (unsigned long)rxval,
.len = 2,
};
if(ioctl(fd, SPI_IOC_MESSAGE(1), &tr) < 0){
perror("ioctl failed");
exit(-7);
}
}
}
void set_baudrate()
{
int prescale = 4;
u8 lcr;
unsigned int div;
if((read_reg(MCR) & 0x80) == 0)
prescale = 1;
div = (FREQ / prescale) / (BAUDRATE * 16);
lcr = read_reg(LCR);
lcr |= 0x80;
write_reg(LCR, lcr);
write_reg(DLL, (u8)div);
write_reg(DLH, (u8)(div >> 8));
lcr &= 0x7f;
write_reg(LCR, lcr);
}
void set_line()
{
u8 lcr;
lcr = read_reg(LCR);
lcr &= 0xC0;
lcr |= 0x03;
write_reg(LCR, lcr);
}
void reset()
{
write_reg(IER, 0x0);
write_reg(IIR, 0x1);
write_reg(FCR, 0x0);
write_reg(LCR, 0x1d);
write_reg(MCR, 0x0);
write_reg(TCR, 0x0);
write_reg(TLR, 0x0);
write_reg(EFCR, 0x0);
read_reg(RHR);
}
void fifo_en()
{
u8 fcr;
fcr = read_reg(FCR);
fcr |= 0x01;
write_reg(FCR, fcr);
}
void fifo_reset()
{
u8 fcr;
fcr = read_reg(FCR);
fcr |= 0x06;
write_reg(FCR, fcr);
}
void init()
{
fifo_en();
fifo_reset();
set_baudrate();
set_line();
}
void write_bytes(char *buf, size_t len)
{
for(int i = 0; i < len; i ++){
write_byte(buf[i]);
}
}
void loop()
{
size_t len = strlen(tx);
write_bytes(tx, len);
while(available_data() > 0){
printf("%c", read_byte());
}
printf("\n");
}
void open_dev()
{
if(type == I2C){
if ((fd = open(device, O_RDWR)) < 0) {
perror("open bus failed\n");
exit(-8);
}
if (ioctl(fd, I2C_SLAVE, addr) < 0) {
close(fd);
perror("failed access i2c dev\n");
exit(-9);
}
}else {
if ((fd = open(device, O_RDWR)) < 0) {
perror("open bus failed");
close(fd_gpio);
exit(-10);
}
u8 mode = SPI_MODE_0;
if (ioctl(fd, SPI_IOC_WR_MODE, &mode) < 0) {
perror("Error setting SPI mode");
close(fd);
close(fd_gpio);
exit(-11);
}
}
}
void usage()
{
puts("usage:");
puts("-d device, such as /dev/spidev0.0 or /dev/i2c-4\n"
"-s string, default is \"spi or i2c test string\"\n"
"\nexample:\n"
"./sc16is752 -d /dev/spidev0.0 -c /proc/rp_gpio/gpio4c5 -s \"TestString\"\n"
"./sc16is752 -d /dev/i2c-4 -s \"TestString\"\n");
exit(-12);
}
void parse_cmd(int argc, char *argv[])
{
static const struct option lopts[] = {
{"device", 1, 0, 'd'}, // 设备节点
{"tx", 1, 0, 's'}, // 传输的字符串
{"cs", 1, 0, 'c'}, // SPI 设备所使用的片选脚
{NULL, 0, 0, 0}
};
while(1){
int c = getopt_long(argc, argv,
"D:c:s:d:b:i:o:vS:I:",
lopts, NULL);
if(c == -1)
break;
switch(c){
case 'd':
device = optarg;
break;
case 'c':
cs = optarg;
break;
case 's':
tx = optarg;
break;
default:
usage();
}
}
if(device == NULL){
printf("device is null\n");
exit(-13);
}
if(strstr(device, "i2c") != NULL)
type = I2C;
else if(strstr(device, "spi") != NULL)
type = SPI;
else {
printf("no i2c or spi device\n");
exit(-14);
}
/* if(type == SPI && cs == NULL){
printf("spi must set gpio pin\n");
exit(-1);
}
*/
}
int main(int argc, char *argv[])
{
parse_cmd(argc, argv);
open_dev();
reset();
test_connect();
init();
loop();
close(fd);
return 0;
}