This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

This is how to read/write CPLD registers on DM6467T

Other Parts Discussed in Thread: TVP5147

Thanks to advice from Brijesh Jadav Norman Wong, I figured out how to read and write CPLD registers on my DM6467T EVM derived custom board.  This was especially critical since I had overloaded meaning into some [newly] unused bits in Reg0 or Reg1 of the CPLD, and I needed to read and write them to make my board do its thing.

Background on how I got to this point can be found at
"How do I call function in board-dm646x-evm from user space?" http://e2e.ti.com/support/embedded/f/354/p/103153/366125.aspx#366125

I wanted to keep things simple as well as keep to a minimum my footprint of changed files in the kernel source.  Therefore, I added one .h for share between kernel source and application source, plus only added code to the bottom of board-dm6467t-evm.c, rather than creating a new .c for the kernel.  Below are three code snippets as described alongside.  Note that "MYB" is an acronym for my new board.   (Sorry, but forum quote mechanism eating my blank lines, so code not as readable as should be.)

myb.h said:

 

// CPLD Reg0

#define MYB_SYS_RESET_IPHY BIT(2)

// CPLD Reg1

#define MYB_NTSC_RST BIT(0)
#define MYB_NTSC_PWD BIT(1)

#define CPLDREGS_IOCTL_DISABLE_INTERNET_PHY _IOW('x', 0x71, unsigned char)
#define CPLDREGS_IOCTL_ENABLE_INTERNET_PHY _IOW('x', 0x72, unsigned char)
#define CPLDREGS_IOCTL_DISABLE_VIDEO_IN _IOW('x', 0x73, unsigned char)
#define CPLDREGS_IOCTL_ENABLE_VIDEO_IN _IOW('x', 0x74, unsigned char)
#define CPLDREGS_GET_REGS _IOW('x', 0x75, unsigned char)
#define CPLDREGS_SET_REGS _IOR('x', 0x76, unsigned char)
// for CPLDREGS_GET_REGS & CPLDREGS_SET_REGS, where Reg1 and higher are offset higher in long, and so bit numbers must be offset as well
#define CPLDREGS_SYS_RESET_IPHY BIT(2) // CPLD Reg0 
#define CPLDREGS_NTSC_RST BIT(8+0) // CPLD Reg1
#define CPLDREGS_NTSC_PWD BIT(8+1) // CPLD Reg1
#define CPLDREGS_REG2_LSBIT BIT(16+0) // CPLD Reg2 - future use
#define CPLDREGS_REG3_LSBIT BIT(24+0) // CPLD Reg3 - future use

add to bottom of board-dm6467t-evm.c said:

 

/*-----------------------------------------------------------------------------
Extensions for device driver for reading/writing CPLD registers
-------------------------------------------------------------------------------*/
// USAGE:
//
// From application code:
// int fd;
// if (0 > (fd = open("/dev/cpldregs", O_RDWR))) {
// perror("open /dev/cpldregs");
// exit(EXIT_FAILURE);
// }
// ioctl(fd, args...);
// close(fd);
//
#define DRIVERNAME "cpldregs"
#define cpldregs_MAX_SIZE (2)
static dev_t cpldregs_devno;
static struct class *cpldregs_class;
struct device *pdev;
struct cdev cpldregs_cdev;
static int cpldregs_open(struct inode *inode, struct file *fp)
{
//printk(KERN_NOTICE "cpldregs_open()\n");
// Nothing to do, claim success
return(0);
}
static int cpldregs_release(struct inode *inode, struct file *fp)
{
//printk(KERN_NOTICE "cpldregs_release()\n");
// Nothing to do, claim success
return(0);
}
#include "myb/myb.h" // git/arch/arm/mach-davinci/include/myb/myb.h
static long cpldregs_ioctl(struct file *fd, unsigned int code, unsigned long arg)
{
long status = 0;
u8 data;
struct i2c_msg msg0[2] = { // For Reg0
{
.addr = cpld_reg0_client->addr,
.flags = I2C_M_RD,
.len = 1,
.buf = &data,
},
{
.addr = cpld_reg0_client->addr,
.flags = 0,
.len = 1,
.buf = &data,
},
};
struct i2c_msg msg1[2] = { // For Reg1
{
.addr = cpld_client->addr,
.flags = I2C_M_RD,
.len = 1,
.buf = &data,
},
{
.addr = cpld_client->addr,
.flags = 0,
.len = 1,
.buf = &data,
},
};
//printk(KERN_NOTICE "cpldregs_ioctl(,%d,%ld)\n",code,arg);
switch(code) {
case CPLDREGS_IOCTL_DISABLE_INTERNET_PHY: // Forces SYS_RESETn signal low, which disables Internet PHY chip, thus reducing current consumption
i2c_transfer(cpld_reg0_client->adapter, msg0, 1); // HgF doc: read existing value of Reg0
data |= MYB_SYS_RESET_IPHY; // HgF doc: in this case, set the bit which causes SYS_RESETn to go low
i2c_transfer(cpld_reg0_client->adapter, msg0 + 1, 1); // HgF doc: write revised value of Reg0
break;
case CPLDREGS_IOCTL_ENABLE_INTERNET_PHY: // Forces SYS_RESETn signal high, which enables Internet PHY chip, thus increasing current consumption
i2c_transfer(cpld_reg0_client->adapter, msg0, 1); // HgF doc: read existing value of Reg0
data &= ~MYB_SYS_RESET_IPHY; // HgF doc: in this case, clear the bit which causes SYS_RESETn to go high
i2c_transfer(cpld_reg0_client->adapter, msg0 + 1, 1); // HgF doc: write revised value of Reg0
break;
case CPLDREGS_IOCTL_DISABLE_VIDEO_IN: // Forces NTSC_PWD (TVP5147_PWD) signal high, which disable video input chip
i2c_transfer(cpld_client->adapter, msg1, 1); // HgF doc: read existing value of Reg0
data |= MYB_NTSC_PWD; // HgF doc: in this case, set the bit which causes NTSC_PWD (TVP5147_PWD) to go high
i2c_transfer(cpld_client->adapter, msg1 + 1, 1); // HgF doc: write revised value of Reg0
break;
case CPLDREGS_IOCTL_ENABLE_VIDEO_IN: // Forces NTSC_PWD (TVP5147_PWD) signal low, which enables video input chip
i2c_transfer(cpld_client->adapter, msg1, 1); // HgF doc: read existing value of Reg0
data &= ~MYB_NTSC_PWD; // HgF doc: in this case, clear the bit which causes NTSC_PWD (TVP5147_PWD) to go low
i2c_transfer(cpld_client->adapter, msg1 + 1, 1); // HgF doc: write revised value of Reg0
break;
case CPLDREGS_GET_REGS: // Return CPLD register values, concatenated into one long as Reg1:Reg0.  Can support up to Reg3:Reg2:Reg1:Reg0, where Reg0 is least significant byte
status = 0;
i2c_transfer(cpld_reg0_client->adapter, msg0, 1); // HgF doc: read existing value of Reg0
status |= (data & 0xFF); // HgF Add in this register byte
i2c_transfer(cpld_client->adapter, msg1, 1); // HgF doc: read existing value of Reg1
status |= ((data & 0xFF) << 8); // HgF Add in this register byte
break;
case CPLDREGS_SET_REGS: // Set CPLD register values, concatenated into one long as Reg1:Reg0.  Can support up to Reg3:Reg2:Reg1:Reg0, where Reg0 is least significant byte
// DANGEROUS!!!!!!!!!!!!!  BE SURE TO CPLDREGS_GET_REGS FIRST, MODIFY, THEN WRITE HERE
// DANGEROUS!!!!!!!!!!!!!  NOTE IN FUTURE, THERE MAY BE LIVE READ-ONLY (STATUS) BITS IN REGS, SO NEED TO NOT CHANGE THEM INAPPROPRIATELY. // (Perhaps code CPLD Regs as follows.  Mix live writable bits with mirrors of read-only bits, so if read-only bit gets written, mirroring will soon correct)
data = (arg & 0xFF); // HgF Isolate Reg0 from least significant byte position
i2c_transfer(cpld_reg0_client->adapter, msg0 + 1, 1); // HgF doc: write revised value of Reg0
data = ((arg>>8) & 0xFF); // HgF Isolate Reg1 from least significant byte position
i2c_transfer(cpld_client->adapter, msg1 + 1, 1); // HgF doc: write revised value of Reg1
break;
}
return(status);
}
struct file_operations cpldregs_fops = {
.owner = THIS_MODULE,
.open = cpldregs_open,
.unlocked_ioctl = cpldregs_ioctl,
.release = cpldregs_release,
}
MODULE_DESCRIPTION("CPLD Regs Driver");
static int __init cpldregs_module_init(void)
{
int status;
//printk(KERN_NOTICE /*KERN_NOTICE*/ "cpldregs_module_init called\n");
cpldregs_class = class_create(THIS_MODULE, DRIVERNAME);
if (IS_ERR(cpldregs_class)) {
status = PTR_ERR(cpldregs_class);
printk(KERN_ERR "unable to create cpldregs class %d\n", status);
return status;
}
status = alloc_chrdev_region(&cpldregs_devno, 0, 1, DRIVERNAME);
if (status) {
printk(KERN_ERR "alloc_chrdev_region %d\n", status);
class_destroy(cpldregs_class);
return status;
}
/* Setup the sysfs files for the printer gadget. HgF: Is it /sys/... or /dev/cpldregs that's created here? */
pdev = device_create(cpldregs_class, NULL, cpldregs_devno, NULL, DRIVERNAME);
if (IS_ERR(pdev)) {
printk(KERN_ERR "Failed to create device: %s\n", DRIVERNAME);
return status;
}
/*
* Register a character device as an interface to a user mode
* program that handles the printer specific functionality.
*/
cdev_init(&cpldregs_cdev, &cpldregs_fops); // cpldregs_fops registered here
cpldregs_cdev.owner = THIS_MODULE;
status = cdev_add(&cpldregs_cdev, cpldregs_devno, 1);
if (status) {
printk(KERN_ERR "Failed to open char device\n");
return status;
}
//printk(KERN_NOTICE /*KERN_NOTICE*/ "cpldregs_module_init SUCCESS\n");
return status;
}
module_init(cpldregs_module_init);
static void __exit cpldregs_cleanup(void)
{
/* Remove sysfs files */
device_destroy(cpldregs_class, cpldregs_devno);
/* Remove Character Device */
cdev_del(&cpldregs_cdev);
class_destroy(cpldregs_class);
unregister_chrdev_region(cpldregs_devno, 1);
}
module_exit(cpldregs_cleanup);

 

test code snippet for application (user space) said:

 

int fd;
long regs;
#include "MYB.h" // git/arch/arm/mach-davinci/include/MYB/MYB.h
if (0 > (fd = open("/dev/cpldregs", O_RDWR))) {
printf("Error %d (%s) opening /dev/cpldregs\n", errno, strerror(errno));
exit(EXIT_FAILURE);
}
regs = ioctl(fd, CPLDREGS_GET_REGS, 0);
printf("\nRead CPLD Regs = %08lx (%02x:%02x:%02x:%02x)\n",regs,((int)(regs>>24)&0xFF),(int)((regs>>18)&0xFF),(int)((regs>>8)&0xFF),(int)(regs&0xFF));
printf("\nSet Reg0 0x31 bits..."); 
regs |= 0x31;
ioctl(fd, CPLDREGS_SET_REGS, regs);
regs = ioctl(fd, CPLDREGS_GET_REGS, 0);
printf("\nRead CPLD Regs = %08lx (%02x:%02x:%02x:%02x)\n",regs,((int)(regs>>24)&0xFF),(int)((regs>>18)&0xFF),(int)((regs>>8)&0xFF),(int)(regs&0xFF));
printf("\nSet Reg1 0x02 bit..."); 
regs |= 0x0200;
ioctl(fd, CPLDREGS_SET_REGS, regs);
regs = ioctl(fd, CPLDREGS_GET_REGS, 0);
printf("\nRead CPLD Regs = %08lx (%02x:%02x:%02x:%02x)\n",regs,((int)(regs>>24)&0xFF),(int)((regs>>18)&0xFF),(int)((regs>>8)&0xFF),(int)(regs&0xFF));
printf("\nClear Reg1 0x02 bit, Clear Reg0 0x31 bits..."); 
regs &= ~(0x0231);
ioctl(fd, CPLDREGS_SET_REGS, regs);
regs = ioctl(fd, CPLDREGS_GET_REGS, 0);
printf("\nRead CPLD Regs = %08lx (%02x:%02x:%02x:%02x)\n",regs,((int)(regs>>24)&0xFF),(int)((regs>>18)&0xFF),(int)((regs>>8)&0xFF),(int)(regs&0xFF));
printf("\nDisable Video In..."); 
ioctl(fd, CPLDREGS_IOCTL_DISABLE_VIDEO_IN, 0);
regs = ioctl(fd, CPLDREGS_GET_REGS, 0);
printf("\nRead CPLD Regs = %08lx (%02x:%02x:%02x:%02x)\n",regs,((int)(regs>>24)&0xFF),(int)((regs>>18)&0xFF),(int)((regs>>8)&0xFF),(int)(regs&0xFF));
printf("\nEnable Video In..."); 
ioctl(fd, CPLDREGS_IOCTL_ENABLE_VIDEO_IN, 0);
regs = ioctl(fd, CPLDREGS_GET_REGS, 0);
printf("\nRead CPLD Regs = %08lx (%02x:%02x:%02x:%02x)\n",regs,((int)(regs>>24)&0xFF),(int)((regs>>18)&0xFF),(int)((regs>>8)&0xFF),(int)(regs&0xFF));
close(fd);