mirror of
https://github.com/genesi/linux-legacy.git
synced 2026-07-08 17:56:11 +00:00
This is i.MX BSP 5.0.0 release ported to 2.6.31 Signed-off-by: Rob Herring <r.herring@freescale.com> Signed-off-by: Alan Tull <r80115@freescale.com> Signed-off-by: Xinyu Chen <xinyu.chen@freescale.com>
359 lines
6.5 KiB
C
359 lines
6.5 KiB
C
/*
|
|
* Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
|
|
*/
|
|
|
|
/*
|
|
* The code contained herein is licensed under the GNU General Public
|
|
* License. You may obtain a copy of the GNU General Public License
|
|
* Version 2 or later at the following locations:
|
|
*
|
|
* http://www.opensource.org/licenses/gpl-license.html
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*/
|
|
|
|
#include <linux/fs.h>
|
|
#include <linux/module.h>
|
|
#include <linux/device.h>
|
|
#include <asm/uaccess.h>
|
|
#include "i2c_slave_device.h"
|
|
|
|
int i2c_slave_major;
|
|
|
|
static ssize_t i2c_slave_read(struct file *fd, char __user *buf, size_t len,
|
|
loff_t *ptr)
|
|
{
|
|
i2c_slave_device_t *dev;
|
|
void *kbuf;
|
|
int ret;
|
|
|
|
if (len == 0)
|
|
return 0;
|
|
|
|
kbuf = kmalloc(len, GFP_KERNEL);
|
|
if (!kbuf) {
|
|
ret = -ENOMEM;
|
|
goto error0;
|
|
}
|
|
|
|
dev = (i2c_slave_device_t *) fd->private_data;
|
|
if (!dev) {
|
|
ret = -ENODEV;
|
|
goto error1;
|
|
}
|
|
|
|
ret = i2c_slave_device_read(dev, len, kbuf);
|
|
if (ret <= 0 || copy_to_user(buf, kbuf, len)) {
|
|
ret = -EFAULT;
|
|
}
|
|
|
|
error1:
|
|
kfree(kbuf);
|
|
error0:
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t i2c_slave_write(struct file *fd, const char __user *buf,
|
|
size_t len, loff_t *ptr)
|
|
{
|
|
i2c_slave_device_t *dev;
|
|
void *kbuf;
|
|
int ret;
|
|
|
|
if (len == 0)
|
|
return 0;
|
|
|
|
kbuf = kmalloc(len, GFP_KERNEL);
|
|
if (!kbuf) {
|
|
ret = -ENOMEM;
|
|
goto error0;
|
|
}
|
|
if (copy_from_user(kbuf, buf, len)) {
|
|
ret = -EFAULT;
|
|
goto error1;
|
|
}
|
|
|
|
dev = (i2c_slave_device_t *) fd->private_data;
|
|
if (!dev) {
|
|
ret = -ENODEV;
|
|
goto error1;
|
|
}
|
|
|
|
ret = i2c_slave_device_write(dev, len, (u8 *) kbuf);
|
|
|
|
error1:
|
|
kfree(kbuf);
|
|
error0:
|
|
return ret;
|
|
}
|
|
|
|
static int i2c_slave_ioctl(struct inode *inode, struct file *fd,
|
|
unsigned code, unsigned long value)
|
|
{
|
|
/*todo */
|
|
return 0;
|
|
}
|
|
|
|
static int i2c_slave_open(struct inode *inode, struct file *fd)
|
|
{
|
|
int ret;
|
|
unsigned int id;
|
|
i2c_slave_device_t *dev;
|
|
id = iminor(inode);
|
|
|
|
if (id >= I2C_SLAVE_DEVICE_MAX) {
|
|
ret = -ENODEV;
|
|
goto error;
|
|
}
|
|
|
|
dev = i2c_slave_device_find(id);
|
|
if (!dev) {
|
|
ret = -ENODEV;
|
|
goto error;
|
|
}
|
|
|
|
i2c_slave_rb_clear(dev->receive_buffer);
|
|
i2c_slave_rb_clear(dev->send_buffer);
|
|
|
|
if (i2c_slave_device_start(dev)) {
|
|
ret = -EBUSY;
|
|
goto error;
|
|
}
|
|
|
|
fd->private_data = (void *)dev;
|
|
ret = 0;
|
|
|
|
error:
|
|
return ret;
|
|
}
|
|
|
|
static int i2c_slave_release(struct inode *inode, struct file *fd)
|
|
{
|
|
int ret;
|
|
unsigned int id;
|
|
i2c_slave_device_t *dev;
|
|
id = iminor(inode);
|
|
|
|
if (id >= I2C_SLAVE_DEVICE_MAX) {
|
|
ret = -ENODEV;
|
|
goto error;
|
|
}
|
|
|
|
dev = i2c_slave_device_find(id);
|
|
if (!dev) {
|
|
ret = -ENODEV;
|
|
goto error;
|
|
}
|
|
|
|
if (i2c_slave_device_stop(dev)) {
|
|
ret = -EBUSY;
|
|
goto error;
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
error:
|
|
return ret;
|
|
}
|
|
|
|
static const struct file_operations i2c_slave_fops = {
|
|
.owner = THIS_MODULE,
|
|
.llseek = no_llseek,
|
|
.read = i2c_slave_read,
|
|
.write = i2c_slave_write,
|
|
.ioctl = i2c_slave_ioctl,
|
|
.open = i2c_slave_open,
|
|
.release = i2c_slave_release,
|
|
};
|
|
|
|
static int i2c_slave_bus_match(struct device *dev, struct device_driver *drv)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
static int i2c_slave_bus_probe(struct device *dev)
|
|
{
|
|
struct device_driver *driver = dev->driver;
|
|
|
|
if (driver) {
|
|
return driver->probe(dev);
|
|
} else {
|
|
dev_err(dev, "%s: no driver\n", __func__);
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
*/
|
|
|
|
static int i2c_slave_bus_remove(struct device *dev)
|
|
{
|
|
struct device_driver *driver = dev->driver;
|
|
|
|
if (driver) {
|
|
if (!driver->remove) {
|
|
return 0;
|
|
} else {
|
|
return driver->remove(dev);
|
|
}
|
|
} else {
|
|
|
|
dev_err(dev, "%s: no driver\n", __func__);
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
static void i2c_slave_bus_shutdown(struct device *dev)
|
|
{
|
|
struct device_driver *driver = dev->driver;
|
|
|
|
if (driver) {
|
|
|
|
driver->shutdown(dev);
|
|
} else {
|
|
|
|
dev_err(dev, "%s: no driver\n", __func__);
|
|
return;
|
|
}
|
|
}
|
|
static int i2c_slave_bus_suspend(struct device *dev, pm_message_t state)
|
|
{
|
|
struct device_driver *driver = dev->driver;
|
|
|
|
if (driver) {
|
|
|
|
if (!driver->suspend) {
|
|
return 0;
|
|
} else {
|
|
return driver->suspend(dev, state);
|
|
}
|
|
} else {
|
|
|
|
dev_err(dev, "%s: no driver\n", __func__);
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
static int i2c_slave_bus_resume(struct device *dev)
|
|
{
|
|
struct device_driver *driver = dev->driver;
|
|
|
|
if (driver) {
|
|
|
|
if (!driver->resume) {
|
|
return 0;
|
|
} else {
|
|
return driver->resume(dev);
|
|
}
|
|
} else {
|
|
|
|
dev_err(dev, "%s: no driver\n", __func__);
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
struct bus_type i2c_slave_bus_type = {
|
|
.name = "i2c-slave",
|
|
.match = i2c_slave_bus_match,
|
|
.remove = i2c_slave_bus_remove,
|
|
.shutdown = i2c_slave_bus_shutdown,
|
|
.suspend = i2c_slave_bus_suspend,
|
|
.resume = i2c_slave_bus_resume,
|
|
};
|
|
|
|
EXPORT_SYMBOL_GPL(i2c_slave_bus_type);
|
|
|
|
static int i2c_slave_driver_probe(struct device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int i2c_slave_driver_remove(struct device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int i2c_slave_driver_shutdown(struct device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int i2c_slave_driver_suspend(struct device *dev, pm_message_t state)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int i2c_slave_driver_resume(struct device *dev)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
extern struct class *i2c_slave_class;
|
|
|
|
static struct device_driver i2c_slave_driver = {
|
|
.name = "i2c-slave",
|
|
.owner = THIS_MODULE,
|
|
.bus = &i2c_slave_bus_type,
|
|
.probe = i2c_slave_driver_probe,
|
|
.remove = i2c_slave_driver_remove,
|
|
.shutdown = i2c_slave_driver_shutdown,
|
|
.suspend = i2c_slave_driver_suspend,
|
|
.resume = i2c_slave_driver_resume,
|
|
};
|
|
|
|
static int __init i2c_slave_dev_init(void)
|
|
{
|
|
int ret;
|
|
|
|
printk(KERN_INFO "i2c slave /dev entries driver\n");
|
|
|
|
ret = bus_register(&i2c_slave_bus_type);
|
|
if (ret) {
|
|
printk(KERN_ERR "%s: bus_register error\n", __func__);
|
|
goto out;
|
|
}
|
|
|
|
i2c_slave_class = class_create(THIS_MODULE, "i2c-slave");
|
|
if (IS_ERR(i2c_slave_class)) {
|
|
pr_err("%s: class_create error\n", __func__);
|
|
goto out_unreg_bus;
|
|
}
|
|
|
|
i2c_slave_major = register_chrdev(0, "i2c-slave", &i2c_slave_fops);
|
|
if (i2c_slave_major <= 0) {
|
|
pr_err("%s: register_chrdev error\n", __func__);
|
|
goto out_unreg_class;
|
|
}
|
|
|
|
ret = driver_register(&i2c_slave_driver);
|
|
if (ret) {
|
|
pr_err("%s: driver_register error\n", __func__);
|
|
goto out_unreg_chrdev;
|
|
}
|
|
|
|
return 0;
|
|
|
|
out_unreg_chrdev:
|
|
unregister_chrdev(i2c_slave_major, "i2c-slave");
|
|
out_unreg_class:
|
|
class_destroy(i2c_slave_class);
|
|
out_unreg_bus:
|
|
bus_unregister(&i2c_slave_bus_type);
|
|
out:
|
|
pr_err("%s: init error\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
static void __exit i2c_dev_exit(void)
|
|
{
|
|
driver_unregister(&i2c_slave_driver);
|
|
class_destroy(i2c_slave_class);
|
|
unregister_chrdev(i2c_slave_major, "i2c-slave");
|
|
bus_unregister(&i2c_slave_bus_type);
|
|
}
|
|
|
|
module_init(i2c_slave_dev_init);
|
|
module_exit(i2c_dev_exit);
|
|
|
|
MODULE_AUTHOR("Freescale Semiconductor, Inc.");
|
|
MODULE_DESCRIPTION("I2C Slave Driver Core");
|
|
MODULE_LICENSE("GPL");
|