267 lines
8.9 KiB
C
Executable File
267 lines
8.9 KiB
C
Executable File
#include <asm/io.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/i2c.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/pm.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/timer.h>
|
|
#include <mach/gpio.h>
|
|
|
|
// mem define
|
|
static unsigned int map_io_base;
|
|
#define D_IO_BASE map_io_base
|
|
#define D_IO_BASE_PHY (0x01c20800)
|
|
#define D_IO_LEN (0x400)
|
|
#define D_IO_A (0)
|
|
#define D_IO_B (1)
|
|
#define D_IO_C (2)
|
|
#define D_IO_D (3)
|
|
#define D_IO_E (4)
|
|
#define D_IO_F (5)
|
|
#define D_IO_G (6)
|
|
#define D_IO_H (7)
|
|
#define D_IO_I (8)
|
|
#define D_IO_CFG0(x) (D_IO_BASE + (x * 0x24) + 0x00)
|
|
#define D_IO_CFG1(x) (D_IO_BASE + (x * 0x24) + 0x04)
|
|
#define D_IO_CFG2(x) (D_IO_BASE + (x * 0x24) + 0x08)
|
|
#define D_IO_CFG3(x) (D_IO_BASE + (x * 0x24) + 0x0c)
|
|
#define D_IO_DAT(x) (D_IO_BASE + (x * 0x24) + 0x10)
|
|
#define D_IO_DRV0(x) (D_IO_BASE + (x * 0x24) + 0x14)
|
|
#define D_IO_DRV1(x) (D_IO_BASE + (x * 0x24) + 0x18)
|
|
#define D_IO_PUL0(x) (D_IO_BASE + (x * 0x24) + 0x1c)
|
|
#define D_IO_PUL1(x) (D_IO_BASE + (x * 0x24) + 0x20)
|
|
|
|
static struct i2c_client *fpga_client = NULL;
|
|
static const struct i2c_device_id i2c_driver_fpga_id[] = {{"i2c_fpga", 0}, {}};
|
|
MODULE_DEVICE_TABLE(i2c, i2c_driver_fpga_id);
|
|
|
|
static unsigned char fpga_refresh_command[] = {0x79, 0x00, 0x00};
|
|
|
|
static unsigned char fpga_none_command[] = {0xff, 0xff, 0xff, 0xff};
|
|
|
|
static const unsigned short i2c_fpga_addr[] = {0x40, I2C_CLIENT_END};
|
|
|
|
static struct delayed_work fpga_reset_work;
|
|
|
|
static struct i2c_msg *i2c_recev_msg;
|
|
static int current_msg_pos;
|
|
|
|
static void fpga_hw_init(void) {
|
|
printk("fpga_loader.c->fpga_hw_init()\n");
|
|
|
|
if (!D_IO_BASE) {
|
|
// printk("Timothy:D_IO_BASE is not initial yet, initial it now\n");
|
|
D_IO_BASE = (unsigned int)ioremap(D_IO_BASE_PHY, D_IO_LEN);
|
|
if (!D_IO_BASE) {
|
|
printk("fpga loader hardware init io error\n");
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// set reset for fpga
|
|
// enable = 1:set ph7 high
|
|
// enable = 0:set ph7 low
|
|
static void set_fpga_reset(int enable) {
|
|
// printk("Timothy:fpga_loader.c->set_fpga_reset()\n");
|
|
if (1 == enable) {
|
|
writel(readl(D_IO_DAT(D_IO_H)) | (1 << 8), D_IO_DAT(D_IO_H));
|
|
} else {
|
|
writel(readl(D_IO_DAT(D_IO_H)) & ~(1 << 8), D_IO_DAT(D_IO_H));
|
|
}
|
|
}
|
|
|
|
int send_to_device(char *data, int count) {
|
|
// //printk("Timothy:fpga_loader.c->send_to_device(), count = %d\n",
|
|
//count);
|
|
int nwrite;
|
|
int i;
|
|
|
|
if (data[0] == 0) // STOP causes this, send stop
|
|
{
|
|
// printk("the data send to device is:");
|
|
// for(i = 1; i < count; i++)
|
|
// {
|
|
// printk("%x ", data[i]);
|
|
// }
|
|
// printk("\n");
|
|
nwrite = i2c_master_send(fpga_client, &data[1], count - 1);
|
|
if (nwrite != count - 1) {
|
|
// printk("Timothy:not write enough, nwrite = %d, count = %d\n",
|
|
// nwrite, count);
|
|
} else {
|
|
// //printk("Timothy:write success, count = %d\n",
|
|
//count);
|
|
}
|
|
return nwrite;
|
|
} else if (data[0] ==
|
|
1) // RESTART causes this, do not send stop, just put int in buf
|
|
{
|
|
if (current_msg_pos >= 8) {
|
|
// printk("Timothy:buf is overflow, quit");
|
|
return -2;
|
|
}
|
|
// //printk("Timothy:the data add to buf is:");
|
|
// for(i = 1; i < count; i++)
|
|
// {
|
|
// printk("%x ", data[i]);
|
|
// }
|
|
// printk("\n");
|
|
i2c_recev_msg[current_msg_pos].addr = i2c_fpga_addr[0];
|
|
i2c_recev_msg[current_msg_pos].len = count - 1;
|
|
i2c_recev_msg[current_msg_pos].buf = (unsigned char *)kzalloc(
|
|
i2c_recev_msg[current_msg_pos].len * sizeof(unsigned char),
|
|
GFP_KERNEL);
|
|
memcpy(i2c_recev_msg[current_msg_pos].buf, &data[1],
|
|
i2c_recev_msg[current_msg_pos].len);
|
|
current_msg_pos++;
|
|
return count - 1;
|
|
} else if (data[0] == 2) {
|
|
// printk("Timothy:send refresh command now\n");
|
|
nwrite = i2c_master_send(fpga_client, fpga_refresh_command, 3);
|
|
return nwrite;
|
|
} else if (data[0] == 3) {
|
|
// printk("Timothy:send none command now\n");
|
|
nwrite = i2c_master_send(fpga_client, fpga_none_command, 4);
|
|
nwrite = i2c_master_send(fpga_client, fpga_none_command, 4);
|
|
return nwrite;
|
|
} else {
|
|
// printk("Timothy:unknow flag for send");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
EXPORT_SYMBOL(send_to_device);
|
|
|
|
int receive_from_device(char *data, int count) {
|
|
// //printk("Timothy:fpga_loader.c->receive_from_device()\n");
|
|
int nread;
|
|
int i, j;
|
|
|
|
if (current_msg_pos >= 8) {
|
|
// printk("Timothy:buf is overflow, quit");
|
|
return -2;
|
|
}
|
|
i2c_recev_msg[current_msg_pos].addr = i2c_fpga_addr[0];
|
|
i2c_recev_msg[current_msg_pos].flags = I2C_M_RD | I2C_M_NO_RD_ACK;
|
|
i2c_recev_msg[current_msg_pos].len = count;
|
|
i2c_recev_msg[current_msg_pos].buf = data;
|
|
current_msg_pos++;
|
|
|
|
// //printk("Timothy:the data send before read is:");
|
|
// for(i = 0; i < current_msg_pos-1; i++)
|
|
// {
|
|
// for(j = 0; j < i2c_recev_msg[i].len; j++)
|
|
// {
|
|
// printk("%x ", i2c_recev_msg[i].buf[j]);
|
|
// }
|
|
// }
|
|
// printk("\n");
|
|
|
|
nread = i2c_transfer(fpga_client->adapter, i2c_recev_msg, current_msg_pos);
|
|
|
|
if (nread != current_msg_pos) {
|
|
// printk("Timothy:not read enough, nread = %d, current_msg_pos = %d\n",
|
|
// nread, current_msg_pos);
|
|
} else {
|
|
// //printk("Timothy:read success, current_msg_pos = %d\n",
|
|
//current_msg_pos);
|
|
}
|
|
|
|
// //printk("Timothy:the data read from i2c is:");
|
|
// for(i = 0; i < count; i++)
|
|
// {
|
|
// printk("%x, ", data[i]);
|
|
// }
|
|
// printk("\n");
|
|
for (i = 0; i < current_msg_pos - 1; i++) {
|
|
if (i2c_recev_msg[i].buf) {
|
|
kfree(i2c_recev_msg[i].buf);
|
|
i2c_recev_msg[i].buf = NULL;
|
|
}
|
|
}
|
|
current_msg_pos = 0;
|
|
|
|
return count;
|
|
}
|
|
|
|
EXPORT_SYMBOL(receive_from_device);
|
|
|
|
static int i2c_driver_fpga_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *id) {
|
|
// printk("Timothy:fpga_loader.c->i2c_driver_fpga_probe()\n");
|
|
if ((client->addr == i2c_fpga_addr[0])) {
|
|
fpga_client = client;
|
|
// printk("Timothy:fpga (%x) init ok\n", client->addr);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int i2c_driver_fpga_remove(struct i2c_client *client) {
|
|
// printk("Timothy:fpga_loader.c->i2c_driver_fpga_remove()\n");
|
|
return 0;
|
|
}
|
|
|
|
static int i2c_driver_fpga_detect(struct i2c_client *client,
|
|
struct i2c_board_info *info) {
|
|
// printk("Timothy:fpga_loader.c->i2c_driver_fpga_detect()\n");
|
|
struct i2c_adapter *p_adapter;
|
|
const char *type_name = "i2c_fpga";
|
|
p_adapter = client->adapter;
|
|
// printk("Timothy:adapter->nr = %d\n", p_adapter->nr);
|
|
if (2 == p_adapter->nr) {
|
|
if (info->addr == i2c_fpga_addr[0]) {
|
|
// printk("Timothy:detect fpga (%x) on i2c adapter (%d)\n",
|
|
// info->addr, p_adapter->nr);
|
|
strlcpy(info->type, type_name, I2C_NAME_SIZE);
|
|
return 0;
|
|
}
|
|
}
|
|
return ENODEV;
|
|
}
|
|
|
|
static struct i2c_driver i2c_driver_fpga = {.class = I2C_CLASS_HWMON,
|
|
.probe = i2c_driver_fpga_probe,
|
|
.remove = i2c_driver_fpga_remove,
|
|
.id_table = i2c_driver_fpga_id,
|
|
.driver =
|
|
{
|
|
.name = "i2c_fpga",
|
|
.owner = THIS_MODULE,
|
|
},
|
|
.detect = i2c_driver_fpga_detect,
|
|
.address_list = i2c_fpga_addr};
|
|
|
|
static int __init i2c_driver_fpga_init(void) {
|
|
// printk("Timothy:fpga_loader.c->i2c_driver_fpga_init()\n");
|
|
fpga_hw_init();
|
|
i2c_recev_msg =
|
|
(struct i2c_msg *)kzalloc(8 * sizeof(struct i2c_msg), GFP_KERNEL);
|
|
current_msg_pos = 0;
|
|
|
|
return i2c_add_driver(&i2c_driver_fpga);
|
|
}
|
|
|
|
static void __exit i2c_driver_fpga_exit(void) {
|
|
// printk("Timothy:fpga_loader.c->i2c_driver_fpga_exit()\n");
|
|
if (i2c_recev_msg) {
|
|
kfree(i2c_recev_msg);
|
|
i2c_recev_msg = NULL;
|
|
}
|
|
current_msg_pos = 0;
|
|
i2c_del_driver(&i2c_driver_fpga);
|
|
}
|
|
|
|
module_init(i2c_driver_fpga_init);
|
|
module_exit(i2c_driver_fpga_exit);
|
|
|
|
MODULE_AUTHOR("Timothy");
|
|
MODULE_DESCRIPTION("I2C device fpga loader");
|
|
MODULE_LICENSE("GPL"); |