diff options
| author | Bernard Xiong <[email protected]> | 2017-09-06 15:52:47 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2017-09-06 15:52:47 +0800 |
| commit | 646102a1d42e645478294fa194ba55086ae1ecae (patch) | |
| tree | 837a8c58c6a009ef66ab645b92afc82edd14328e /bsp | |
| parent | 080ea89b2b1b10e811e905c2a983b1e4102c78db (diff) | |
| parent | 8d908671821bad9136be1bc5cbc3c5dbd966541c (diff) | |
Merge pull request #840 from caogos/master
[BSP] Add I2C driver for Loongson 1C.
Diffstat (limited to 'bsp')
| -rw-r--r-- | bsp/ls1cdev/libraries/ls1c_gpio.c | 7 | ||||
| -rw-r--r-- | bsp/ls1cdev/libraries/ls1c_i2c.c | 373 | ||||
| -rw-r--r-- | bsp/ls1cdev/libraries/ls1c_i2c.h | 134 | ||||
| -rw-r--r-- | bsp/ls1cdev/libraries/ls1c_public.c | 22 | ||||
| -rw-r--r-- | bsp/ls1cdev/libraries/ls1c_public.h | 16 | ||||
| -rw-r--r-- | bsp/ls1cdev/libraries/ls1c_regs.h | 5 |
6 files changed, 555 insertions, 2 deletions
diff --git a/bsp/ls1cdev/libraries/ls1c_gpio.c b/bsp/ls1cdev/libraries/ls1c_gpio.c index d0f0633b4e..ee073b7c4b 100644 --- a/bsp/ls1cdev/libraries/ls1c_gpio.c +++ b/bsp/ls1cdev/libraries/ls1c_gpio.c @@ -211,8 +211,8 @@ unsigned int gpio_get(unsigned int gpio) */ void gpio_set_irq_type(unsigned int gpio, gpio_irq_type_t type) { - volatile unsigned int *int_pol; // �жϼ���ѡ��Ĵ��� - volatile unsigned int *int_edge; // �жϱ���ѡ��Ĵ��� + volatile unsigned int *int_pol = NULL; // �жϼ���ѡ��Ĵ��� + volatile unsigned int *int_edge = NULL; // �жϱ���ѡ��Ĵ��� unsigned int port = GPIO_GET_PORT(gpio); unsigned int pin = GPIO_GET_PIN(gpio); @@ -257,6 +257,9 @@ void gpio_set_irq_type(unsigned int gpio, gpio_irq_type_t type) *int_pol &= ~(1 << pin); *int_edge &= ~(1 << pin); break; + + default: + break; } return ; diff --git a/bsp/ls1cdev/libraries/ls1c_i2c.c b/bsp/ls1cdev/libraries/ls1c_i2c.c new file mode 100644 index 0000000000..6a1622471c --- /dev/null +++ b/bsp/ls1cdev/libraries/ls1c_i2c.c @@ -0,0 +1,373 @@ +/* + * File : ls1c_i2c.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-09-06 ��Ϊ�� first version + */ + +// ��װӲ��i2c�ӿ� + + +#include "ls1c_public.h" +#include "ls1c_regs.h" +#include "ls1c_clock.h" +#include "ls1c_i2c.h" +#include "ls1c_delay.h" + + + +/* + * I2C�����Ĵ�����Ի���ַ��ƫ�� + * �������ݼĴ����ͽ������ݼĴ�����ƫ������ͬ�� + * ����Ĵ�����״̬�Ĵ�����ƫ������ͬ�ģ���ͬ��������Ĵ���ֻд��״̬�Ĵ���ֻ�� + */ +#define LS1C_I2C_PRER_LOW_OFFSET (0) // ��Ƶ���������ֽڼĴ���ƫ�� +#define LS1C_I2C_PRER_HIGH_OFFSET (1) // ��Ƶ���������ֽڼĴ���ƫ�� +#define LS1C_I2C_CONTROL_OFFSET (2) // ���ƼĴ���ƫ�� +#define LS1C_I2C_DATA_OFFSET (3) // �������ݼĴ����ͽ������ݼĴ�����ƫ������ͬ�� +#define LS1C_I2C_CMD_OFFSET (4) // ����Ĵ���ƫ�ƣ�ֻд +#define LS1C_I2C_STATUS_OFFSET (4) // ״̬�Ĵ���ƫ�ƣ�ֻ�� + + +// ���ƼĴ�����λ�� +#define LS1C_I2C_CONTROL_EN (0x80) // i2cģ��ʹ�� +#define LS1C_I2C_CONTROL_IEN (0x40) // �ж�ʹ�� + +// ����Ĵ�����λ�� +#define LS1C_I2C_CMD_START (0x90) // ����START�ź� +#define LS1C_I2C_CMD_STOP (0x40) // ����STOP�ź� +#define LS1C_I2C_CMD_READ (0x20) // �������źţ�������ACK�ź� +#define LS1C_I2C_CMD_WRITE (0x10) // ����д�ź� +#define LS1C_I2C_CMD_READ_ACK (0x20) // ����ACK�źţ�����ź���ͬ +#define LS1C_I2C_CMD_READ_NACK (0x28) // ����NACK�ź� +#define LS1C_I2C_CMD_IACK (0x00) // �����ж�Ӧ���ź� + +// ״̬�Ĵ�����λ�� +#define LS1C_I2C_STATUS_IF (0x01) // �жϱ�־λ +#define LS1C_I2C_STATUS_TIP (0x02) // ָʾ����Ĺ��̡�1�����ڴ��䣻0��������� +#define LS1C_I2C_STATUS_ARBLOST (0x20) // I2C��ʧȥI2C���ߵĿ���Ȩ +#define LS1C_I2C_STATUS_BUSY (0x40) // I2C����æ��־ +#define LS1C_I2C_STATUS_NACK (0x80) // Ӧ��λ��־��1��û�յ�Ӧ��λ��0���յ�Ӧ��λ + + +/* + * ��ȡָ��i2cģ��Ļ���ַ + * @I2Cx I2Cģ��ı�� + */ +void *i2c_get_base(ls1c_i2c_t I2Cx) +{ + void *base = NULL; + + switch (I2Cx) + { + case LS1C_I2C_0: + base = (void *)LS1C_I2C0_BASE; + break; + + case LS1C_I2C_1: + base = (void *)LS1C_I2C1_BASE; + break; + + case LS1C_I2C_2: + base = (void *)LS1C_I2C2_BASE; + break; + + default: + base = NULL; + break; + } + + return base; +} + + +/* + * ������Ĵ���д���� + * @i2c_info_p i2cģ����Ϣ + * @cmd ���� + */ +void i2c_cmd(ls1c_i2c_info_t *i2c_info_p, unsigned char cmd) +{ + void *i2c_base = i2c_get_base(i2c_info_p->I2Cx); + + reg_write_8(cmd, i2c_base + LS1C_I2C_CMD_OFFSET); + + return ; +} + + +/* + * ִ��START�������START�ź� + * @i2c_info_p i2cģ����Ϣ + */ +void i2c_cmd_start(ls1c_i2c_info_t *i2c_info_p) +{ + i2c_cmd(i2c_info_p, LS1C_I2C_CMD_START); + return ; +} + + +/* + * ִ��STOP�������STOP�ź� + * @i2c_info_p i2cģ����Ϣ + */ +void i2c_cmd_stop(ls1c_i2c_info_t *i2c_info_p) +{ + i2c_cmd(i2c_info_p, LS1C_I2C_CMD_STOP); + return ; +} + + +/* + * ִ��д���� + * @i2c_info_p i2cģ����Ϣ + */ +void i2c_cmd_write(ls1c_i2c_info_t *i2c_info_p) +{ + i2c_cmd(i2c_info_p, LS1C_I2C_CMD_WRITE); + return ; +} + + +/* + * ִ�ж�ack������Ͷ�ack�ź� + * @i2c_info_p i2cģ����Ϣ + */ +void i2c_cmd_read_ack(ls1c_i2c_info_t *i2c_info_p) +{ + i2c_cmd(i2c_info_p, LS1C_I2C_CMD_READ_ACK); + return ; +} + + +/* + * ִ�ж�nack����,���Ͷ�nack�ź� + * @i2c_info_p i2cģ����Ϣ + */ +void i2c_cmd_read_nack(ls1c_i2c_info_t *i2c_info_p) +{ + i2c_cmd(i2c_info_p, LS1C_I2C_CMD_READ_NACK); + return ; +} + + +/* + * �����ж�Ӧ���ź� + * @i2c_info_p i2cģ����Ϣ + */ +void i2c_cmd_iack(ls1c_i2c_info_t *i2c_info_p) +{ + i2c_cmd(i2c_info_p, LS1C_I2C_CMD_IACK); + return ; +} + + +/* + * ��ȡ״̬�Ĵ�����ֵ + * @i2c_info_p i2cģ����Ϣ + * @ret ״̬�Ĵ�����ֵ + */ +unsigned char i2c_get_status(ls1c_i2c_info_t *i2c_info_p) +{ + void *i2c_base = i2c_get_base(i2c_info_p->I2Cx); + + return reg_read_8(i2c_base + LS1C_I2C_STATUS_OFFSET); +} + + +/* + * Poll the i2c status register until the specified bit is set. + * Returns 0 if timed out (100 msec). + * @i2c_info_p i2cģ����Ϣ + * @bit �Ĵ�����ijһλ + * @ret true or false + */ +int i2c_poll_status(ls1c_i2c_info_t *i2c_info_p, unsigned long bit) +{ + int loop_cntr = 20000; + + do { + delay_us(1); + } while ((i2c_get_status(i2c_info_p) & bit) && (0 < --loop_cntr)); + + return (0 < loop_cntr); +} + + +/* + * ��ʼ��ָ��i2cģ�� + * @i2c_info_p ij��i2cģ�����Ϣ + */ +void i2c_init(ls1c_i2c_info_t *i2c_info_p) +{ + void *i2c_base = i2c_get_base(i2c_info_p->I2Cx); + unsigned long i2c_clock = i2c_info_p->clock; + unsigned char ctrl = reg_read_8(i2c_base + LS1C_I2C_CONTROL_OFFSET); + unsigned long prescale = 0; + + /* make sure the device is disabled */ + ctrl = ctrl & ~(LS1C_I2C_CONTROL_EN | LS1C_I2C_CONTROL_IEN); + reg_write_8(ctrl, i2c_base + LS1C_I2C_CONTROL_OFFSET); + + // ����ʱ�� + i2c_clock = MIN(i2c_clock, LS1C_I2C_CLOCK_MAX); // ���������������Χ�� + prescale = clk_get_apb_rate(); + prescale = (prescale / (5 * i2c_clock)) - 1; + reg_write_8(prescale & 0xff, i2c_base + LS1C_I2C_PRER_LOW_OFFSET); + reg_write_8(prescale >> 8, i2c_base + LS1C_I2C_PRER_HIGH_OFFSET); + + // ʹ�� + i2c_cmd_iack(i2c_info_p); + ctrl = ctrl | LS1C_I2C_CONTROL_EN; + reg_write_8(ctrl, i2c_base + LS1C_I2C_CONTROL_OFFSET); + + return ; +} + + +/* + * (�ٷ���һ���ֽ�����֮��)���մӻ����͵�ACK�ź� + * @i2c_info_p i2cģ����Ϣ + * @ret LS1C_I2C_ACK or LS1C_I2C_NACK + */ +ls1c_i2c_ack_t i2c_receive_ack(ls1c_i2c_info_t *i2c_info_p) +{ + ls1c_i2c_ack_t ret = LS1C_I2C_NACK; + + if (LS1C_I2C_STATUS_NACK & i2c_get_status(i2c_info_p)) + { + ret = LS1C_I2C_NACK; + } + else + { + ret = LS1C_I2C_ACK; + } + + return ret; +} + + +/* + * �������� + * @i2c_info_p i2cģ����Ϣ + * @buf ���ݻ��� + * @len ���������ݵij��� + */ +ls1c_i2c_ret_t i2c_receive_data(ls1c_i2c_info_t *i2c_info_p, unsigned char *buf, int len) +{ + void *i2c_base = i2c_get_base(i2c_info_p->I2Cx); + int i = 0; + + for (i=0; i<len; i++) + { + // ��ʼ���� + if (i != (len - 1)) + i2c_cmd_read_ack(i2c_info_p); + else + i2c_cmd_read_nack(i2c_info_p); + + // �ȴ���ֱ��������� + if (!i2c_poll_status(i2c_info_p, LS1C_I2C_STATUS_TIP)) + return LS1C_I2C_RET_TIMEOUT; + + // ��ȡ���ݣ������� + *buf++ = reg_read_8(i2c_base + LS1C_I2C_DATA_OFFSET); + } + + return LS1C_I2C_RET_OK; +} + + +/* + * ����START�źź͵�ַ + * @i2c_info_p i2cģ����Ϣ + * @slave_addr �ӻ���ַ + * @direction ���ݴ��䷽��(����д) + */ +ls1c_i2c_ret_t i2c_send_start_and_addr(ls1c_i2c_info_t *i2c_info_p, + unsigned char slave_addr, + ls1c_i2c_direction_t direction) +{ + void *i2c_base = i2c_get_base(i2c_info_p->I2Cx); + unsigned char data = 0; + + // �ȴ�i2c���߿��� + if (!i2c_poll_status(i2c_info_p, LS1C_I2C_STATUS_BUSY)) + return LS1C_I2C_RET_TIMEOUT; + + // ����ַ�����ݼĴ��� + data = (slave_addr << 1) | ((LS1C_I2C_DIRECTION_READ == direction) ? 1 : 0); + reg_write_8(data , i2c_base + LS1C_I2C_DATA_OFFSET); + + // ��ʼ���� + i2c_cmd_start(i2c_info_p); + + // �ȴ���ֱ��������� + if (!i2c_poll_status(i2c_info_p, LS1C_I2C_STATUS_TIP)) + return LS1C_I2C_RET_TIMEOUT; + + return LS1C_I2C_RET_OK; +} + + +/* + * �������� + * @i2c_info_p i2cģ����Ϣ + * @data �����͵����� + * @len ���������ݵij��� + */ +ls1c_i2c_ret_t i2c_send_data(ls1c_i2c_info_t *i2c_info_p, unsigned char *data, int len) +{ + void *i2c_base = i2c_get_base(i2c_info_p->I2Cx); + int i = 0; + + for (i=0; i<len; i++) + { + // ��һ���ֽ�����д�����ݼĴ��� + reg_write_8(*data++, i2c_base + LS1C_I2C_DATA_OFFSET); + + // ��ʼ���� + reg_write_8(LS1C_I2C_CMD_WRITE, i2c_base + LS1C_I2C_CMD_OFFSET); + + // �ȴ���ֱ��������� + if (!i2c_poll_status(i2c_info_p, LS1C_I2C_STATUS_TIP)) + return LS1C_I2C_RET_TIMEOUT; + + // ��ȡӦ���ź� + if (LS1C_I2C_ACK != i2c_receive_ack(i2c_info_p)) + return len; + } + + return LS1C_I2C_RET_OK; +} + + + +/* + * ����STOP�ź� + * @i2c_info_p i2cģ����Ϣ + */ +void i2c_send_stop(ls1c_i2c_info_t *i2c_info_p) +{ + i2c_cmd_stop(i2c_info_p); + return ; +} + + diff --git a/bsp/ls1cdev/libraries/ls1c_i2c.h b/bsp/ls1cdev/libraries/ls1c_i2c.h new file mode 100644 index 0000000000..ada22242fb --- /dev/null +++ b/bsp/ls1cdev/libraries/ls1c_i2c.h @@ -0,0 +1,134 @@ +/* + * File : ls1c_i2c.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006 - 2012, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2017-09-06 ��Ϊ�� first version + */ + + +// Ӳ��i2c�ӿڵ�ͷ�ļ� + +#ifndef __OPENLOONGSON_I2C_H +#define __OPENLOONGSON_I2C_H + + + +// I2C��ʱ��Ƶ�� +#define LS1C_I2C_CLOCK_DEFAULT (100000) // Hz. Ĭ��Ƶ�� +#define LS1C_I2C_CLOCK_MAX (400000) // Hz, max 400 Kbits/sec + + +// I2Cģ���� +typedef enum +{ + LS1C_I2C_0 = 0, + LS1C_I2C_1, + LS1C_I2C_2 +}ls1c_i2c_t; + + +// I2C���ݴ��䷽�� +typedef enum +{ + LS1C_I2C_DIRECTION_WRITE = 0, // ������ӻ�д��Ϣ + LS1C_I2C_DIRECTION_READ, // ������ӻ�����Ϣ +}ls1c_i2c_direction_t; + + +// Ӳ��I2C��Ϣ +typedef struct +{ + ls1c_i2c_t I2Cx; // i2cģ���� + unsigned long clock; // i2cʱ��Ƶ�ʣ���λhz +}ls1c_i2c_info_t; + + +// I2CӦ�� +typedef enum +{ + LS1C_I2C_ACK = 0, // �յ�Ӧ�� + LS1C_I2C_NACK = 1, // û�յ�Ӧ�� +}ls1c_i2c_ack_t; + + +// ��������ֵ +typedef enum +{ + LS1C_I2C_RET_OK = 0, // OK + LS1C_I2C_RET_TIMEOUT, // ��ʱ +}ls1c_i2c_ret_t; + + + +/* + * ��ʼ��ָ��i2cģ�� + * @i2c_info_p ij��i2cģ�����Ϣ + */ +void i2c_init(ls1c_i2c_info_t *i2c_info_p); + + +/* + * (�ٷ���һ���ֽ�����֮��)���մӻ����͵�ACK�ź� + * @i2c_info_p i2cģ����Ϣ + * @ret LS1C_I2C_ACK or LS1C_I2C_NACK + */ +ls1c_i2c_ack_t i2c_receive_ack(ls1c_i2c_info_t *i2c_info_p); + + +/* + * �������� + * @i2c_info_p i2cģ����Ϣ + * @buf ���ݻ��� + * @len ���������ݵij��� + */ +ls1c_i2c_ret_t i2c_receive_data(ls1c_i2c_info_t *i2c_info_p, unsigned char *buf, int len); + + + +/* + * ����START�źź͵�ַ + * @i2c_info_p i2cģ����Ϣ + * @slave_addr �ӻ���ַ + * @direction ���ݴ��䷽��(����д) + */ +ls1c_i2c_ret_t i2c_send_start_and_addr(ls1c_i2c_info_t *i2c_info_p, + unsigned char slave_addr, + ls1c_i2c_direction_t direction); + + +/* + * �������� + * @i2c_info_p i2cģ����Ϣ + * @data �����͵����� + * @len ���������ݵij��� + */ +ls1c_i2c_ret_t i2c_send_data(ls1c_i2c_info_t *i2c_info_p, unsigned char *data, int len); + + +/* + * ����STOP�ź� + * @i2c_info_p i2cģ����Ϣ + */ +void i2c_send_stop(ls1c_i2c_info_t *i2c_info_p); + + + +#endif + diff --git a/bsp/ls1cdev/libraries/ls1c_public.c b/bsp/ls1cdev/libraries/ls1c_public.c index 84518f0bd0..a04f68a877 100644 --- a/bsp/ls1cdev/libraries/ls1c_public.c +++ b/bsp/ls1cdev/libraries/ls1c_public.c @@ -55,6 +55,28 @@ unsigned int reg_get_bit(volatile unsigned int *reg, unsigned int bit) /* + * ��Ĵ�����д��8bit(һ���ֽ�)���� + * @data ��д������� + * @addr �Ĵ�����ַ + */ +void reg_write_8(unsigned char data, volatile unsigned char *addr) +{ + *addr = data; +} + + +/* + * �ӼĴ�������8bit(һ���ֽ�)���� + * @addr �Ĵ�����ַ + * @ret ���������� + */ +unsigned char reg_read_8(volatile unsigned char *addr) +{ + return (*addr); +} + + +/* * ��Ĵ�����дһ��32bit������ * @data ��д������� * @addr �Ĵ�����ַ diff --git a/bsp/ls1cdev/libraries/ls1c_public.h b/bsp/ls1cdev/libraries/ls1c_public.h index 3ecabeafaa..34164d8c1c 100644 --- a/bsp/ls1cdev/libraries/ls1c_public.h +++ b/bsp/ls1cdev/libraries/ls1c_public.h @@ -58,6 +58,22 @@ unsigned int reg_get_bit(volatile unsigned int *reg, unsigned int bit); /* + * ��Ĵ�����д��8bit(һ���ֽ�)���� + * @data ��д������� + * @addr �Ĵ�����ַ + */ +void reg_write_8(unsigned char data, volatile unsigned char *addr); + + +/* + * �ӼĴ�������8bit(һ���ֽ�)���� + * @addr �Ĵ�����ַ + * @ret ���������� + */ +unsigned char reg_read_8(volatile unsigned char *addr); + + +/* * ��Ĵ�����дһ��32bit������ * @data ��д������� * @addr �Ĵ�����ַ diff --git a/bsp/ls1cdev/libraries/ls1c_regs.h b/bsp/ls1cdev/libraries/ls1c_regs.h index fb67086d34..3d23429865 100644 --- a/bsp/ls1cdev/libraries/ls1c_regs.h +++ b/bsp/ls1cdev/libraries/ls1c_regs.h @@ -111,6 +111,11 @@ #define LS1C_INT4_EDGE (0xbfd010b4) +// I2C�Ĵ��� +#define LS1C_I2C0_BASE (0xbfe58000) +#define LS1C_I2C1_BASE (0xbfe68000) +#define LS1C_I2C2_BASE (0xbfe70000) + #endif |
