134 lines
3.2 KiB
C
134 lines
3.2 KiB
C
#include "device/iic.h"
|
|
|
|
static struct list_head head = LIST_HEAD_INIT(head);
|
|
|
|
|
|
static int iic_open(const char *name, struct device **device, void *arg)
|
|
{
|
|
struct iic_device *p;
|
|
int id = name[3] - '0';
|
|
|
|
list_for_each_entry(p, &head, entry) {
|
|
if (p->id == id) {
|
|
*device = &p->dev;
|
|
(*device)->private_data = p;
|
|
if (!p->open_status) {
|
|
if (p->ops->open) {
|
|
p->ops->open(p);
|
|
}
|
|
os_mutex_create(&p->mutex);
|
|
p->open_status = 1;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int iic_read(struct device *device, void *buf, unsigned int len, u32 addr)
|
|
{
|
|
struct iic_device *iic = (struct iic_device *)device->private_data;
|
|
int ret;
|
|
|
|
os_mutex_pend(&iic->mutex, 0);
|
|
ret = iic->ops->read(iic, buf, len);
|
|
os_mutex_post(&iic->mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int iic_write(struct device *device, void *buf, unsigned int len, u32 addr)
|
|
{
|
|
struct iic_device *iic = (struct iic_device *)device->private_data;
|
|
int ret;
|
|
|
|
os_mutex_pend(&iic->mutex, 0);
|
|
ret = iic->ops->write(iic, buf, len);
|
|
os_mutex_post(&iic->mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int __attribute__((weak)) iic_ioctl_ex(struct iic_device *iic, int cmd, int arg)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
static int iic_ioctl(struct device *device, unsigned int cmd, unsigned int arg)
|
|
{
|
|
int ret = 0;
|
|
struct iic_device *iic = (struct iic_device *)device->private_data;
|
|
|
|
if (iic->ops->ioctl) {
|
|
if (cmd == IIC_IOCTL_START) {
|
|
if (!(cpu_in_irq() || cpu_irq_disabled())) {
|
|
os_mutex_pend(&iic->mutex, 0);
|
|
}
|
|
}
|
|
if (!iic_ioctl_ex(iic, cmd, arg)) {
|
|
ret = iic->ops->ioctl(iic, cmd, arg);
|
|
}
|
|
if (cmd == IIC_IOCTL_STOP) {
|
|
if (!(cpu_in_irq() || cpu_irq_disabled())) {
|
|
os_mutex_post(&iic->mutex);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int iic_init(const struct dev_node *node, void *_data)
|
|
{
|
|
int id;
|
|
struct iic_device *iic;
|
|
const struct iic_operations *p;
|
|
const struct iic_platform_data *data = (const struct iic_platform_data *)_data;
|
|
|
|
id = node->name[3] - '0';
|
|
|
|
list_for_each_iic_device_ops(p) {
|
|
if (p->type == data->type) {
|
|
iic = data->p_iic_device;//(struct iic_device *)malloc(sizeof(*iic));
|
|
if (!iic) {
|
|
return -ENOMEM;
|
|
}
|
|
iic->id = id;
|
|
iic->hw = &data->data;
|
|
iic->ops = p;
|
|
iic->open_status = 0;
|
|
list_add(&iic->entry, &head);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int iic_close(struct device *device)
|
|
{
|
|
struct iic_device *iic = (struct iic_device *)device->private_data;
|
|
int ret = 0;
|
|
|
|
os_mutex_pend(&iic->mutex, 0);
|
|
if (iic->ops->close) {
|
|
ret = iic->ops->close(iic);
|
|
}
|
|
os_mutex_del(&iic->mutex, OS_DEL_ALWAYS);
|
|
iic->open_status = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
const struct device_operations iic_dev_ops = {
|
|
.init = iic_init,
|
|
.open = iic_open,
|
|
.read = iic_read,
|
|
.write = iic_write,
|
|
.ioctl = iic_ioctl,
|
|
.close = iic_close,
|
|
};
|
|
|