Browse Source

ls2k add gpio i2c.

Change-Id: I3002486c9ab9347a0537a14168487a1f5a74b0e3
Signed-off-by: Chong Qiao <qiaochong@loongson.cn>
master
Chong Qiao 3 years ago
parent
commit
3e47be73bc
  1. 2
      Targets/LS2K/conf/files.LS2K
  2. 86
      Targets/LS2K/dev/gpio.c
  3. 435
      Targets/LS2K/dev/i2c-gpio.c

2
Targets/LS2K/conf/files.LS2K

@ -41,6 +41,8 @@ file sys/dev/nand/spinand_mt29f.c spinand_mt29f & nand needs-flag
file sys/dev/nand/spinand_lld.c spinand_lld & nand needs-flag
file sys/dev/nand/m25p80.c m25p80 & nand needs-flag
file Targets/LS2K/dev/i2c.c i2c
file Targets/LS2K/dev/i2c-gpio.c i2cgpio
file Targets/LS2K/dev/gpio.c i2cgpio
file Targets/LS2K/dev/9022a.c sii9022a needs-flag
file Targets/LS2K/dev/lt8168.c lt8168s needs-flag
file Targets/LS2K/dev/can_test.c can

86
Targets/LS2K/dev/gpio.c

@ -0,0 +1,86 @@
#include <sys/linux/types.h>
#include <asm/errno.h>
#define GPIO_IO_CONF(x) ((int)0xbfe10500 + 0)
#define GPIO_OUT(x) ((int)0xbfe10500 + 0x10)
#define GPIO_IN(x) ((int)0xbfe10500 + 0x20)
#define GPIO_INTEN(x) ((int)0xbfe10500 + 0x30)
#define readq(x) (*(volatile unsigned long long *)(x))
#define writeq(v, x) (*(volatile unsigned long long *)(x) = (v))
static inline void
__set_direction(unsigned pin, int input)
{
u64 u;
u = readq(GPIO_IO_CONF(lgpio));
if (input)
u |= 1ULL << pin;
else
u &= ~(1ULL << pin);
writeq(u, GPIO_IO_CONF(lgpio));
}
static void __set_level(unsigned pin, int high)
{
u64 u;
u = readq(GPIO_OUT(lgpio));
if (high)
u |= 1ULL << pin;
else
u &= ~(1ULL << pin);
writeq(u, GPIO_OUT(lgpio));
}
/*
* GPIO primitives.
*/
int ls2_gpio_request(unsigned pin)
{
if (pin >= 64)
return -EINVAL;
else
return 0;
}
int ls2_gpio_direction_input(unsigned pin)
{
__set_direction(pin, 1);
return 0;
}
int ls2_gpio_get(unsigned pin)
{
u64 val;
if (readq(GPIO_IO_CONF(lgpio)) & (1ULL << pin))
val = readq(GPIO_IN(lgpio));
else
val = readq(GPIO_OUT(lgpio));
return (val >> pin) & 1;
}
int ls2_gpio_direction_output(unsigned pin, int value)
{
__set_level(pin, value);
__set_direction(pin, 0);
return 0;
}
void ls2_gpio_set(unsigned pin, int value)
{
__set_level(pin, value);
}
int ls2_gpio_inten(unsigned int pin, int value)
{
u64 inten = readq(GPIO_INTEN(pin));
if(value) inten |= (1ULL<<pin);
else inten &= ~(1ULL<<pin);
writeq(inten, GPIO_INTEN(pin));
return 0;
}

435
Targets/LS2K/dev/i2c-gpio.c

@ -0,0 +1,435 @@
/*
* (C) Copyright 2015, Samsung Electronics
* Przemyslaw Marczak <p.marczak@samsung.com>
*
* This file is based on: drivers/i2c/soft-i2c.c,
* with added driver-model support and code cleanup.
*/
#include <pmon.h>
#include <linux/types.h>
#include <asm/errno.h>
#include "target/ls2k.h"
typedef unsigned char uchar ;
typedef int bool;
#define debug(fmt, args...) //printf(fmt, ##args)
static inline void udelay(unsigned long us)
{
delay(us);
}
/* All transfers are described by this data structure */
struct i2c_msg {
u16 addr; /* slave address */
u16 flags;
#define I2C_M_TEN 0x0010 /* this is a ten bit chip address */
#define I2C_M_RD 0x0001 /* read data, from slave to master */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
u16 len; /* msg length */
u8 *buf; /* pointer to msg data */
};
#define DEFAULT_UDELAY 5
#define RETRIES 0
#define I2C_ACK 0
#define I2C_NOACK 1
enum {
PIN_SDA = 0,
PIN_SCL,
PIN_COUNT,
};
struct i2c_gpio_bus {
/**
* udelay - delay [us] between GPIO toggle operations,
* which is 1/4 of I2C speed clock period.
*/
int udelay;
/* sda, scl */
int pin_sda, pin_scl;
int (*get_sda)(struct i2c_gpio_bus *bus);
void (*set_sda)(struct i2c_gpio_bus *bus, int bit);
void (*set_scl)(struct i2c_gpio_bus *bus, int bit);
};
static int i2c_gpio_sda_get(struct i2c_gpio_bus *bus)
{
ls2_gpio_direction_input(bus->pin_sda);
return ls2_gpio_get(bus->pin_sda);
}
static void i2c_gpio_sda_set(struct i2c_gpio_bus *bus, int bit)
{
ls2_gpio_direction_output(bus->pin_sda, bit);
}
static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
{
ls2_gpio_direction_output(bus->pin_scl, bit);
}
static void i2c_gpio_write_bit(struct i2c_gpio_bus *bus, int delay, uchar bit)
{
bus->set_scl(bus, 0);
udelay(delay);
bus->set_sda(bus, bit);
udelay(delay);
bus->set_scl(bus, 1);
udelay(2 * delay);
}
static int i2c_gpio_read_bit(struct i2c_gpio_bus *bus, int delay)
{
int value;
bus->set_scl(bus, 1);
udelay(delay);
value = bus->get_sda(bus);
udelay(delay);
bus->set_scl(bus, 0);
udelay(2 * delay);
return value;
}
/* START: High -> Low on SDA while SCL is High */
static void i2c_gpio_send_start(struct i2c_gpio_bus *bus, int delay)
{
udelay(delay);
bus->set_sda(bus, 1);
udelay(delay);
bus->set_scl(bus, 1);
udelay(delay);
bus->set_sda(bus, 0);
udelay(delay);
}
/* STOP: Low -> High on SDA while SCL is High */
static void i2c_gpio_send_stop(struct i2c_gpio_bus *bus, int delay)
{
bus->set_scl(bus, 0);
udelay(delay);
bus->set_sda(bus, 0);
udelay(delay);
bus->set_scl(bus, 1);
udelay(delay);
bus->set_sda(bus, 1);
udelay(delay);
}
/* ack should be I2C_ACK or I2C_NOACK */
static void i2c_gpio_send_ack(struct i2c_gpio_bus *bus, int delay, int ack)
{
i2c_gpio_write_bit(bus, delay, ack);
bus->set_scl(bus, 0);
udelay(delay);
}
/**
* Send a reset sequence consisting of 9 clocks with the data signal high
* to clock any confused device back into an idle state. Also send a
* <stop> at the end of the sequence for belts & suspenders.
*/
static void i2c_gpio_send_reset(struct i2c_gpio_bus *bus, int delay)
{
int j;
for (j = 0; j < 9; j++)
i2c_gpio_write_bit(bus, delay, 1);
i2c_gpio_send_stop(bus, delay);
}
/* Set sda high with low clock, before reading slave data */
static void i2c_gpio_sda_high(struct i2c_gpio_bus *bus, int delay)
{
bus->set_scl(bus, 0);
udelay(delay);
bus->set_sda(bus, 1);
udelay(delay);
}
/* Send 8 bits and look for an acknowledgement */
static int i2c_gpio_write_byte(struct i2c_gpio_bus *bus, int delay, uchar data)
{
int j;
int nack;
for (j = 0; j < 8; j++) {
i2c_gpio_write_bit(bus, delay, data & 0x80);
data <<= 1;
}
udelay(delay);
/* Look for an <ACK>(negative logic) and return it */
i2c_gpio_sda_high(bus, delay);
nack = i2c_gpio_read_bit(bus, delay);
return nack; /* not a nack is an ack */
}
/**
* if ack == I2C_ACK, ACK the byte so can continue reading, else
* send I2C_NOACK to end the read.
*/
static uchar i2c_gpio_read_byte(struct i2c_gpio_bus *bus, int delay, int ack)
{
int data;
int j;
i2c_gpio_sda_high(bus, delay);
data = 0;
for (j = 0; j < 8; j++) {
data <<= 1;
data |= i2c_gpio_read_bit(bus, delay);
}
i2c_gpio_send_ack(bus, delay, ack);
return data;
}
/* send start and the slave chip address */
int i2c_send_slave_addr(struct i2c_gpio_bus *bus, int delay, uchar chip)
{
i2c_gpio_send_start(bus, delay);
if (i2c_gpio_write_byte(bus, delay, chip)) {
i2c_gpio_send_stop(bus, delay);
return -EIO;
}
return 0;
}
static int i2c_gpio_write_data(struct i2c_gpio_bus *bus, uchar chip,
uchar *buffer, int len,
bool end_with_repeated_start)
{
unsigned int delay = bus->udelay;
int failures = 0;
debug("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
if (i2c_send_slave_addr(bus, delay, chip << 1)) {
debug("gpio_i2c_write, no chip responded %02X\n", chip);
return -EIO;
}
while (len-- > 0) {
if (i2c_gpio_write_byte(bus, delay, *buffer++))
failures++;
}
if (!end_with_repeated_start) {
i2c_gpio_send_stop(bus, delay);
return failures;
}
if (i2c_send_slave_addr(bus, delay, (chip << 1) | 0x1)) {
debug("gpio_i2c_write, no chip responded %02X\n", chip);
return -EIO;
}
return failures;
}
static int i2c_gpio_read_data(struct i2c_gpio_bus *bus, uchar chip,
uchar *buffer, int len)
{
unsigned int delay = bus->udelay;
debug("%s: chip %x buffer: %p len %d\n", __func__, chip, buffer, len);
while (len-- > 0)
*buffer++ = i2c_gpio_read_byte(bus, delay, len == 0);
i2c_gpio_send_stop(bus, delay);
return 0;
}
static int i2c_gpio_xfer(struct i2c_gpio_bus *bus, struct i2c_msg *msg, int nmsgs)
{
int ret;
for (; nmsgs > 0; nmsgs--, msg++) {
bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
if (msg->flags & I2C_M_RD) {
ret = i2c_gpio_read_data(bus, msg->addr, msg->buf,
msg->len);
} else {
ret = i2c_gpio_write_data(bus, msg->addr, msg->buf,
msg->len, next_is_read);
}
if (ret)
return -EREMOTEIO;
}
return 0;
}
static int i2c_gpio_set_bus_speed(struct i2c_gpio_bus *bus, unsigned int speed_hz)
{
bus->udelay = 1000000 / (speed_hz << 2);
i2c_gpio_send_reset(bus, bus->udelay);
return 0;
}
static struct i2c_gpio_bus i2c_gpio_bus = {
.udelay = 1,
.pin_scl = 18,
.pin_sda = 19,
.get_sda = i2c_gpio_sda_get,
.set_sda = i2c_gpio_sda_set,
.set_scl = i2c_gpio_scl_set,
};
/**
* gpio_i2c_read: - Read multiple bytes from an i2c device
*
* The higher level routines take into account that this function is only
* called with len < page length of the device (see configuration file)
*
* @chip: address of the chip which is to be read
* @addr: i2c data address within the chip
* @alen: length of the i2c data address (1..2 bytes)
* @buffer: where to write the data
* @len: how much byte do we want to read
* @return: 0 in case of success
*/
int gpio_i2c_read(u8 chip, uint addr, int alen, u8 *buffer, int len)
{
struct i2c_msg msg[2] = { { chip, 0, alen, (u8 *)&addr },
{ chip, I2C_M_RD, len, buffer }
};
debug("gpio_i2c_read(chip=0x%02x, addr=0x%02x, alen=0x%02x, len=0x%02x)\n",chip,addr,alen,len);
i2c_gpio_xfer(&i2c_gpio_bus, msg, 2);
return 0;
}
/**
* gpio_i2c_write: - Write multiple bytes to an i2c device
*
* The higher level routines take into account that this function is only
* called with len < page length of the device (see configuration file)
*
* @chip: address of the chip which is to be written
* @addr: i2c data address within the chip
* @alen: length of the i2c data address (1..2 bytes)
* @buffer: where to find the data to be written
* @len: how much byte do we want to read
* @return: 0 in case of success
*/
int gpio_i2c_write(u8 chip, uint addr, int alen, u8 *buffer, int len)
{
struct i2c_msg msg[2] = { { chip, 0, alen, (u8 *)&addr },
{ chip, I2C_M_NOSTART, len, buffer }
};
debug("gpio_i2c_write(chip=0x%02x, addr=0x%02x, alen=0x%02x, len=0x%02x)\n",chip,addr,alen,len);
i2c_gpio_xfer(&i2c_gpio_bus, msg, 2);
return 0;
}
union commondata{
unsigned char data1;
unsigned short data2;
unsigned int data4;
unsigned int data8[2];
unsigned char c[8];
};
extern unsigned int syscall_addrtype;
extern int (*syscall1)(int type,long long addr,union commondata *mydata);
extern int (*syscall2)(int type,long long addr,union commondata *mydata);
static int syscall_i2c_addrlen;
static char syscall_i2c_chip;
static int syscall_i2c_addrlen;
static int gpio_i2c_read_syscall(int type,long long addr,union commondata *mydata)
{
char c;
switch(type)
{
case 1:
gpio_i2c_read(syscall_i2c_chip, addr, syscall_i2c_addrlen, &mydata->data1, 1);
break;
default: return -1;break;
}
return 0;
}
static int gpio_i2c_write_syscall(int type,long long addr,union commondata *mydata)
{
char c;
switch(type)
{
case 1:
gpio_i2c_write(syscall_i2c_chip, addr, syscall_i2c_addrlen, &mydata->data1, 1);
break;
default: return -1;break;
}
return 0;
}
//----------------------------------------
static int gpio_i2cs(int argc,char **argv)
{
volatile int bus;
if(argc<2)
return -1;
bus=strtoul(argv[1],0,0);
syscall_i2c_chip = strtoul(argv[2],0,0);
syscall_i2c_addrlen = argc>3?strtoul(argv[3],0,0):1;
#if !I2C1_SELGPIO
/*i2c1 as gpio*/
*(volatile int *)0xbfe10420 &= ~(1<<11);
#endif
syscall1=(void*)gpio_i2c_read_syscall;
syscall2=(void*)gpio_i2c_write_syscall;
syscall_addrtype=0;
return 0;
}
static const Cmd Cmds[] =
{
{"MyCmds"},
{"gpio_i2cs","bus chip [alen]", 0, "test i2c", gpio_i2cs, 0, 99, CMD_REPEAT},
{0, 0}
};
static void init_cmd __P((void)) __attribute__ ((constructor));
static void init_cmd()
{
cmdlist_expand(Cmds, 1);
}
Loading…
Cancel
Save