343 lines
7.2 KiB
C
343 lines
7.2 KiB
C
/*
|
|
* Copyright (c) 2006-2022, RT-Thread Development Team
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Change Logs:
|
|
* 2021-11-19 xieyangrun first version
|
|
*/
|
|
|
|
#include <rthw.h>
|
|
#include <rtdevice.h>
|
|
|
|
#include "sunxi_hal_twi.h"
|
|
|
|
#define DBG_LVL DBG_WARNING
|
|
#define DBG_TAG "drv/i2c"
|
|
#include <rtdbg.h>
|
|
|
|
struct hal_i2c_bus
|
|
{
|
|
struct rt_i2c_bus_device parent;
|
|
twi_port_t id;
|
|
struct rt_mutex lock;
|
|
};
|
|
|
|
//connect am drv to rt drv.
|
|
static rt_ssize_t _i2c_master_xfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg *msgs, rt_uint32_t num)
|
|
{
|
|
struct hal_i2c_bus *_i2c_bus = (struct hal_i2c_bus *)bus;
|
|
struct rt_i2c_msg *msg;
|
|
twi_msg_t *twi_msg;
|
|
int i;
|
|
twi_status_t status;
|
|
extern twi_status_t hal_twi_xfer(twi_port_t port, twi_msg_t *msgs, int32_t num);
|
|
|
|
|
|
twi_msg = rt_malloc(sizeof(*twi_msg) * num);
|
|
if (!twi_msg)
|
|
{
|
|
LOG_E("i2c xfer malloc(%d) failure\n", sizeof(*twi_msg) * num);
|
|
return -RT_ENOMEM;
|
|
}
|
|
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
msg = &msgs[i];
|
|
if (msg->flags == RT_I2C_RD)
|
|
{
|
|
twi_msg[i].flags = TWI_M_RD;
|
|
}
|
|
else if(msg->flags == RT_I2C_WR)
|
|
{
|
|
twi_msg[i].flags = 0;
|
|
}
|
|
|
|
if (_i2c_bus->parent.flags & RT_I2C_DEV_CTRL_10BIT)
|
|
{
|
|
twi_msg[i].flags |= TWI_M_TEN;
|
|
}
|
|
|
|
twi_msg[i].addr = msg->addr;
|
|
twi_msg[i].len = msg->len;
|
|
twi_msg[i].buf = msg->buf;
|
|
}
|
|
|
|
rt_mutex_take(&_i2c_bus->lock, RT_WAITING_FOREVER);
|
|
status = hal_twi_xfer(_i2c_bus->id, twi_msg, i);
|
|
rt_mutex_release(&_i2c_bus->lock);
|
|
|
|
if (status != TWI_STATUS_OK)
|
|
{
|
|
i = 0;
|
|
LOG_E("i2c xfer failure\n");
|
|
}
|
|
|
|
rt_free(twi_msg);
|
|
|
|
return i;
|
|
}
|
|
|
|
static const struct rt_i2c_bus_device_ops _i2c_ops =
|
|
{
|
|
_i2c_master_xfer,
|
|
RT_NULL,
|
|
RT_NULL
|
|
};
|
|
|
|
#ifdef BSP_USING_I2C0
|
|
static struct hal_i2c_bus _i2c_bus_0 = {
|
|
.id = TWI_MASTER_0
|
|
};
|
|
#endif
|
|
|
|
#ifdef BSP_USING_I2C1
|
|
static struct hal_i2c_bus _i2c_bus_1 = {
|
|
.id = TWI_MASTER_1,
|
|
};
|
|
#endif
|
|
|
|
#ifdef BSP_USING_I2C2
|
|
static struct hal_i2c_bus _i2c_bus_2 = {
|
|
.id = TWI_MASTER_2,
|
|
};
|
|
#endif
|
|
|
|
#ifdef BSP_USING_I2C3
|
|
static struct hal_i2c_bus _i2c_bus_3 = {
|
|
.id = TWI_MASTER_3,
|
|
};
|
|
#endif
|
|
|
|
#define CFG_GPIO_PORT(p) ((p) - 'A' + 1)
|
|
|
|
static const user_gpio_set_t _i2c_gpio_cfg[][2] = {
|
|
{// twi0
|
|
{
|
|
.gpio_name = "twi0.sck",
|
|
.port = CFG_GPIO_PORT('B'),
|
|
.port_num = 3, // PB3
|
|
.mul_sel = 4,
|
|
.pull = 1, // pull up
|
|
.drv_level = 3,
|
|
.data = 1,
|
|
},
|
|
{
|
|
.gpio_name = "twi0.sda",
|
|
.port = CFG_GPIO_PORT('B'),
|
|
.port_num = 2, // PB2
|
|
.mul_sel = 4,
|
|
.pull = 1, // pull up
|
|
.drv_level = 3,
|
|
.data = 1,
|
|
}
|
|
},
|
|
{// twi1
|
|
{
|
|
.gpio_name = "twi1.sck",
|
|
.port = CFG_GPIO_PORT('B'),
|
|
.port_num = 4, // PB4
|
|
.mul_sel = 4,
|
|
.pull = 1, // pull up
|
|
.drv_level = 3,
|
|
.data = 1,
|
|
},
|
|
{
|
|
.gpio_name = "twi1.sda",
|
|
.port = CFG_GPIO_PORT('B'),
|
|
.port_num = 5, // PB5
|
|
.mul_sel = 4,
|
|
.pull = 1, // pull up
|
|
.drv_level = 3,
|
|
.data = 1,
|
|
}
|
|
},
|
|
#ifdef BSP_USING_MANGOPI // mango board
|
|
{// twi2
|
|
{
|
|
.gpio_name = "twi2.sck",
|
|
.port = CFG_GPIO_PORT('E'),
|
|
.port_num = 12, // PE12
|
|
.mul_sel = 2,
|
|
.pull = 1, // pull up
|
|
.drv_level = 3,
|
|
.data = 1,
|
|
},
|
|
{
|
|
.gpio_name = "twi2.sda",
|
|
.port = CFG_GPIO_PORT('E'),
|
|
.port_num = 13, // PE13
|
|
.mul_sel = 2,
|
|
.pull = 1, // pull up
|
|
.drv_level = 3,
|
|
.data = 1,
|
|
}
|
|
},
|
|
#elif defined(BSP_USING_M7)
|
|
{// twi2
|
|
{
|
|
.gpio_name = "twi2.sck",
|
|
.port = CFG_GPIO_PORT('G'),
|
|
.port_num = 6, // PG6
|
|
.mul_sel = 3,
|
|
.pull = 1, // pull up
|
|
.drv_level = 3,
|
|
.data = 1,
|
|
},
|
|
{
|
|
.gpio_name = "twi2.sda",
|
|
.port = CFG_GPIO_PORT('G'),
|
|
.port_num = 7, // PG7
|
|
.mul_sel = 3,
|
|
.pull = 1, // pull up
|
|
.drv_level = 3,
|
|
.data = 1,
|
|
}
|
|
},
|
|
#endif
|
|
{// twi3
|
|
{
|
|
.gpio_name = "twi3.sck",
|
|
.port = CFG_GPIO_PORT('B'),
|
|
.port_num = 6, // PB6
|
|
.mul_sel = 4,
|
|
.pull = 1, // pull up
|
|
.drv_level = 3,
|
|
.data = 1,
|
|
},
|
|
{
|
|
.gpio_name = "twi3.sda",
|
|
.port = CFG_GPIO_PORT('B'),
|
|
.port_num = 7, // PB7
|
|
.mul_sel = 4,
|
|
.pull = 1, // pull up
|
|
.drv_level = 3,
|
|
.data = 1,
|
|
}
|
|
},
|
|
};
|
|
|
|
int hal_i2c_gpio_cfg_load(user_gpio_set_t *gpio_cfg, int32_t GPIONum, int id)
|
|
{
|
|
int i;
|
|
|
|
if (id > sizeof(_i2c_gpio_cfg) / sizeof(_i2c_gpio_cfg[0]))
|
|
{
|
|
rt_kprintf("twi id %d>%d\n", id, sizeof(_i2c_gpio_cfg) / sizeof(_i2c_gpio_cfg[0]));
|
|
return -1;
|
|
}
|
|
|
|
/* twi0 */
|
|
for (i = 0; i < GPIONum; i++)
|
|
{
|
|
memcpy(gpio_cfg, &_i2c_gpio_cfg[id][i], sizeof(user_gpio_set_t));
|
|
gpio_cfg++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int _i2c_dev_register(struct hal_i2c_bus* bus, const char* name)
|
|
{
|
|
rt_mutex_init(&bus->lock, name, RT_IPC_FLAG_PRIO);
|
|
|
|
hal_twi_init(bus->id);
|
|
bus->parent.ops = &_i2c_ops;
|
|
|
|
if (rt_i2c_bus_device_register(&bus->parent, name) != RT_EOK)
|
|
{
|
|
LOG_E("i2c bus register:%s failure\n", name);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int rt_hw_i2c_init(void)
|
|
{
|
|
#ifdef BSP_USING_I2C0
|
|
/* init i2c bus device */
|
|
_i2c_dev_register(&_i2c_bus_0, "i2c0");
|
|
#endif
|
|
|
|
#ifdef BSP_USING_I2C1
|
|
/* init i2c bus device */
|
|
_i2c_dev_register(&_i2c_bus_1, "i2c1");
|
|
#endif
|
|
|
|
#ifdef BSP_USING_I2C2
|
|
_i2c_dev_register(&_i2c_bus_2, "i2c2");
|
|
#endif
|
|
|
|
#ifdef BSP_USING_I2C3
|
|
_i2c_dev_register(&_i2c_bus_3, "i2c3");
|
|
#endif
|
|
|
|
//rt_kprintf("i2c_init!\n");
|
|
|
|
return 0;
|
|
}
|
|
// #ifdef RT_USING_COMPONENTS_INIT
|
|
INIT_BOARD_EXPORT(rt_hw_i2c_init);
|
|
// #endif
|
|
|
|
static void _i2c_test(int argc, char *args[])
|
|
{
|
|
struct rt_i2c_bus_device *i2c_bus;
|
|
struct rt_i2c_msg msg[2];
|
|
uint8_t buf[3] = {0x12, 0x34, 0x56};
|
|
|
|
if (argc < 2) return;
|
|
|
|
i2c_bus = (struct rt_i2c_bus_device*)rt_device_find("i2c2");
|
|
if (!i2c_bus)
|
|
{
|
|
rt_kprintf("i2c2 not found\n");
|
|
return;
|
|
}
|
|
|
|
msg[0].addr = 0x36;
|
|
msg[0].flags = 0;
|
|
msg[0].buf = buf;
|
|
msg[0].len = sizeof(buf);
|
|
|
|
msg[1].addr = 0x36;
|
|
msg[1].flags = RT_I2C_RD;
|
|
msg[1].buf = buf;
|
|
msg[1].len = sizeof(buf);
|
|
|
|
if (atoi(args[1]) == 0)
|
|
{
|
|
rt_i2c_transfer(i2c_bus, &msg[0], 1);
|
|
}
|
|
else
|
|
{
|
|
rt_i2c_transfer(i2c_bus, &msg[0], 2);
|
|
}
|
|
}
|
|
MSH_CMD_EXPORT_ALIAS(_i2c_test, i2c_test, i2c bus test);
|
|
|
|
static void _pin_test(void)
|
|
{
|
|
int i;
|
|
rt_base_t pin;
|
|
|
|
pin = GPIO_PE10;
|
|
|
|
rt_pin_mode(pin, PIN_MODE_OUTPUT);
|
|
|
|
for (i = 0; i < 20; i++)
|
|
{
|
|
rt_pin_write(pin, !!(i & 1));
|
|
rt_thread_mdelay(2);
|
|
}
|
|
}
|
|
MSH_CMD_EXPORT_ALIAS(_pin_test, pin_test, gpio pin test);
|
|
|
|
/*@}*/
|
|
|
|
|
|
|
|
|
|
|