sonic-buildimage/platform/nephos/sonic-platform-modules-cig/cs6436-56p/modules/x86-64-cig-cs6436-56p-cpld.c
michealylj1 7ed5a92fc0 [Devices] Add new device CIG CS6436-56P (#2587)
* Add new device CIG CS6436-56P

* Delete minigraph.xml

It isn't necessary in the current system, just delete it

* Update qos.json.j2

* Update port_config.ini

Add the speed column. The cmd to show interface status as:

root@switch1:~# show interface status             
  Interface            Lanes    Speed    MTU         Alias    Oper    Admin    Type    Asym PFC
-----------  ---------------  -------  -----  ------------  ------  -------  ------  ----------
  Ethernet0                8      25G   9100   Ethernet1/1      up       up     SFP         N/A
  Ethernet1                9      25G   9100   Ethernet2/1      up       up     SFP         N/A
  Ethernet2               10      25G   9100   Ethernet3/1    down     down     N/A         N/A
  Ethernet3               11      25G   9100   Ethernet4/1    down     down     N/A         N/A
  Ethernet4               12      25G   9100   Ethernet5/1    down     down     N/A         N/A
  Ethernet5               13      25G   9100   Ethernet6/1    down     down     N/A         N/A
  Ethernet6               14      25G   9100   Ethernet7/1    down     down     N/A         N/A
  Ethernet7               15      25G   9100   Ethernet8/1    down     down     N/A         N/A
  Ethernet8               16      25G   9100   Ethernet9/1    down     down     N/A         N/A
  Ethernet9               17      25G   9100  Ethernet10/1    down     down     N/A         N/A
 Ethernet10               18      25G   9100  Ethernet11/1    down     down     N/A         N/A
 Ethernet11               19      25G   9100  Ethernet12/1    down     down     N/A         N/A
 Ethernet12               20      25G   9100  Ethernet13/1    down     down     N/A         N/A
 Ethernet13               21      25G   9100  Ethernet14/1    down     down     N/A         N/A
 Ethernet14               22      25G   9100  Ethernet15/1    down     down     N/A         N/A
 Ethernet15               23      25G   9100  Ethernet16/1    down     down     N/A         N/A
 Ethernet16               32      25G   9100  Ethernet17/1    down     down     N/A         N/A
 Ethernet17               33      25G   9100  Ethernet18/1    down     down     N/A         N/A
 Ethernet18               34      25G   9100  Ethernet19/1    down     down     N/A         N/A
 Ethernet19               35      25G   9100  Ethernet20/1    down     down     N/A         N/A
 Ethernet20               40      25G   9100  Ethernet21/1    down     down     N/A         N/A
 Ethernet21               41      25G   9100  Ethernet22/1    down     down     N/A         N/A
 Ethernet22               42      25G   9100  Ethernet23/1    down     down     N/A         N/A
 Ethernet23               43      25G   9100  Ethernet24/1    down     down     N/A         N/A
 Ethernet24               48      25G   9100  Ethernet25/1    down     down     N/A         N/A
 Ethernet25               49      25G   9100  Ethernet26/1    down     down     N/A         N/A
 Ethernet26               50      25G   9100  Ethernet27/1    down     down     N/A         N/A
 Ethernet27               51      25G   9100  Ethernet28/1    down     down     N/A         N/A
 Ethernet28               56      25G   9100  Ethernet29/1    down     down     N/A         N/A
 Ethernet29               57      25G   9100  Ethernet30/1    down     down     N/A         N/A
 Ethernet30               58      25G   9100  Ethernet31/1    down     down     N/A         N/A
 Ethernet31               59      25G   9100  Ethernet32/1    down     down     N/A         N/A
 Ethernet32               64      25G   9100  Ethernet33/1    down     down     N/A         N/A
 Ethernet33               65      25G   9100  Ethernet34/1    down     down     N/A         N/A
 Ethernet34               66      25G   9100  Ethernet35/1    down     down     N/A         N/A
 Ethernet35               67      25G   9100  Ethernet36/1    down     down     N/A         N/A
 Ethernet36               68      25G   9100  Ethernet37/1    down     down     N/A         N/A
 Ethernet37               69      25G   9100  Ethernet38/1    down     down     N/A         N/A
 Ethernet38               70      25G   9100  Ethernet39/1    down     down     N/A         N/A
 Ethernet39               71      25G   9100  Ethernet40/1    down     down     N/A         N/A
 Ethernet40               72      25G   9100  Ethernet41/1    down     down     N/A         N/A
 Ethernet41               73      25G   9100  Ethernet42/1    down     down     N/A         N/A
 Ethernet42               74      25G   9100  Ethernet43/1    down     down     N/A         N/A
 Ethernet43               75      25G   9100  Ethernet44/1    down     down     N/A         N/A
 Ethernet44               76      25G   9100  Ethernet45/1    down     down     N/A         N/A
 Ethernet45               77      25G   9100  Ethernet46/1    down     down     N/A         N/A
 Ethernet46               78      25G   9100  Ethernet47/1    down     down     N/A         N/A
 Ethernet47               79      25G   9100  Ethernet48/1    down     down     N/A         N/A
 Ethernet48      84,85,86,87     100G   9100  Ethernet49/1      up       up  QSFP28         N/A
 Ethernet49      80,81,82,83     100G   9100  Ethernet50/1      up       up  QSFP28         N/A
 Ethernet50      92,93,94,95     100G   9100  Ethernet51/1    down     down     N/A         N/A
 Ethernet51      88,89,90,91     100G   9100  Ethernet52/1    down     down     N/A         N/A
 Ethernet52  108,109,110,111     100G   9100  Ethernet53/1    down     down     N/A         N/A
 Ethernet53  104,105,106,107     100G   9100  Ethernet54/1    down     down     N/A         N/A
 Ethernet54  116,117,118,119     100G   9100  Ethernet55/1    down     down     N/A         N/A
 Ethernet55  112,113,114,115     100G   9100  Ethernet56/1    down     down     N/A         N/A
root@switch1:~#
2019-04-18 02:27:39 -07:00

1633 lines
38 KiB
C
Executable File

/*
* A hwmon driver for the CIG cs6436-56P CPLD
*
* Copyright (C) 2018 Cambridge, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/wait.h>
#include <linux/isa.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <asm/irq.h>
#include "i2c-algo-lpc.h"
#include "i2c-algo-lpc2iic.h"
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/i2c-mux.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/dmi.h>
#include <linux/dma-mapping.h>
#ifndef CPLD_USER
# include <linux/ioctl.h>
#else
# include <sys/ioctl.h>
#endif
/*
* ISA bus.
*/
static void platform_isa_bus_release(struct device * dev)
{
return ;
}
static struct device isa_bus = {
.init_name = "lpc-isa",
.release = platform_isa_bus_release,
};
struct isa_dev {
struct device dev;
struct device *next;
unsigned int id;
};
#define to_isa_dev(x) container_of((x), struct isa_dev, dev)
static int isa_bus_match(struct device *dev, struct device_driver *driver)
{
struct isa_driver *isa_driver = to_isa_driver(driver);
if (dev->platform_data == isa_driver) {
if (!isa_driver->match ||
isa_driver->match(dev, to_isa_dev(dev)->id))
return 1;
dev->platform_data = NULL;
}
return 0;
}
static int isa_bus_probe(struct device *dev)
{
struct isa_driver *isa_driver = dev->platform_data;
if (isa_driver->probe)
return isa_driver->probe(dev, to_isa_dev(dev)->id);
return 0;
}
static int isa_bus_remove(struct device *dev)
{
struct isa_driver *isa_driver = dev->platform_data;
if (isa_driver->remove)
return isa_driver->remove(dev, to_isa_dev(dev)->id);
return 0;
}
static void isa_bus_shutdown(struct device *dev)
{
struct isa_driver *isa_driver = dev->platform_data;
if (isa_driver->shutdown)
isa_driver->shutdown(dev, to_isa_dev(dev)->id);
}
static int isa_bus_suspend(struct device *dev, pm_message_t state)
{
struct isa_driver *isa_driver = dev->platform_data;
if (isa_driver->suspend)
return isa_driver->suspend(dev, to_isa_dev(dev)->id, state);
return 0;
}
static int isa_bus_resume(struct device *dev)
{
struct isa_driver *isa_driver = dev->platform_data;
if (isa_driver->resume)
return isa_driver->resume(dev, to_isa_dev(dev)->id);
return 0;
}
static struct bus_type isa_bus_type = {
.name = "lpc-isa",
.match = isa_bus_match,
.probe = isa_bus_probe,
.remove = isa_bus_remove,
.shutdown = isa_bus_shutdown,
.suspend = isa_bus_suspend,
.resume = isa_bus_resume
};
static void isa_dev_release(struct device *dev)
{
kfree(to_isa_dev(dev));
}
void lpc_unregister_driver(struct isa_driver *isa_driver)
{
struct device *dev = isa_driver->devices;
while (dev) {
struct device *tmp = to_isa_dev(dev)->next;
device_unregister(dev);
dev = tmp;
}
driver_unregister(&isa_driver->driver);
}
int lpc_register_driver(struct isa_driver *isa_driver, unsigned int ndev)
{
int error;
unsigned int id;
isa_driver->driver.bus = &isa_bus_type;
isa_driver->devices = NULL;
error = driver_register(&isa_driver->driver);
if (error)
return error;
for (id = 0; id < ndev; id++) {
struct isa_dev *isa_dev;
isa_dev = kzalloc(sizeof *isa_dev, GFP_KERNEL);
if (!isa_dev) {
error = -ENOMEM;
break;
}
isa_dev->dev.parent = &isa_bus;
isa_dev->dev.bus = &isa_bus_type;
dev_set_name(&isa_dev->dev, "%s.%u",
isa_driver->driver.name, id);
isa_dev->dev.platform_data = isa_driver;
isa_dev->dev.release = isa_dev_release;
isa_dev->id = id;
isa_dev->dev.coherent_dma_mask = DMA_BIT_MASK(24);
isa_dev->dev.dma_mask = &isa_dev->dev.coherent_dma_mask;
error = device_register(&isa_dev->dev);
if (error) {
put_device(&isa_dev->dev);
break;
}
if (isa_dev->dev.platform_data) {
isa_dev->next = isa_driver->devices;
isa_driver->devices = &isa_dev->dev;
} else
device_unregister(&isa_dev->dev);
}
if (!error && !isa_driver->devices)
error = -ENODEV;
if (error)
isa_unregister_driver(isa_driver);
return error;
}
int lpc_bus_init(void)
{
int error;
error = bus_register(&isa_bus_type);
if (!error) {
error = device_register(&isa_bus);
if (error)
bus_unregister(&isa_bus_type);
}
return error;
}
void lpc_bus_exit(void)
{
device_unregister(&isa_bus);
bus_unregister(&isa_bus_type);
}
/*
* module parameters:
*/
static int i2c_debug = 0;
static struct mutex lpc_lock;
#define DEB2(x) if (i2c_debug >= 2) x
#define DEB3(x) if (i2c_debug >= 3) x
/* print several statistical values */
#define DEBPROTO(x) if (i2c_debug >= 9) x;
/* debug the protocol by showing transferred bits */
#define DEF_TIMEOUT 160
/* setting states on the bus with the right timing: */
#define set_lpc(adap, ctl, val) adap->setlpc(adap->data, ctl, val)
#define get_lpc(adap, ctl) adap->getlpc(adap->data, ctl)
#define get_own(adap) adap->getown(adap->data)
#define get_clock(adap) adap->getclock(adap->data)
#define i2c_outaddr(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DEVICE_ADDR, val)
#define i2c_outbyte1(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DATA_TX1, val)
#define i2c_outbyte2(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DATA_TX2, val)
#define i2c_outbyte3(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DATA_TX3, val)
#define i2c_outbyte4(adap, val) adap->setlpc(adap->data, I2C_LPC_REG_DATA_TX4, val)
#define i2c_inbyte1(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX1)
#define i2c_inbyte2(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX2)
#define i2c_inbyte3(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX3)
#define i2c_inbyte4(adap) adap->getlpc(adap->data, I2C_LPC_REG_DATA_RX4)
#define LPC_FPRINTF_LOG_PATH "/tmp/file.log"
struct file *lpc_fprintf_file = NULL;
static int lpc_fprintf_debug(const char *fmt, ...)
{
char lpc_fprintf_buf[256]={0};
struct va_format vaf;
va_list args;
int r;
unsigned int file_size = 0;
mm_segment_t old_fs;
struct timeval tv;
do_gettimeofday(&tv);
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
r=snprintf(lpc_fprintf_buf,"[%012d.%012d] %pV\n",sizeof(lpc_fprintf_buf),tv.tv_sec, tv.tv_usec, &vaf);
va_end(args);
old_fs = get_fs();
set_fs(KERNEL_DS);
lpc_fprintf_file->f_op->write(lpc_fprintf_file, (char *)lpc_fprintf_buf, strlen(lpc_fprintf_buf), &lpc_fprintf_file->f_pos);
set_fs(old_fs);
memset(lpc_fprintf_buf,0x0,sizeof(lpc_fprintf_buf));
return r;
}
static int lpc_fprintf_init(void)
{
mm_segment_t old_fs;
DEB2(printk("lpc_fprintf_init.\n");)
if(lpc_fprintf_file == NULL)
lpc_fprintf_file = filp_open(LPC_FPRINTF_LOG_PATH, O_RDWR | O_APPEND | O_CREAT, 0644);
if (IS_ERR(lpc_fprintf_file)) {
DEB2(printk("error occured while opening file %s, exiting...\n", LPC_FPRINTF_LOG_PATH);)
return 0;
}
return 0;
}
static int lpc_fprintf_exit(void)
{
DEB2(printk("lpc_fprintf_exit.\n");)
if(lpc_fprintf_file != NULL)
filp_close(lpc_fprintf_file, NULL);
return 0;
}
/* other auxiliary functions */
void print_reg(struct i2c_algo_lpc_data *adap)
{
unsigned char status;
DEBPROTO(lpc_fprintf_debug("================================================\n");)
status = get_lpc(adap, I2C_LPC_REG_BUS_SEL);
DEBPROTO(lpc_fprintf_debug("%s select reg %x : %x\n",__func__,I2C_LPC_REG_BUS_SEL, status);)
status = get_lpc(adap, I2C_LPC_REG_BYTE_COUNT);
DEBPROTO(lpc_fprintf_debug("%s count reg %x : %x\n",__func__,I2C_LPC_REG_BYTE_COUNT, status);)
status = get_lpc(adap, I2C_LPC_REG_COMMAND);
DEBPROTO(lpc_fprintf_debug("%s command reg %x : %x\n",__func__,I2C_LPC_REG_COMMAND, status);)
status = get_lpc(adap, I2C_LPC_REG_DEVICE_ADDR);
DEBPROTO(lpc_fprintf_debug("%s address reg %x : %x\n",__func__,I2C_LPC_REG_DEVICE_ADDR, status);)
status = get_lpc(adap, I2C_LPC_REG_STATUS);
DEBPROTO(lpc_fprintf_debug("%s status reg %x : %x\n",__func__,I2C_LPC_REG_STATUS, status);)
}
static void i2c_repstart(struct i2c_algo_lpc_data *adap)
{
DEBPROTO(lpc_fprintf_debug(" Sr\n"));
set_lpc(adap, I2C_LPC_REG_COMMAND, I2C_LPC_REPSTART);
}
static void i2c_stop(struct i2c_algo_lpc_data *adap)
{
DEBPROTO(lpc_fprintf_debug("%s :\n",__func__);)
set_lpc(adap, I2C_LPC_REG_COMMAND, I2C_LPC_STOP);
udelay(60);
set_lpc(adap, I2C_LPC_REG_COMMAND, 0x00);
}
static void i2c_start(struct i2c_algo_lpc_data *adap)
{
unsigned char status;
int timeout = DEF_TIMEOUT;
print_reg(adap);
set_lpc(adap, I2C_LPC_REG_COMMAND, I2C_LPC_START);
print_reg(adap);
}
static int wait_for_bb(struct i2c_algo_lpc_data *adap)
{
int timeout = DEF_TIMEOUT;
int status;
while (--timeout) {
status = get_lpc(adap, I2C_LPC_REG_STATUS);
DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus free status : %x\n",__func__,status);)
if(status == I2C_LPC_TD)
{
DEBPROTO(lpc_fprintf_debug("%s : Bus is free status : %x\n",__func__,status);)
break;
}
}
if (timeout == 0) {
DEBPROTO(lpc_fprintf_debug("%s : Timeout for free busy status : %x\n",__func__,status);)
return -ETIMEDOUT;
}
return 0;
}
static int wait_for_be(int mode,struct i2c_algo_lpc_data *adap)
{
int timeout = DEF_TIMEOUT;
unsigned char status;
while (--timeout) {
status = get_lpc(adap, I2C_LPC_REG_STATUS);
DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus empty status : %x\n",__func__,status);)
if(mode == 1)
{
if((status & I2C_LPC_IBB) && (status & I2C_LPC_TBE))
{
DEBPROTO(lpc_fprintf_debug("%s : Bus is empty status : %x\n",__func__,status);)
break;
}
}
else
{
if(status & I2C_LPC_TD)
{
DEBPROTO(lpc_fprintf_debug("%s : Bus is empty status : %x\n",__func__,status);)
break;
}
}
status = get_lpc(adap, I2C_LPC_REG_TEST);
DEBPROTO(lpc_fprintf_debug("%s : The test register data : %x\n",__func__,status);)
udelay(1); /* wait for 100 us */
}
if (timeout == 0) {
DEBPROTO(lpc_fprintf_debug("%s : Timeout waiting for Bus Empty\n",__func__);)
return -ETIMEDOUT;
}
return 0;
}
static int wait_for_bf(struct i2c_algo_lpc_data *adap)
{
int timeout = DEF_TIMEOUT;
int status;
while (--timeout) {
status = get_lpc(adap, I2C_LPC_REG_STATUS);
DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus full status : %x\n",__func__,status);)
if(status & I2C_LPC_RBF)
{
DEBPROTO(lpc_fprintf_debug("%s : Bus is full status : %x\n",__func__,status);)
break;
}
status = get_lpc(adap, I2C_LPC_REG_TEST);
DEBPROTO(lpc_fprintf_debug("%s : The test register data : %x\n",__func__,status);)
udelay(1); /* wait for 100 us */
}
if (timeout == 0) {
DEBPROTO(lpc_fprintf_debug("%s : Timeout waiting for Bus Full\n",__func__);)
return -ETIMEDOUT;
}
return 0;
}
static int wait_for_td(struct i2c_algo_lpc_data *adap)
{
int timeout = DEF_TIMEOUT;
int status=0;
while (--timeout) {
udelay(4);
status = get_lpc(adap, I2C_LPC_REG_STATUS);
DEBPROTO(lpc_fprintf_debug("%s : Waiting for bus done status : %x\n",__func__,status);)
if(status == I2C_LPC_TD)
{
DEBPROTO(lpc_fprintf_debug("%s : Bus is done status : %x\n",__func__,status);)
break;
}
}
if (timeout == 0) {
DEBPROTO(lpc_fprintf_debug("%s : Timeout waiting for Bus Done\n",__func__);)
return -ETIMEDOUT;
}
return 0;
}
static int wait_for_pin(struct i2c_algo_lpc_data *adap, int *status)
{
int timeout = DEF_TIMEOUT;
*status = get_lpc(adap, I2C_LPC_REG_STATUS);
while ((*status & I2C_LPC_TBE) && --timeout) {
*status = get_lpc(adap, I2C_LPC_REG_STATUS);
}
if (timeout == 0)
return -ETIMEDOUT;
return 0;
}
static int lpc_doAddress(struct i2c_algo_lpc_data *adap,struct i2c_msg *msg)
{
unsigned short flags = msg->flags;
unsigned char addr;
addr = msg->addr << 1;
if (flags & I2C_M_RD)
{
addr |= 1;
DEBPROTO(lpc_fprintf_debug("step 7 : read mode then write device address 0x%x\n",addr);)
}
else
{
DEBPROTO(lpc_fprintf_debug("step 2 : write mode then write device address 0x%x\n",addr);)
}
if (flags & I2C_M_REV_DIR_ADDR)
{
addr ^= 1;
}
i2c_outaddr(adap, addr);
return 0;
}
static int lpc_sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
struct i2c_algo_lpc_data *adap = i2c_adap->algo_data;
int i = 0,timeout=0;
unsigned int count = msg->len;
unsigned char *buf = msg->buf;
do{
lpc_doAddress(adap,msg);
set_lpc(adap, I2C_LPC_REG_BYTE_COUNT, (count-i) >= 4 ? 4:(count - i));
DEBPROTO(lpc_fprintf_debug("step 3 : write register count %x\n",count);)
if((count -i) >= 4)
{
i2c_outbyte1(adap, buf[i+0] & 0xff);
i2c_outbyte2(adap, buf[i+1] & 0xff);
i2c_outbyte3(adap, buf[i+2] & 0xff);
i2c_outbyte4(adap, buf[i+3] & 0xff);
DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+0,buf[i+0]);)
DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+1,buf[i+1]);)
DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+2,buf[i+2]);)
DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+3,buf[i+3]);)
i += 4;
}
else if((count -i) == 3)
{
i2c_outbyte1(adap, buf[i+0] & 0xff);
i2c_outbyte2(adap, buf[i+1] & 0xff);
i2c_outbyte3(adap, buf[i+2] & 0xff);
DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+0,buf[i+0]);)
DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+1,buf[i+1]);)
DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+2,buf[i+2]);)
i += 3;
}
else if((count -i) == 2)
{
i2c_outbyte1(adap, buf[i+0] & 0xff);
i2c_outbyte2(adap, buf[i+1] & 0xff);
DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+0,buf[i+0]);)
DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+1,buf[i+1]);)
i += 2;
}
else if((count -i) == 1)
{
i2c_outbyte1(adap, buf[i+0] & 0xff);
DEBPROTO(lpc_fprintf_debug("step 4 : Send data[%d] = %x\n",i+0,buf[i+0]);)
i += 1;
}
/* Send START */
DEBPROTO(lpc_fprintf_debug("step 5-1 : Delay 6mS \n");)
udelay(6000);
DEBPROTO(lpc_fprintf_debug("step 5-2 : Start to transfrom \n");)
i2c_stop(adap);
i2c_start(adap);
DEBPROTO(lpc_fprintf_debug("step 5-3 : Start done\n");)
udelay(400);
DEBPROTO(lpc_fprintf_debug("step 6 : Waiting for BE\n");)
timeout = wait_for_td(adap);
if (timeout) {
DEBPROTO(lpc_fprintf_debug("step 6 : Timeout waiting for BE \n");)
return -1;
}
}while (i < count);
if(i == count)
{
DEBPROTO(lpc_fprintf_debug("Writen %d bytes successd !\n",count);)
return i;
}
else
{
DEBPROTO(lpc_fprintf_debug("Writen %d bytes failed \n",count);)
return -1;
}
}
static int lpc_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
int i=0,timeout=0;
struct i2c_algo_lpc_data *adap = i2c_adap->algo_data;
int wfp;
unsigned int count = msg->len;
unsigned char *buf = msg->buf;
do{
lpc_doAddress(adap,msg);
set_lpc(adap, I2C_LPC_REG_BYTE_COUNT, (count-i) >= 4 ? 4:(count - i));
DEBPROTO(lpc_fprintf_debug("step 8 : write register count %d\n",count);)
/* Send START */
DEBPROTO(lpc_fprintf_debug("step 9-1 : Delay 6mS\n");)
udelay(6000);
DEBPROTO(lpc_fprintf_debug("step 9-2 : Start to receive data\n");)
i2c_stop(adap);
i2c_start(adap);
DEBPROTO(lpc_fprintf_debug("step 9-3 : Start done\n");)
udelay(400);
DEBPROTO(lpc_fprintf_debug("step 10 : Waiting for TD\n");)
timeout = wait_for_td(adap);
if (timeout) {
DEBPROTO(lpc_fprintf_debug("step 10 : Timeout waiting for TD \n");)
return -1;
}
if((count -i) >= 4)
{
buf[i+0] = 0xff & i2c_inbyte1(adap);
buf[i+1] = 0xff & i2c_inbyte2(adap);
buf[i+2] = 0xff & i2c_inbyte3(adap);
buf[i+3] = 0xff & i2c_inbyte4(adap);
DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+0,buf[i+0]);)
DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+1,buf[i+1]);)
DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+2,buf[i+2]);)
DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+3,buf[i+3]);)
i += 4;
}
else if((count -i) == 3)
{
buf[i+0] = 0xff & i2c_inbyte1(adap);
buf[i+1] = 0xff & i2c_inbyte2(adap);
buf[i+2] = 0xff & i2c_inbyte3(adap);
DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+0,buf[i+0]);)
DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+1,buf[i+1]);)
DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+2,buf[i+2]);)
i += 3;
}
else if((count -i) == 2)
{
buf[i+0] = 0xff & i2c_inbyte1(adap);
buf[i+1] = 0xff & i2c_inbyte2(adap);
DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+0,buf[i+0]);)
DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+1,buf[i+1]);)
i += 2;
}
else if((count -i) == 1)
{
buf[i+0] = 0xff & i2c_inbyte1(adap);
DEBPROTO(lpc_fprintf_debug("step 11 : Receive data[%d] = %x\n",i+0,buf[i+0]);)
i += 1;
}
}while(i < count);
if(i == count)
{
DEBPROTO(lpc_fprintf_debug("Read %d bytes successd !\n",count);)
return i;
}
else
{
DEBPROTO(lpc_fprintf_debug("Read %d bytes failed \n",count);)
return -1;
}
return i;
}
struct cpld_client_node {
struct i2c_client *client;
struct list_head list;
};
#define LPC_I2C_MAX_NCHANS 6
struct lpc_iic {
struct i2c_adapter *virt_adaps[LPC_I2C_MAX_NCHANS];
u8 last_chan; /* last register value */
};
static int lpc_master_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg *msgs,
int num)
{
struct i2c_algo_lpc_data *adap = i2c_adap->algo_data;
struct i2c_msg *pmsg;
int i;
int ret=0, timeout, status;
mutex_lock(&lpc_lock);
if (adap->xfer_begin)
adap->xfer_begin(&i2c_adap->nr);
for (i = 0;ret >= 0 && i < num; i++) {
pmsg = &msgs[i];
DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n",
pmsg->flags & I2C_M_RD ? "read" : "write",
pmsg->len, pmsg->addr, i + 1, num);)
DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n",
i, msgs[i].addr, msgs[i].flags, msgs[i].len);)
if (pmsg->flags & I2C_M_RD) {
ret = lpc_readbytes(i2c_adap, pmsg);
if (ret != pmsg->len) {
DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: fail: "
"only read %d bytes.\n",ret));
} else {
DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: read %d bytes.\n",ret));
}
} else {
ret = lpc_sendbytes(i2c_adap, pmsg);
if (ret != pmsg->len) {
DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: fail: "
"only wrote %d bytes.\n",ret));
} else {
DEBPROTO(lpc_fprintf_debug("lpc_xfer.o: wrote %d bytes.\n",ret));
}
}
}
if (adap->xfer_end)
adap->xfer_end(&i2c_adap->nr);
mutex_unlock(&lpc_lock);
return i;
}
static u32 lpc_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_QUICK;
}
/* exported algorithm data: */
static const struct i2c_algorithm lpc_algo = {
.master_xfer = lpc_master_xfer,
//.smbus_xfer = lpc_smbus_xfer,
.functionality = lpc_func,
};
/*
* registering functions to load algorithms at runtime
*/
int lpc_add_iic_bus(struct i2c_adapter *adap,unsigned int id)
{
//struct i2c_algo_lpc_data *lpc_adap = adap->3;
int rval,num;
DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
/* register new adapter to i2c module... */
adap->algo = &lpc_algo;
for(num = 0; num < LPC_I2C_MAX_NCHANS;num++)
{
adap->nr = num;
snprintf(adap->name, sizeof(adap->name),
"i2c-%d-lpc (chan_id %d)", i2c_adapter_id(adap), num);
if(num)
{
rval = i2c_add_numbered_adapter(adap);
}
else
{
rval = i2c_add_adapter(adap);
}
}
return rval;
}
EXPORT_SYMBOL(lpc_add_iic_bus);
#define DEFAULT_BASE 0x0a00
static int lpc_base= 0x0a00;
static u8 __iomem *lpc_base_iomem;
static int lpc_irq;
static int lpc_clock = 0x1c;
static int lpc_own = 0x55;
static int lpc_mmapped;
static unsigned long lpc_base_addr = 0x0a00;
static unsigned int lpc_io_space_size = 2;
static unsigned long LPC_INDEX_REG;
static unsigned long LPC_DATA_REG;
/* notice : removed static struct i2c_lpc_iic gpi; code -
this module in real supports only one device, due to missing arguments
in some functions, called from the algo-lpc module. Sometimes it's
need to be rewriten - but for now just remove this for simpler reading */
static wait_queue_head_t lpc_wait;
static int lpc_pending;
static spinlock_t lock;
static spinlock_t lpc_slock;
static struct i2c_adapter lpc_iic_ops;
struct cpld_dev_type {
struct resource *io_resource;
struct semaphore sem;
struct cdev cdev;
};
struct cpld_dev_type *cpld_device;
/* ----- local functions ---------------------------------------------- */
static void lpc_cpld_setbyte(void *data, int ctl, int val)
{
//udelay(2);
outb(ctl, LPC_INDEX_REG);
mb();
outb(val, LPC_DATA_REG);
mb();
}
static int lpc_cpld_getbyte(void *data, int ctl)
{
u8 val = 0;
//udelay(2);
outb(ctl, LPC_INDEX_REG);
mb();
val = inb(LPC_DATA_REG);
mb();
return val;
}
static void lpc_iic_setbyte(void *data, int ctl, int val)
{
if (!cpld_device)
return -ENOTTY;
if (down_interruptible(&cpld_device->sem))
return -ERESTARTSYS;
lpc_cpld_setbyte(data,ctl,val);
up(&cpld_device->sem);
DEB2(printk("%s REG[%x] = %x\n",__func__,ctl,val);)
}
static int lpc_iic_getbyte(void *data, int ctl)
{
u8 val = 0;
if (!cpld_device)
return -ENOTTY;
if (down_interruptible(&cpld_device->sem))
return -ERESTARTSYS;
val = lpc_cpld_getbyte(data,ctl);
up(&cpld_device->sem);
DEB2(printk("%s REG[%x] = %x\n",__func__,ctl,val);)
return val;
}
int cig_cpld_read_register(u8 reg_off, u8 *val)
{
if (!cpld_device)
return -ENOTTY;
if (down_interruptible(&cpld_device->sem))
return -ERESTARTSYS;
*val = lpc_cpld_getbyte(cpld_device, reg_off);
up(&cpld_device->sem);
return 0;
}
EXPORT_SYMBOL(cig_cpld_read_register);
int cig_cpld_write_register(u8 reg_off, u8 val)
{
if (!cpld_device)
return -ENOTTY;
if (down_interruptible(&cpld_device->sem))
return -ERESTARTSYS;
lpc_cpld_setbyte(cpld_device, reg_off, val);
up(&cpld_device->sem);
return 0;
}
EXPORT_SYMBOL(cig_cpld_write_register);
static int lpc_iic_getown(void *data)
{
return (lpc_own);
}
static int lpc_iic_getclock(void *data)
{
return (lpc_clock);
}
static void lpc_iic_waitforpin(void *data)
{
DEFINE_WAIT(wait);
int timeout = 2;
unsigned long flags;
if (lpc_irq > 0) {
spin_lock_irqsave(&lock, flags);
if (lpc_pending == 0) {
spin_unlock_irqrestore(&lock, flags);
prepare_to_wait(&lpc_wait, &wait, TASK_INTERRUPTIBLE);
if (schedule_timeout(timeout*HZ)) {
spin_lock_irqsave(&lock, flags);
if (lpc_pending == 1) {
lpc_pending = 0;
}
spin_unlock_irqrestore(&lock, flags);
}
finish_wait(&lpc_wait, &wait);
} else {
lpc_pending = 0;
spin_unlock_irqrestore(&lock, flags);
}
} else {
udelay(100);
}
}
static irqreturn_t lpc_iic_handler(int this_irq, void *dev_id) {
spin_lock(&lock);
lpc_pending = 1;
spin_unlock(&lock);
wake_up_interruptible(&lpc_wait);
return IRQ_HANDLED;
}
static int board_id = 0;
static int lpc_select_chan(void *data)
{
unsigned int chan_id=0;
chan_id = *(unsigned int *)data;
chan_id -= 1;
DEB2(printk("step 1 : selest channel id = %d\n",chan_id);)
lpc_iic_setbyte(data,I2C_LPC_REG_BUS_SEL,chan_id);
return 0;
}
static int lpc_deselect_chan(void *data)
{
unsigned int chan_id=0;
chan_id = *(unsigned int *)data;
chan_id -= 1;
DEB2(printk("step last :deselect channel id = %d\n",chan_id);)
return 0;
}
/* ------------------------------------------------------------------------
* Encapsulate the above functions in the correct operations structure.
* This is only done when more than one hardware adapter is supported.
*/
static struct i2c_algo_lpc_data lpc_iic_data = {
.setlpc = lpc_iic_setbyte,
.getlpc = lpc_iic_getbyte,
.getown = lpc_iic_getown,
.getclock = lpc_iic_getclock,
.waitforpin = lpc_iic_waitforpin,
.xfer_begin = lpc_select_chan,
.xfer_end = lpc_deselect_chan,
};
#include <linux/i2c-algo-bit.h>
static struct i2c_adapter lpc_iic_arr_ops[LPC_I2C_MAX_NCHANS] = {0};
static void dummy_setscl(void *data, int state)
{
return 1;
}
static void dummy_setsda(void *data, int state)
{
return 1;
}
static int dummy_getscl(void *data)
{
return 1;
}
static int dummy_getsda(void *data)
{
return 1;
}
static struct i2c_algo_bit_data dummy_algo_data = {
.setsda = dummy_setsda,
.setscl = dummy_setscl,
.getsda = dummy_getsda,
.getscl = dummy_getscl,
.udelay = 50,
.timeout = HZ,
};
static int dummy_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg *msgs,
int num)
{
return 1;
}
static u32 dummy_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_QUICK;
}
static const struct i2c_algorithm dummy_algo = {
.master_xfer = dummy_xfer,
.functionality = dummy_func,
};
static struct i2c_adapter i2c_dummy = {
.owner = THIS_MODULE,
.class = I2C_CLASS_HWMON,
.algo_data = &dummy_algo_data,
.algo = &dummy_algo,
.name = "i2c_dummy",
};
static int lpc_iic_match(struct device *dev, unsigned int id)
{
/* sanity checks for lpc_mmapped I/O */
DEB2(printk("lpc_iic_match\n");)
if (lpc_base < DEFAULT_BASE) {
dev_err(dev, "incorrect lpc_base address (%#x) specified "
"for lpc_mmapped I/O\n", lpc_base);
return 0;
}
if (lpc_base == 0) {
lpc_base = DEFAULT_BASE;
}
return 1;
}
static int lpc_iic_probe(struct device *dev, unsigned int id)
{
int rval,num;
lpc_fprintf_init();
DEB2(printk("lpc_iic_probe\n");)
mutex_init(&lpc_lock);
if(board_id == 1)
i2c_add_adapter(&i2c_dummy);
for(num = 0; num < LPC_I2C_MAX_NCHANS;num++)
{
lpc_iic_arr_ops[num].dev.parent = dev;
lpc_iic_arr_ops[num].owner = THIS_MODULE;
lpc_iic_arr_ops[num].class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
lpc_iic_arr_ops[num].algo = &lpc_algo;
lpc_iic_arr_ops[num].algo_data = &lpc_iic_data,
lpc_iic_arr_ops[num].nr=num;
snprintf(lpc_iic_arr_ops[num].name, sizeof(lpc_iic_arr_ops[num].name), "i2c-%d-lpc", i2c_adapter_id(&lpc_iic_arr_ops[num]), num);
rval |= i2c_add_adapter(&lpc_iic_arr_ops[num]);
DEB2(printk("%s\n",lpc_iic_arr_ops[num].name);)
}
return 0;
}
static int lpc_iic_remove(struct device *dev, unsigned int id)
{
int num;
DEB2(printk("lpc_iic_remove\n"));
lpc_fprintf_exit();
for(num = LPC_I2C_MAX_NCHANS - 1; num >= 0 ;num--)
i2c_del_adapter(&lpc_iic_arr_ops[num]);
if(board_id == 1)
i2c_del_adapter(&i2c_dummy);
return 0;
}
static struct isa_driver i2c_lpc_driver = {
.match = lpc_iic_match,
.probe = lpc_iic_probe,
.remove = lpc_iic_remove,
.driver = {
.owner = THIS_MODULE,
.name = "lpc-iic",
},
};
struct kset cpld_kset;
static int cpld_major = 0;
static int cpld_minor = 0;
struct cpld_rw_msg {
unsigned char addr;
unsigned char data;
};
static struct cpld_rw_msg param_read = {-1};
static struct cpld_rw_msg param_write = {-1};
void cpld_sysfs_kobj_release(struct kobject *kobj)
{
return;
}
int cpld_sysfs_add_attr(struct kobject* kobj, char* attr_name)
{
struct attribute *attr;
attr = kmalloc(sizeof(struct attribute), GFP_KERNEL);
attr->name = attr_name;
attr->mode = 0644;
return sysfs_create_file(kobj, attr);
}
static ssize_t cpld_sysfs_show(struct kobject *kobj, struct attribute *attr, char *buffer)
{
u8 val,ret;
if (0 == strcmp(attr->name, "read"))
{
val = lpc_iic_getbyte(NULL,param_read.addr);
ret = sprintf(buffer,"read : addr = %x val = %x\n",param_read.addr, val);
}
else if (0 == strcmp(attr->name, "write"))
{
lpc_iic_setbyte(NULL, param_write.addr,param_write.data);
ret = sprintf(buffer,"write : addr = %x val = %x\n",param_write.addr, param_write.data);
}
else if (0 == strcmp(attr->name, "version"))
{
val = lpc_iic_getbyte(NULL, 0x02);
ret = sprintf(buffer,"CPLD version : V%02x\n",val);
}
return ret;
}
static ssize_t cpld_sysfs_store(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t count)
{
int param[3];
if (0 == strcmp(attr->name, "read"))
{
sscanf(buffer, "0x%02x", &param[0]);
param_read.addr = param[0];
}
else if (0 == strcmp(attr->name, "write"))
{
sscanf(buffer, "0x%2x 0x%02x", &param[0], &param[1]);
param_write.addr = param[0];
param_write.data = param[1];
}
return count;
}
static struct sysfs_ops cpld_sysfs_ops =
{
.show = cpld_sysfs_show,
.store = cpld_sysfs_store,
};
static struct kobj_type cpld_kobj_type =
{
.release = cpld_sysfs_kobj_release,
.sysfs_ops = &cpld_sysfs_ops,
.default_attrs = NULL,
};
static const char driver_name[] = "cpld_drv";
static atomic_t cpld_available = ATOMIC_INIT(1);
static struct class *cpld_class;
#define CPLD_IOC_MAGIC '['
#define CPLD_IOC_RDREG _IOR(CPLD_IOC_MAGIC, 0, struct cpld_rw_msg)
#define CPLD_IOC_WRREG _IOW(CPLD_IOC_MAGIC, 1, struct cpld_rw_msg)
#define CPLD_IOC_MAXNR 2
int cpld_open(struct inode *inode, struct file *filp)
{
struct cpld_dev_type *dev;
if (! atomic_dec_and_test(&cpld_available)) {
atomic_inc(&cpld_available);
return -EBUSY;
}
dev = container_of(inode->i_cdev, struct cpld_dev_type, cdev);
filp->private_data = dev;
return 0;
}
int cpld_release(struct inode *inode, struct file *flip)
{
atomic_inc(&cpld_available);
return 0;
}
long cpld_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int rc = 0;
int err = 0;
struct cpld_dev_type *dev = (struct cpld_dev_type *)filp->private_data;
struct cpld_rw_msg msg;
if (_IOC_TYPE(cmd) != CPLD_IOC_MAGIC)
return -ENOTTY;
if (_IOC_NR(cmd) > CPLD_IOC_MAXNR)
return -ENOTTY;
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
if (_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
if (err)
return -EFAULT;
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
switch(cmd){
case CPLD_IOC_RDREG:
rc = copy_from_user(&msg, (void __user *)arg, sizeof(msg));
if (!rc) {
msg.data = lpc_cpld_getbyte(dev, msg.addr);
rc = copy_to_user((void __user *)arg, &msg, sizeof(msg));
}
break;
case CPLD_IOC_WRREG:
rc = copy_from_user(&msg, (void __user *)arg, sizeof(msg));
if (!rc) {
lpc_cpld_setbyte(dev, msg.addr, msg.data);
}
break;
default:
rc = -ENOTTY;
break;
}
up(&dev->sem);
return rc;
}
struct file_operations cpld_fops = {
.owner = THIS_MODULE,
.open = cpld_open,
.unlocked_ioctl = cpld_ioctl,
.release = cpld_release,
};
static void cpld_setup_cdev(struct cpld_dev_type *dev)
{
int err, devno = MKDEV(cpld_major, cpld_minor);
cdev_init(&dev->cdev, &cpld_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &cpld_fops;
err = cdev_add(&dev->cdev, devno, 1);
if (err)
DEB2(printk(KERN_NOTICE "Error %d adding cpld", err);)
}
//#define CPLD_KTHREAD_TEST
#ifdef CPLD_KTHREAD_TEST
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/delay.h>
static struct task_struct *test_TaskStruct;
void get_random_bytes(void *buf, int nbytes);
#define LM75_REAR_LEFT_PATH "/sys/class/hwmon/hwmon5/temp1_input"
#define LM75_REAR_RIGHT_PATH "/sys/class/hwmon/hwmon6/temp1_input"
static int threadTask(void* arg)
{
static int count =0;
unsigned char lpc_read_data=0;
unsigned char lpc_write_data=0;
unsigned char lpc_random_data=0;
struct file *temp1_file = NULL,*temp2_file = NULL;
unsigned char temp1_buffer[8]={0},temp2_buffer[8]={0};
mm_segment_t old_fs;
while(1)
{
if(kthread_should_stop())
{
DEB2(printk("threadTask: kthread_should_stop\n"));
break;
}
#if 1
get_random_bytes(&lpc_random_data,1);
lpc_write_data = lpc_random_data;
lpc_iic_setbyte(NULL,I2C_LPC_REG_TEST,lpc_write_data);
//DEB2(printk("threadTask: lpc write reg[01] data : %02x\n",lpc_write_data));
lpc_read_data = lpc_iic_getbyte(NULL,I2C_LPC_REG_TEST);
//DEB2(printk("threadTask: lpc read reg[01] data : %02x\n",lpc_read_data));
udelay(10000);
if(lpc_write_data != lpc_read_data)
{
printk("Error : WRITE %02x != READ %02x\n",lpc_write_data,lpc_read_data);
}
msleep(10);
#else
if(temp1_file != NULL)
temp1_file = filp_open(LM75_REAR_LEFT_PATH, O_RDONLY , 0);
if (IS_ERR(temp1_file)) {
printk("error occured while opening file %s, exiting...\n", LM75_REAR_LEFT_PATH);
}
if(temp2_file != NULL)
temp2_file = filp_open(LM75_REAR_RIGHT_PATH, O_RDONLY ,0);
if (IS_ERR(temp2_file)) {
printk("error occured while opening file %s, exiting...\n", LM75_REAR_RIGHT_PATH);
}
old_fs = get_fs();
set_fs(KERNEL_DS);
temp1_file->f_op->read(temp1_file, (char *)temp1_buffer, strlen(temp1_buffer), &temp1_file->f_pos);
temp2_file->f_op->read(temp2_file, (char *)temp2_buffer, strlen(temp2_buffer), &temp2_file->f_pos);
set_fs(old_fs);
if((simple_strtoul(temp1_buffer,NULL,10) >=30000) || (simple_strtoul(temp2_buffer,NULL,10) >=30000))
{
lpc_iic_setbyte(NULL,0x40,0xff);
printk("Full speed\n");
}
msleep(1000);
#endif
}
}
static int init_kernel_Thread(void)
{
test_TaskStruct=kthread_create(threadTask,NULL,"KernelThead",0);
if(IS_ERR(test_TaskStruct))
{
printk("kthread_create error\n");
}
else
{
wake_up_process(test_TaskStruct);
}
return 0;
}
static void exit_kernel_Thread(void)
{
kthread_stop(test_TaskStruct);
test_TaskStruct = NULL;
}
#endif
static int __init cpld_init(void)
{
int rval,rc;
dev_t dev;
DEB2(printk("cpld_init\n");)
cpld_device = kzalloc(sizeof(struct cpld_dev_type), GFP_KERNEL);
if (!cpld_device)
goto error3;
cpld_device->io_resource = request_region(lpc_base_addr,
lpc_io_space_size, "lpc-i2c");
if (!cpld_device->io_resource) {
DEB2(printk("lpc: claim I/O resource fail\n");)
goto error2;
}
sema_init(&cpld_device->sem, 1);
LPC_INDEX_REG = lpc_base_addr;
LPC_DATA_REG = lpc_base_addr + 1;
rval = lpc_bus_init();
rval = lpc_register_driver(&i2c_lpc_driver, 1);
kobject_set_name(&cpld_kset.kobj, "cpld");
cpld_kset.kobj.ktype= &cpld_kobj_type;
kset_register(&cpld_kset);
cpld_sysfs_add_attr(&cpld_kset.kobj, "read");
cpld_sysfs_add_attr(&cpld_kset.kobj, "write");
cpld_sysfs_add_attr(&cpld_kset.kobj, "version");
if (cpld_major) {
dev = MKDEV(cpld_major, cpld_minor);
rc = register_chrdev_region(dev, 1, "cpld");
} else {
rc = alloc_chrdev_region(&dev, cpld_major, 1, "cpld");
cpld_major = MAJOR(dev);
}
cpld_setup_cdev(cpld_device);
cpld_class = class_create(THIS_MODULE, KBUILD_MODNAME);
if (!cpld_class) {
DEB2(printk("failed to create class\n");)
goto error1;
}
device_create(cpld_class, NULL, dev, NULL, "cpld");
#ifdef CPLD_KTHREAD_TEST
init_kernel_Thread();
#endif
return 0;
error1:
cdev_del(&cpld_device->cdev);
unregister_chrdev_region(dev, 1);
error2:
release_resource(cpld_device->io_resource);
error3:
kfree(cpld_device);
return rc;
}
static void __exit cpld_exit(void)
{
DEB2(printk("cpld_exit\n"));
lpc_unregister_driver(&i2c_lpc_driver);
lpc_bus_exit();
#ifdef CPLD_KTHREAD_TEST
exit_kernel_Thread();
#endif
dev_t devno = MKDEV(cpld_major, cpld_minor);
cdev_del(&cpld_device->cdev);
if (cpld_class) {
device_destroy(cpld_class, devno);
class_destroy(cpld_class);
}
kobject_put(&cpld_kset.kobj);
if(cpld_kset.kobj.ktype)
kset_unregister(&cpld_kset);
if (cpld_device) {
if (cpld_device->io_resource)
release_resource(cpld_device->io_resource);
kfree(cpld_device);
}
unregister_chrdev_region(devno, 1);
}
module_param(cpld_major, int, S_IRUGO);
module_param(cpld_minor, int, S_IRUGO);
module_param(i2c_debug, int, S_IRUGO);
module_param(board_id, int, S_IRUGO);
module_init(cpld_init);
module_exit(cpld_exit);
MODULE_AUTHOR("Zhang Peng <zhangpeng@cigtech.com>");
MODULE_DESCRIPTION("cs6436-56p-cpld driver");
MODULE_LICENSE("GPL");