*/
/*!
* @file ad5669.c
*
* @brief AD5669 voltage-output DAC driver
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#define AD5669_IOCTL_WRITE_DA _IOW(0, 1, unsigned long)
#define AD5669_CMD_WRITE_INPUT_N 0x0
#define AD5669_CMD_UPDATE_DAC_N 0x1
#define AD5669_CMD_WRITE_INPUT_N_UPDATE_ALL 0x2
#define AD5669_CMD_WRITE_INPUT_N_UPDATE_N 0x3
#define AD5669_CMD_POWERDOWN_DAC 0x4
#define AD5669_CMD_CLEAR 0x5
#define AD5669_CMD_LDAC_MASK 0x6
#define AD5669_CMD_RESET 0x7
#define AD5669_CMD_CONFIG 0x8
static struct {
struct i2c_client *i2c_client;
struct class *ad5669_class;
int major;
} ad5669_data;
static int ad5669_probe(struct i2c_client *adapter, const struct i2c_device_id *id);
static int ad5669_remove(struct i2c_client *client);
static const struct i2c_device_id ad5669_id[] = {
{"ad5669", 0},
{},
};
MODULE_DEVICE_TABLE(i2c, ad5669_id);
static struct i2c_driver ad5669_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "ad5669",
},
.probe = ad5669_probe,
.remove = __devexit_p(ad5669_remove),
.id_table = ad5669_id,
};
static int ad5669_write_reg(u8 command, u16 val)
{
char data[3];
data[0] = command;
data[1] = val >> 8;
data[2] = val & 0xff;
if (i2c_master_send(ad5669_data.i2c_client, data, 3) < 0) {
dev_err(&ad5669_data.i2c_client->dev,
"%s: write reg error: command = 0x%02X, val = 0x%04X\n", __func__,
command, val);
return -EIO;
}
return 0;
}
static ssize_t ad5669_read(struct file *file, char __user *buf, size_t len,
loff_t *ppos)
{
return 0;
}
static ssize_t ad5669_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
return 0;
}
static int ad5669_open(struct inode *inode, struct file *file)
{
return 0;
}
static int ad5669_release(struct inode *inode, struct file *file)
{
return 0;
}
static int ad5669_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int ret = 0, channel;
u16 value;
pr_debug("ioctl cmd %d is issued...\n", cmd);
switch (cmd) {
case AD5669_IOCTL_WRITE_DA:
channel = arg >> 16;
value = arg & 0xffff;
if ((channel > 7) && (channel != 15)) {
ret = -EINVAL;
break;
}
ret = ad5669_write_reg((AD5669_CMD_WRITE_INPUT_N_UPDATE_N << 4) | channel, value);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static const struct file_operations ad5669_fops = {
.owner = THIS_MODULE,
.read = ad5669_read,
.write = ad5669_write,
.open = ad5669_open,
.release = ad5669_release,
.ioctl = ad5669_ioctl,
};
static int ad5669_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int ret = 0;
struct device *dev;
dev_dbg(&ad5669_data.i2c_client->dev,
"%s:ad5669 probe i2c address is 0x%02X \n",
__func__, ad5669_data.i2c_client->addr);
ad5669_data.i2c_client = client;
ad5669_data.major = 0;
ret = register_chrdev(ad5669_data.major, "ad5669", &ad5669_fops);
if (ret < 0)
return ret;
if (ad5669_data.major == 0) {
ad5669_data.major = ret;
printk(KERN_INFO "AD5669: major number %d\n", ad5669_data.major);
}
/* create class and device for udev information */
ad5669_data.ad5669_class = class_create(THIS_MODULE, "ad5669");
if (IS_ERR(ad5669_data.ad5669_class)) {
dev_err(&client->dev, "AD5669: failed to create ad5669 class\n");
goto char_dev_remove;
}
dev = device_create(ad5669_data.ad5669_class, NULL,
MKDEV(ad5669_data.major, 0), NULL, "ad5669");
if (IS_ERR(dev)) {
dev_err(&client->dev,
"AD5669: failed to create class device\n");
goto class_remove;
}
return 0;
class_remove:
class_destroy(ad5669_data.ad5669_class);
char_dev_remove:
unregister_chrdev(ad5669_data.major, "ad5669");
return -ENODEV;
}
static int ad5669_remove(struct i2c_client *client)
{
device_destroy(ad5669_data.ad5669_class, MKDEV(ad5669_data.major, 0));
class_destroy(ad5669_data.ad5669_class);
unregister_chrdev(ad5669_data.major, "ad5669");
return 0;
}
static __init int ad5669_init(void)
{
u8 err = 0;
dev_dbg(&ad5669_data.i2c_client->dev, "In ad5669_init\n");
/* Tells the i2c driver what functions to call for this driver. */
err = i2c_add_driver(&ad5669_i2c_driver);
if (err != 0)
pr_err("%s:driver registration failed, error=%d \n",
__func__, err);
return err;
}
static void __exit ad5669_exit(void)
{
dev_dbg(&ad5669_data.i2c_client->dev, "In ad5669_exit\n");
i2c_del_driver(&ad5669_i2c_driver);
}
module_init(ad5669_init);
module_exit(ad5669_exit);
MODULE_AUTHOR("Electronics, Inc");
MODULE_DESCRIPTION("AD5669 voltage-output DAC driver");
MODULE_LICENSE("GPL");