【C5】1
创始人
2025-05-31 04:15:38
0

文章目录

  • mc24lc64t.c
  • i2c-ocores.h
  • i2c-ocores.c
  • i2c_kobj_sysfs.h
  • i2c_kobj_sysfs.c
  • i2c_dev_sysfs.h
  • i2c_dev_sysfs.c
  • hwmon-sysfs.h
  • gpio-ich.c
  • fpga_i2c_adapter.c
  • cpu_addr.c
  • cpld_lpc.c
  • cpld_i2c.c


mc24lc64t.c

   eeprom驱动
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include #define EEPROM_SIZE 8192 //mc24lt64t eeprom size in bytes.struct mc24lc64t_data {struct mutex update_lock;
};static ssize_t mc24lc64t_read(struct file *filp,struct kobject *kobj,struct bin_attribute *bin_attr,char *buf,loff_t off,size_t count)
{struct i2c_client *client = kobj_to_i2c_client(kobj);struct mc24lc64t_data *drvdata = i2c_get_clientdata(client);size_t timeout, read_time, i = 0;int32_t status;if (drvdata == NULL)return -ENODEV;if (i2c_smbus_write_byte_data(client, off >> 8, off)) {status = -EIO;goto exit;}msleep(1);mutex_lock(&drvdata->update_lock);begin:if (i < count) {timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/do {read_time = jiffies;status = i2c_smbus_read_byte(client);if (status >= 0) {buf[i++] = status;goto begin;}} while (time_before(read_time, timeout));status = -ETIMEDOUT;goto exit;}status = count;
exit:mutex_unlock(&drvdata->update_lock);return status;
}static ssize_t mc24lc64t_write(struct file *filp,struct kobject *kobj,struct bin_attribute *bin_attr,char *buf,loff_t off,size_t count)
{struct i2c_client *client = kobj_to_i2c_client(kobj);struct mc24lc64t_data *drvdata = i2c_get_clientdata(client);size_t timeout, write_time, i = 0;int32_t status;u16 value;if (drvdata == NULL)return -ENODEV;mutex_lock(&drvdata->update_lock);begin:if (i < count) {timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/value = (buf[i] << 8 | (off & 0xff));do {write_time = jiffies;status = i2c_smbus_write_word_data(client, off >> 8, value);if (status == 0) {/* increase offset */off++;/* increase buffer index */i++;goto begin;}} while (time_before(write_time, timeout));status = -ETIMEDOUT;goto exit;}status = count;exit:mutex_unlock(&drvdata->update_lock);return status;
}static struct bin_attribute mc24lc64t_bit_attr = {   //eeprom节点,/sys/bus/i2c-1.attr = {.name = "eeprom",.mode = S_IRUGO | S_IWUGO,},.size = EEPROM_SIZE,.read = mc24lc64t_read,.write = mc24lc64t_write,
};static int32_t mc24lc64t_probe(struct i2c_client *client, const struct i2c_device_id *id)
{struct i2c_adapter *adapter = client->adapter;struct mc24lc64t_data *drvdata;int32_t err;if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA | I2C_FUNC_SMBUS_READ_BYTE))return -EPFNOSUPPORT;if (!(drvdata = devm_kzalloc(&client->dev, sizeof(struct mc24lc64t_data), GFP_KERNEL)))return -ENOMEM;i2c_set_clientdata(client, drvdata);mutex_init(&drvdata->update_lock);err = sysfs_create_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr);return err;
}static int32_t mc24lc64t_remove(struct i2c_client *client)
{sysfs_remove_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr);return 0;
}static const struct i2c_device_id mc24lc64t_id[] = {{"24lc64t", 0}, {}};
MODULE_DEVICE_TABLE(i2c, mc24lc64t_id);static struct i2c_driver mc24lc64t_driver = {.driver = {.name = "mc24lc64t",  //wusuowei.owner = THIS_MODULE,},.probe = mc24lc64t_probe,.remove = mc24lc64t_remove,.id_table = mc24lc64t_id,
};module_i2c_driver(mc24lc64t_driver);MODULE_AUTHOR("Huaqin Technology Co.,Ltd.");
MODULE_DESCRIPTION("Hua Qin 24LC64T Driver");
MODULE_VERSION("0.0.1");
MODULE_LICENSE("GPL");

i2c-ocores.h

/* SPDX-License-Identifier: GPL-2.0 */
/** i2c-ocores.h - definitions for the i2c-ocores interface** Peter Korsgaard */#ifndef _LINUX_I2C_OCORES_H
#define _LINUX_I2C_OCORES_Hstruct ocores_i2c_platform_data {uint32_t reg_shift;                   /* register offset shift value */uint32_t reg_io_width;                /* register io read/write width */uint32_t clock_khz;                   /* input clock in kHz */uint32_t bus_khz;                     /* bus clock in kHz */bool big_endian;                      /* registers are big endian */uint8_t num_devices;                  /* number of devices in the devices list */struct i2c_board_info const *devices; /* devices connected to the bus */
};#endif /* _LINUX_I2C_OCORES_H */

i2c-ocores.c

// SPDX-License-Identifier: GPL-2.0
/** i2c-ocores.c: I2C bus driver for OpenCores I2C controller* (https://opencores.org/project/i2c/overview)** Peter Korsgaard ** Support for the GRLIB port of the controller by* Andreas Larsson     节点:i2c-1,控制器属性*/#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include 
#include 
#include 
#include 
#include 
#include 
#include "i2c-ocores.h"#define OCORES_FLAG_POLL BIT(0)/** 'process_lock' exists because ocores_process() and ocores_process_timeout()* can't run in parallel.*/
struct ocores_i2c {void __iomem *base;int32_t iobase;uint32_t reg_shift;uint32_t reg_io_width;size_t flags;wait_queue_head_t wait;struct i2c_adapter adap;struct i2c_msg *msg;int32_t pos;int32_t nmsgs;int32_t state; /* see STATE_ */int32_t nack_retry;spinlock_t process_lock;struct clk *clk;int32_t ip_clock_khz;int32_t bus_clock_khz;void (*setreg)(struct ocores_i2c *i2c, int32_t reg, uint8_t value);uint8_t (*getreg)(struct ocores_i2c *i2c, int32_t reg);
};/* registers */
#define OCI2C_PRELOW        0
#define OCI2C_PREHIGH       1
#define OCI2C_CONTROL       2
#define OCI2C_DATA          3
#define OCI2C_CMD           4 /* write only */
#define OCI2C_STATUS        4 /* read only, same address as OCI2C_CMD */#define OCI2C_CTRL_IEN      0x40
#define OCI2C_CTRL_EN       0x80#define OCI2C_CMD_START     0x91
#define OCI2C_CMD_STOP      0x41
#define OCI2C_CMD_READ      0x21
#define OCI2C_CMD_WRITE     0x11
#define OCI2C_CMD_READ_ACK  0x21
#define OCI2C_CMD_READ_NACK 0x29
#define OCI2C_CMD_IACK      0x01#define OCI2C_STAT_IF       0x01
#define OCI2C_STAT_TIP      0x02
#define OCI2C_STAT_ARBLOST  0x20
#define OCI2C_STAT_BUSY     0x40
#define OCI2C_STAT_NACK     0x80#define STATE_DONE          0
#define STATE_START         1
#define STATE_WRITE         2
#define STATE_READ          3
#define STATE_ERROR         4#define TYPE_OCORES         0
#define TYPE_GRLIB          1
#define I2C_CTRL            0x8
#define I2C_CMD_STA0        0x10#define PORT_XCVR_REGISTER_SIZE 0x3e0static void oc_setreg_8(struct ocores_i2c *i2c, int32_t reg, uint8_t value)
{iowrite8(value, i2c->base + (reg << i2c->reg_shift));
}static void oc_setreg_16(struct ocores_i2c *i2c, int32_t reg, uint8_t value)
{iowrite16(value, i2c->base + (reg << i2c->reg_shift));
}static void oc_setreg_32(struct ocores_i2c *i2c, int32_t reg, uint8_t value)
{iowrite32(value, i2c->base + (reg << i2c->reg_shift));
}static void oc_setreg_16be(struct ocores_i2c *i2c, int32_t reg, uint8_t value)
{iowrite16be(value, i2c->base + (reg << i2c->reg_shift));
}static void oc_setreg_32be(struct ocores_i2c *i2c, int32_t reg, uint8_t value)
{iowrite32be(value, i2c->base + (reg << i2c->reg_shift));
}static inline uint8_t oc_getreg_8(struct ocores_i2c *i2c, int32_t reg)
{return ioread8(i2c->base + (reg << i2c->reg_shift));
}static inline uint8_t oc_getreg_16(struct ocores_i2c *i2c, int32_t reg)
{return ioread16(i2c->base + (reg << i2c->reg_shift));
}static inline uint8_t oc_getreg_32(struct ocores_i2c *i2c, int32_t reg)
{return ioread32(i2c->base + (reg << i2c->reg_shift));
}static inline uint8_t oc_getreg_16be(struct ocores_i2c *i2c, int32_t reg)
{return ioread16be(i2c->base + (reg << i2c->reg_shift));
}static inline uint8_t oc_getreg_32be(struct ocores_i2c *i2c, int32_t reg)
{return ioread32be(i2c->base + (reg << i2c->reg_shift));
}static void oc_setreg_io_8(struct ocores_i2c *i2c, int32_t reg, uint8_t value)
{outb(value, i2c->iobase + reg);
}static inline uint8_t oc_getreg_io_8(struct ocores_i2c *i2c, int32_t reg)
{return inb(i2c->iobase + reg);
}static inline void oc_setreg(struct ocores_i2c *i2c, int32_t reg, uint8_t value)
{i2c->setreg(i2c, reg, value);
}static inline uint8_t oc_getreg(struct ocores_i2c *i2c, int32_t reg)
{return i2c->getreg(i2c, reg);
}static void ocores_process(struct ocores_i2c *i2c, uint8_t stat)
{struct i2c_msg *msg = i2c->msg;size_t flags;/** If we spin here is because we are in timeout, so we are going* to be in STATE_ERROR. See ocores_process_timeout()*/spin_lock_irqsave(&i2c->process_lock, flags);dev_dbg(&i2c->adap.dev, "STATE: %d\n", i2c->state);if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) {/* stop has been sent */oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);wake_up(&i2c->wait);goto out;}/* error? */if (stat & OCI2C_STAT_ARBLOST) {i2c->state = STATE_START;oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);dev_dbg(&i2c->adap.dev, "ERR: AL\n");goto out;}if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) {i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;if (stat & OCI2C_STAT_NACK) {dev_dbg(&i2c->adap.dev, "ERR: NACK\n");i2c->state = STATE_ERROR;if (!(msg->flags & I2C_M_RD))i2c->nack_retry = 1;oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);goto out;}} else {msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA);}/* end of msg? */if (i2c->pos == msg->len) {i2c->nmsgs--;i2c->msg++;i2c->pos = 0;msg = i2c->msg;if (i2c->nmsgs) { /* end? *//* send start? */if (!(msg->flags & I2C_M_NOSTART)) {uint8_t addr = i2c_8bit_addr_from_msg(msg);i2c->state = STATE_START;oc_setreg(i2c, OCI2C_DATA, addr);oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);goto out;}i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;} else {i2c->state = STATE_DONE;oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);goto out;}}if (i2c->state == STATE_READ) {oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len - 1) ? OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK);} else {oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]);oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE);}out:spin_unlock_irqrestore(&i2c->process_lock, flags);
}static irqreturn_t ocores_isr(int32_t irq, void *dev_id)
{struct ocores_i2c *i2c = dev_id;uint8_t stat = oc_getreg(i2c, OCI2C_STATUS);dev_dbg(&i2c->adap.dev, "STATUS: 0x%x\n", stat);if (!(stat & OCI2C_STAT_IF))return IRQ_NONE;ocores_process(i2c, stat);return IRQ_HANDLED;
}/*** Process timeout event* @i2c: ocores I2C device instance*/
static void ocores_process_timeout(struct ocores_i2c *i2c)
{size_t flags;spin_lock_irqsave(&i2c->process_lock, flags);i2c->state = STATE_ERROR;oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP);spin_unlock_irqrestore(&i2c->process_lock, flags);
}/*** Wait until something change in a given register* @i2c: ocores I2C device instance* @reg: register to query* @mask: bitmask to apply on register value* @val: expected result* @timeout: timeout in jiffies** Timeout is necessary to avoid to stay here forever when the chip* does not answer correctly.** Return: 0 on success, -ETIMEDOUT on timeout*/
static int32_t ocores_wait(struct ocores_i2c *i2c, int32_t reg, uint8_t mask, uint8_t val, const size_t timeout)
{size_t j;j = jiffies + timeout;while (1) {uint8_t status = oc_getreg(i2c, reg);if ((status & mask) == val)break;if (time_after(jiffies, j))return -ETIMEDOUT;cpu_relax();cond_resched();}return 0;
}/*** Wait until is possible to process some data* @i2c: ocores I2C device instance** Used when the device is in polling mode (interrupts disabled).** Return: 0 on success, -ETIMEDOUT on timeout*/
static int32_t ocores_poll_wait(struct ocores_i2c *i2c)
{uint8_t mask;int32_t err;if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) {/* transfer is over */mask = OCI2C_STAT_BUSY;} else {/* on going transfer */mask = OCI2C_STAT_TIP;/** We wait for the data to be transferred (8bit),* then we start polling on the ACK/NACK bit*/udelay((8 * 1000) / i2c->bus_clock_khz);}dev_dbg(&i2c->adap.dev, "Wait for: 0x%x\n", mask);/** once we are here we expect to get the expected result immediately* so if after 1ms we timeout then something is broken.*/err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(30));if (err)dev_warn(i2c->adap.dev.parent, "%s: STATUS timeout, bit 0x%x did not clear in 30ms\n", __func__, mask);return err;
}/*** It handles an IRQ-less transfer* @i2c: ocores I2C device instance** Even if IRQ are disabled, the I2C OpenCore IP behavior is exactly the same* (only that IRQ are not produced). This means that we can re-use entirely* ocores_isr(), we just add our polling code around it.** It can run in atomic context*/
static void ocores_process_polling(struct ocores_i2c *i2c)
{int32_t polling_timeout = 655; //Add for avoiding i2c hold cause cpu halt and OS crash//while (1) {while (polling_timeout) {irqreturn_t ret;int32_t err;polling_timeout--;err = ocores_poll_wait(i2c);if (err) {i2c->state = STATE_ERROR;break; /* timeout */}ret = ocores_isr(-1, i2c);if (ret == IRQ_NONE) {break; /* all messages have been transferred */}}if (polling_timeout == 0)printk(KERN_ERR "ocores_process_polling polling timeout\n");
}static int32_t ocores_xfer_core(struct ocores_i2c *i2c, struct i2c_msg *msgs, int32_t num, bool polling)
{int32_t ret;uint8_t ctrl;ctrl = oc_getreg(i2c, OCI2C_CONTROL);if (polling)oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~OCI2C_CTRL_IEN);elseoc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN);i2c->msg = msgs;i2c->pos = 0;i2c->nmsgs = num;i2c->state = STATE_START;dev_dbg(&i2c->adap.dev, "STATE: %d\n", i2c->state);oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg));oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START);if (polling) {ocores_process_polling(i2c);} else {ret = wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || (i2c->state == STATE_DONE), HZ);if (ret == 0) {ocores_process_timeout(i2c);return -ETIMEDOUT;}}return (i2c->state == STATE_DONE) ? num : -EIO;
}static int32_t ocores_xfer_polling(struct i2c_adapter *adap, struct i2c_msg *msgs, int32_t num)
{return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, true);
}static int32_t ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int32_t num)
{int32_t ret;int32_t retry = 0;int32_t max_retry = 0;struct ocores_i2c *i2c = i2c_get_adapdata(adap);i2c->nack_retry = 0;if (i2c->flags & OCORES_FLAG_POLL) {//return ocores_xfer_polling(adap, msgs, num);ret = ocores_xfer_polling(adap, msgs, num);// Fix i2cdetect issueif (num == 1)max_retry = 5;elsemax_retry = 5;while ((i2c->nack_retry == 1) && (retry < max_retry)) {retry++;i2c->nack_retry = 0;ret = ocores_xfer_polling(adap, msgs, num);// printk("nack retry polling = %d\n",retry);}i2c->nack_retry = 0;return ret;}return ocores_xfer_core(i2c, msgs, num, false);
}static int32_t ocores_init(struct device *dev, struct ocores_i2c *i2c)
{int32_t prescale;int32_t diff;uint8_t ctrl = oc_getreg(i2c, OCI2C_CONTROL);/* make sure the device is disabled */ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN);oc_setreg(i2c, OCI2C_CONTROL, ctrl);prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1;prescale = clamp(prescale, 0, 0xffff);diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz;if (abs(diff) > i2c->bus_clock_khz / 10) {dev_err(dev, "Unsupported clock settings: core: %d KHz, bus: %d KHz\n", i2c->ip_clock_khz, i2c->bus_clock_khz);return -EINVAL;}oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);//	ctrl = oc_getreg(i2c, OCI2C_PRELOW);//debug//	printk("OCI2C_PRELOW %x\n",ctrl);//	ctrl = oc_getreg(i2c, OCI2C_PREHIGH);//debug//	printk("OCI2C_PREHIGH %x\n",ctrl);dev_info(dev, "Set bus speed to %d KHz\n", i2c->bus_clock_khz);dev_info(dev, "Prescale: %d\n", prescale);/* Init the device */oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_EN);return 0;
}static uint32_t ocores_func(struct i2c_adapter *adap)
{return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}static const struct i2c_algorithm ocores_algorithm = {.master_xfer = ocores_xfer,.functionality = ocores_func,
};static const struct i2c_adapter ocores_adapter = {.owner = THIS_MODULE,.name = "i2c-ocores",.class = I2C_CLASS_DEPRECATED,.algo = &ocores_algorithm,
};static const struct of_device_id ocores_i2c_match[] = {{.compatible = "opencores,i2c-ocores",.data = (void *)TYPE_OCORES,},{.compatible = "aeroflexgaisler,i2cmst",.data = (void *)TYPE_GRLIB,},{},
};
MODULE_DEVICE_TABLE(of, ocores_i2c_match);#ifdef CONFIG_OF
/** Read and write functions for the GRLIB port of the controller. Registers are* 32-bit big endian and the PRELOW and PREHIGH registers are merged into one* register. The subsequent registers have their offsets decreased accordingly.*/
static uint8_t oc_getreg_grlib(struct ocores_i2c *i2c, int32_t reg)
{uint32_t rd;int32_t rreg = reg;if (reg != OCI2C_PRELOW)rreg--;rd = ioread32be(i2c->base + (rreg << i2c->reg_shift));if (reg == OCI2C_PREHIGH)return (uint8_t)(rd >> 8);elsereturn (uint8_t)rd;
}static void oc_setreg_grlib(struct ocores_i2c *i2c, int32_t reg, uint8_t value)
{uint32_t curr, wr;int32_t rreg = reg;if (reg != OCI2C_PRELOW)rreg--;if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) {curr = ioread32be(i2c->base + (rreg << i2c->reg_shift));if (reg == OCI2C_PRELOW)wr = (curr & 0xff00) | value;elsewr = (((uint32_t)value) << 8) | (curr & 0xff);} else {wr = value;}iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift));
}static int32_t ocores_i2c_of_probe(struct platform_device *pdev, struct ocores_i2c *i2c)
{struct device_node *np = pdev->dev.of_node;const struct of_device_id *match;uint32_t val;uint32_t clock_frequency;bool clock_frequency_present;if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) {/* no 'reg-shift', check for deprecated 'regstep' */if (!of_property_read_u32(np, "regstep", &val)) {if (!is_power_of_2(val)) {dev_err(&pdev->dev, "invalid regstep %d\n", val);return -EINVAL;}i2c->reg_shift = ilog2(val);dev_warn(&pdev->dev, "regstep property deprecated, use reg-shift\n");}}clock_frequency_present = !of_property_read_u32(np, "clock-frequency", &clock_frequency);i2c->bus_clock_khz = 100;i2c->clk = devm_clk_get(&pdev->dev, NULL);if (!IS_ERR(i2c->clk)) {int32_t ret = clk_prepare_enable(i2c->clk);if (ret) {dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);return ret;}i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000;if (clock_frequency_present)i2c->bus_clock_khz = clock_frequency / 1000;}if (i2c->ip_clock_khz == 0) {if (of_property_read_u32(np, "opencores,ip-clock-frequency", &val)) {if (!clock_frequency_present) {dev_err(&pdev->dev, "Missing required parameter 'opencores,ip-clock-frequency'\n");clk_disable_unprepare(i2c->clk);return -ENODEV;}i2c->ip_clock_khz = clock_frequency / 1000;dev_warn(&pdev->dev,"Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n");} else {i2c->ip_clock_khz = val / 1000;if (clock_frequency_present)i2c->bus_clock_khz = clock_frequency / 1000;}}of_property_read_u32(pdev->dev.of_node, "reg-io-width", &i2c->reg_io_width);match = of_match_node(ocores_i2c_match, pdev->dev.of_node);if (match && (ssize_t)match->data == TYPE_GRLIB) {dev_dbg(&pdev->dev, "GRLIB variant of i2c-ocores\n");i2c->setreg = oc_setreg_grlib;i2c->getreg = oc_getreg_grlib;}return 0;
}
#else
#define ocores_i2c_of_probe(pdev, i2c) -ENODEV
#endifstatic ssize_t i2ccore_ctrl_reg_show(struct device *dev, struct device_attribute *attr, char *buf)
{uint8_t data;size_t flags;struct ocores_i2c *i2c = dev_get_drvdata(dev);if (!dev || !i2c)return -EINVAL;spin_lock_irqsave(&i2c->process_lock, flags);data = ioread32(i2c->base + I2C_CTRL);spin_unlock_irqrestore(&i2c->process_lock, flags);return snprintf(buf, PAGE_SIZE, "0x%8.8x\n", data);
}static ssize_t i2ccore_ctrl_reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{ssize_t ret = 0;size_t value;uint32_t data;size_t flags;int8_t *tok;int32_t len = size;int8_t clone[size];int8_t *pclone = clone;struct ocores_i2c *i2c = dev_get_drvdata(dev);if (!dev || !i2c)return -EINVAL;if (buf[size - 1] == '\0' || buf[size - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}data = (uint32_t)value;spin_lock_irqsave(&i2c->process_lock, flags);iowrite32(data, i2c->base + I2C_CTRL);spin_unlock_irqrestore(&i2c->process_lock, flags);ret = (ssize_t)size;return ret;
}
DEVICE_ATTR_RW(i2ccore_ctrl_reg);static ssize_t i2ccore_cmd_sta0_reg_show(struct device *dev, struct device_attribute *attr, char *buf)
{uint8_t data;size_t flags;struct ocores_i2c *i2c = dev_get_drvdata(dev);if (!dev || !i2c)return -EINVAL;spin_lock_irqsave(&i2c->process_lock, flags);data = ioread32(i2c->base + I2C_CMD_STA0);spin_unlock_irqrestore(&i2c->process_lock, flags);return snprintf(buf, PAGE_SIZE, "0x%8.8x\n", data);
}static ssize_t i2ccore_cmd_sta0_reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{ssize_t ret = 0;size_t value;uint32_t data;size_t flags;int8_t *tok;int32_t len = size;int8_t clone[size];int8_t *pclone = clone;struct ocores_i2c *i2c = dev_get_drvdata(dev);if (!dev || !i2c)return -EINVAL;if (buf[size - 1] == '\0' || buf[size - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}data = (uint32_t)value;spin_lock_irqsave(&i2c->process_lock, flags);iowrite32(data, i2c->base + I2C_CMD_STA0);spin_unlock_irqrestore(&i2c->process_lock, flags);ret = (ssize_t)size;return ret;
}
DEVICE_ATTR_RW(i2ccore_cmd_sta0_reg);static ssize_t
dump_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count)
{size_t i = 0;ssize_t status;uint8_t read_reg;size_t flags;struct device *dev = kobj_to_dev(kobj);struct ocores_i2c *i2c = dev_get_drvdata(dev);if ((off + count) > PORT_XCVR_REGISTER_SIZE)return -EINVAL;if (!dev || !i2c)return -EINVAL;spin_lock_irqsave(&i2c->process_lock, flags);while (i < count) {read_reg = ioread8(i2c->base + off + i);buf[i++] = read_reg;}spin_unlock_irqrestore(&i2c->process_lock, flags);status = count;return status;
}
static BIN_ATTR_RO(dump, PORT_XCVR_REGISTER_SIZE);static struct bin_attribute *fpga_i2c_bin_attrs[] = {&bin_attr_dump,NULL,
};static struct attribute *fpga_i2ccore_attrs[] = {&dev_attr_i2ccore_ctrl_reg.attr,&dev_attr_i2ccore_cmd_sta0_reg.attr,NULL,
};static struct attribute_group fpga_i2c_attr_grp = {.attrs = fpga_i2ccore_attrs,.bin_attrs = fpga_i2c_bin_attrs,
};static int32_t ocores_i2c_probe(struct platform_device *pdev)
{struct ocores_i2c *i2c;struct ocores_i2c_platform_data *pdata;struct resource *res;int32_t irq;int32_t ret;int32_t i;i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);if (!i2c)return -ENOMEM;spin_lock_init(&i2c->process_lock);res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (res) {i2c->base = devm_ioremap_resource(&pdev->dev, res);if (IS_ERR(i2c->base))return PTR_ERR(i2c->base);} else {res = platform_get_resource(pdev, IORESOURCE_IO, 0);if (!res)return -EINVAL;i2c->iobase = res->start;if (!devm_request_region(&pdev->dev, res->start, resource_size(res), pdev->name)) {dev_err(&pdev->dev, "Can't get I/O resource.\n");return -EBUSY;}i2c->setreg = oc_setreg_io_8;i2c->getreg = oc_getreg_io_8;}pdata = dev_get_platdata(&pdev->dev);if (pdata) {i2c->reg_shift = pdata->reg_shift;i2c->reg_io_width = pdata->reg_io_width;i2c->ip_clock_khz = pdata->clock_khz;if (pdata->bus_khz)i2c->bus_clock_khz = pdata->bus_khz;elsei2c->bus_clock_khz = 100;} else {ret = ocores_i2c_of_probe(pdev, i2c);if (ret)return ret;}if (i2c->reg_io_width == 0)i2c->reg_io_width = 4; /* Set 4 bytes width to default value */if (!i2c->setreg || !i2c->getreg) {bool be = pdata ? pdata->big_endian : of_device_is_big_endian(pdev->dev.of_node);switch (i2c->reg_io_width) {case 1:i2c->setreg = oc_setreg_8;i2c->getreg = oc_getreg_8;break;case 2:i2c->setreg = be ? oc_setreg_16be : oc_setreg_16;i2c->getreg = be ? oc_getreg_16be : oc_getreg_16;break;case 4:i2c->setreg = be ? oc_setreg_32be : oc_setreg_32;i2c->getreg = be ? oc_getreg_32be : oc_getreg_32;break;default:dev_err(&pdev->dev, "Unsupported I/O width (%d)\n", i2c->reg_io_width);ret = -EINVAL;goto err_clk;}}init_waitqueue_head(&i2c->wait);irq = platform_get_irq(pdev, 0);if (irq == -ENXIO) {i2c->flags |= OCORES_FLAG_POLL;} else {if (irq < 0)return irq;}if (!(i2c->flags & OCORES_FLAG_POLL)) {ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, pdev->name, i2c);if (ret) {dev_err(&pdev->dev, "Cannot claim IRQ\n");goto err_clk;}}ret = ocores_init(&pdev->dev, i2c);if (ret)goto err_clk;/* hook up driver to tree */platform_set_drvdata(pdev, i2c);i2c->adap = ocores_adapter;i2c_set_adapdata(&i2c->adap, i2c);i2c->adap.dev.parent = &pdev->dev;i2c->adap.dev.of_node = pdev->dev.of_node;/* add i2c adapter to i2c tree */ret = i2c_add_adapter(&i2c->adap);if (ret)goto err_clk;/* add in known devices to the bus */if (pdata) {for (i = 0; i < pdata->num_devices; i++)i2c_new_device(&i2c->adap,pdata->devices + i); //will put platform data to device.platform data and get use dev_get_platdata}ret = sysfs_create_group(&pdev->dev.kobj, &fpga_i2c_attr_grp);if (ret != 0) {pr_err("Cannot create FPGA_I2C sysfs attributes\n");goto err_clk;}return 0;err_clk:clk_disable_unprepare(i2c->clk);return ret;
}static int32_t ocores_i2c_remove(struct platform_device *pdev)
{struct ocores_i2c *i2c = platform_get_drvdata(pdev);uint8_t ctrl = oc_getreg(i2c, OCI2C_CONTROL);/* disable i2c logic */ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN);oc_setreg(i2c, OCI2C_CONTROL, ctrl);/* remove adapter & data */i2c_del_adapter(&i2c->adap);if(!pdev && !&pdev->dev.kobj)sysfs_remove_group(&pdev->dev.kobj, &fpga_i2c_attr_grp);if (!IS_ERR(i2c->clk))clk_disable_unprepare(i2c->clk);return 0;
}#ifdef CONFIG_PM_SLEEP
static int32_t ocores_i2c_suspend(struct device *dev)
{struct ocores_i2c *i2c = dev_get_drvdata(dev);uint8_t ctrl = oc_getreg(i2c, OCI2C_CONTROL);/* make sure the device is disabled */ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN);oc_setreg(i2c, OCI2C_CONTROL, ctrl);if (!IS_ERR(i2c->clk))clk_disable_unprepare(i2c->clk);return 0;
}static int32_t ocores_i2c_resume(struct device *dev)
{struct ocores_i2c *i2c = dev_get_drvdata(dev);if (!IS_ERR(i2c->clk)) {size_t rate;int32_t ret = clk_prepare_enable(i2c->clk);if (ret) {dev_err(dev, "clk_prepare_enable failed: %d\n", ret);return ret;}rate = clk_get_rate(i2c->clk) / 1000;if (rate)i2c->ip_clock_khz = rate;}return ocores_init(dev, i2c);
}static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume);
#define OCORES_I2C_PM (&ocores_i2c_pm)
#else
#define OCORES_I2C_PM NULL
#endifstatic struct platform_driver ocores_i2c_driver = {.probe = ocores_i2c_probe,.remove = ocores_i2c_remove,.driver = {.name = "ocores-i2c-hq",.of_match_table = ocores_i2c_match,.pm = OCORES_I2C_PM,},
};module_platform_driver(ocores_i2c_driver);MODULE_AUTHOR("Peter Korsgaard ");
MODULE_DESCRIPTION("OpenCores I2C bus driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ocores-i2c");

i2c_kobj_sysfs.h

/** i2c_kobj_sysfs.h - The i2c device sysfs library header** Copyright 2015-present Facebook. All Rights Reserved.** 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.*/#ifndef I2C_KOBJ_SYSFS_H
#define I2C_KOBJ_SYSFS_H#include 
#include typedef ssize_t (*i2c_kobj_attr_show_fn)(struct kobject *kobj, struct kobj_attribute *attr, char *buf);
typedef ssize_t (*i2c_kobj_attr_store_fn)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count);#define I2C_KOBJ_ATTR_SHOW_DEFAULT  (i2c_kobj_attr_show_fn)(1)
#define I2C_KOBJ_ATTR_STORE_DEFAULT (i2c_kobj_attr_store_fn)(1)typedef struct i2c_kobj_attr_st_ {const int8_t *ida_name;const char *ida_help;i2c_kobj_attr_show_fn ida_show;i2c_kobj_attr_store_fn ida_store;int32_t ida_reg;int32_t ida_bit_offset;int32_t ida_n_bits;size_t enable_log_on_write : 1;
} i2c_kobj_attr_st;typedef struct i2c_sysfs_attr_st_ {struct kobj_attribute isa_kobj_attr;const i2c_kobj_attr_st *isa_i2c_attr;
} i2c_sysfs_attr_st;#define TO_I2C_SYSFS_ATTR(_attr) container_of(_attr, i2c_sysfs_attr_st, isa_kobj_attr)typedef struct i2c_kobj_data_st_ {struct device *idd_hwmon_dev;struct mutex idd_lock;i2c_sysfs_attr_st *idd_attrs;struct attribute_group idd_attr_group;
} i2c_kobj_data_st;int32_t i2c_kobj_sysfs_data_complex_init(struct i2c_client *client,i2c_kobj_data_st *data,const i2c_kobj_attr_st *dev_attrs,int32_t n_attrs,const char *dir);void i2c_kobj_sysfs_data_clean(struct i2c_client *client, i2c_kobj_data_st *data);
#endif

i2c_kobj_sysfs.c

/** i2c_kobj_sysfs.c - The i2c device sysfs library** Copyright 2015-present Facebook. All Rights Reserved.** 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.    光模块i2c接口*///#define DEBUG#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "i2c_kobj_sysfs.h"#ifdef DEBUG#define PP_DEBUG(fmt, ...)                                                           \do {                                                                             \printk(KERN_DEBUG "%s:%d " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__); \} while (0)#else /* !DEBUG */#define PP_DEBUG(fmt, ...)#endifstatic ssize_t i2c_kobj_sysfs_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{struct i2c_client *client = kobj_to_i2c_client(kobj);i2c_sysfs_attr_st *i2c_attr;int32_t val, val_mask, reg_val;const i2c_kobj_attr_st *dev_attr;i2c_attr = TO_I2C_SYSFS_ATTR(attr);if (!i2c_attr)return -ENODEV;dev_attr = i2c_attr->isa_i2c_attr;if (!dev_attr)return -ENODEV;if (!dev_attr->ida_show) {return -EOPNOTSUPP;}if (client == NULL)return -ENODEV;if (dev_attr->ida_show != I2C_KOBJ_ATTR_SHOW_DEFAULT) {return dev_attr->ida_show(kobj, attr, buf);}val_mask = (1 << (dev_attr->ida_n_bits)) - 1;/* default handling */reg_val = i2c_smbus_read_byte_data(client, dev_attr->ida_reg);if (reg_val < 0) {/* error case */return reg_val;}val = (reg_val >> dev_attr->ida_bit_offset) & val_mask;return scnprintf(buf, PAGE_SIZE,"%#x\n\nNote:\n%s\n""Bit[%d:%d] @ register %#x, register value %#x\n",val, (dev_attr->ida_help) ? dev_attr->ida_help : "", dev_attr->ida_bit_offset + dev_attr->ida_n_bits - 1,dev_attr->ida_bit_offset, dev_attr->ida_reg, reg_val);
}static ssize_t i2c_kobj_sysfs_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{struct i2c_client *client = kobj_to_i2c_client(kobj);// i2c_kobj_data_st *data = i2c_get_clientdata(client);int32_t val;int32_t req_val;int32_t req_val_mask;i2c_sysfs_attr_st *i2c_attr;const i2c_kobj_attr_st *dev_attr;// if (!data)//     return -ENODEV;i2c_attr = TO_I2C_SYSFS_ATTR(attr);if (!i2c_attr)return -ENODEV;dev_attr = i2c_attr->isa_i2c_attr;if (!dev_attr)return -ENODEV;if (!dev_attr->ida_store) {return -EOPNOTSUPP;}  if (dev_attr->ida_store != I2C_KOBJ_ATTR_STORE_DEFAULT) {return dev_attr->ida_store(kobj, attr, buf, count);}/* parse the buffer */if (sscanf(buf, "%i", &req_val) <= 0) {return -EINVAL;}// req_val_mask = ~(((-1) >> (dev_attr->ida_n_bits)) << (dev_attr->ida_n_bits));req_val_mask = ~(((0xffffffff) >> (dev_attr->ida_n_bits)) << (dev_attr->ida_n_bits));req_val &= req_val_mask;/* default handling, first read back the current value */val = i2c_smbus_read_byte_data(client, dev_attr->ida_reg);if (val < 0) {/* fail to read */goto unlock_out;}// mutex_lock(&data->idd_lock);/* mask out all bits for the value requested */val &= ~(req_val_mask << dev_attr->ida_bit_offset);val |= req_val << dev_attr->ida_bit_offset;// mutex_unlock(&data->idd_lock);val = i2c_smbus_write_byte_data(client, dev_attr->ida_reg, val);unlock_out:if (val < 0) {/* error case */return val;}if (dev_attr->enable_log_on_write) {pr_crit("Wrote %#x to %s -> %s by pid %ld (cmd=%s)\n", req_val, client->name, i2c_attr->isa_kobj_attr.attr.name,(ssize_t)current->pid, current->comm);}return count;
}void i2c_kobj_sysfs_data_clean(struct i2c_client *client, i2c_kobj_data_st *data)
{if (!data) {return;}if (data->idd_attr_group.attrs) {sysfs_remove_group(&client->dev.kobj, &data->idd_attr_group);kfree(data->idd_attr_group.attrs);}if (data->idd_attrs) {kfree(data->idd_attrs);}memset(data, 0, sizeof(*data));
}
EXPORT_SYMBOL_GPL(i2c_kobj_sysfs_data_clean);int32_t i2c_kobj_sysfs_data_complex_init(struct i2c_client *client,i2c_kobj_data_st *data,const i2c_kobj_attr_st *dev_attrs,int32_t n_attrs,const char *dir)
{int32_t i;int32_t err;i2c_sysfs_attr_st *cur_attr;const i2c_kobj_attr_st *cur_kobj_attr;struct attribute **cur_grp_attr;static struct kobject *dir_kobj = NULL;memset(data, 0, sizeof(*data)); //devm_kzalloc to create data, and don't need free,remove data interfacei2c_set_clientdata(client, data);mutex_init(&data->idd_lock);/* allocate all attribute */data->idd_attrs = kzalloc(sizeof(*data->idd_attrs) * n_attrs, GFP_KERNEL); //same devm_kzalloc/* allocate the attribute group. +1 for the last NULL */data->idd_attr_group.attrs = kzalloc(sizeof(*data->idd_attr_group.attrs) * (n_attrs + 1), GFP_KERNEL);if (!data->idd_attrs || !data->idd_attr_group.attrs) {err = -ENOMEM;goto exit_cleanup;}PP_DEBUG("Allocated %u attributes", n_attrs);for (i = 0, cur_attr = &data->idd_attrs[0], cur_grp_attr = &data->idd_attr_group.attrs[0], cur_kobj_attr = dev_attrs;i < n_attrs; i++, cur_attr++, cur_grp_attr++, cur_kobj_attr++) {mode_t mode = S_IRUGO;if (cur_kobj_attr->ida_store) {mode |= S_IWUSR;}cur_attr->isa_kobj_attr.attr.name = cur_kobj_attr->ida_name;cur_attr->isa_kobj_attr.attr.mode = mode;cur_attr->isa_kobj_attr.show = i2c_kobj_sysfs_show;cur_attr->isa_kobj_attr.store = i2c_kobj_sysfs_store;*cur_grp_attr = &cur_attr->isa_kobj_attr.attr;cur_attr->isa_i2c_attr = cur_kobj_attr;PP_DEBUG("Created attribute \"%s\"", cur_attr->isa_kobj_attr.attr.name);}/* Register sysfs hooks */if (dir != NULL && dir[0] != 0) {dir_kobj = kobject_create_and_add(dir, &client->dev.kobj);if (!dir_kobj) {dev_err(&client->dev, "failed to create kobject.\n");return -ENOMEM;}if ((err = sysfs_create_group(dir_kobj, &data->idd_attr_group))) {goto exit_cleanup;}} else {if ((err = sysfs_create_group(&client->dev.kobj, &data->idd_attr_group))) {goto exit_cleanup;}}PP_DEBUG("i2c device sysfs init data done");return 0;exit_cleanup:i2c_kobj_sysfs_data_clean(client, data);return err;
}
EXPORT_SYMBOL_GPL(i2c_kobj_sysfs_data_complex_init);MODULE_AUTHOR("Tian Fang ");
MODULE_DESCRIPTION("i2c device sysfs attribute library");
MODULE_LICENSE("GPL");

i2c_dev_sysfs.h

/** i2c_dev_sysfs.h - The i2c device sysfs library header** Copyright 2015-present Facebook. All Rights Reserved.** 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.*/#ifndef I2C_DEV_SYSFS_H
#define I2C_DEV_SYSFS_H#include 
#include typedef ssize_t (*i2c_dev_attr_show_fn)(struct device *dev, struct device_attribute *attr, char *buf);
typedef ssize_t (*i2c_dev_attr_store_fn)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);#define I2C_DEV_ATTR_SHOW_DEFAULT  (i2c_dev_attr_show_fn)(1)
#define I2C_DEV_ATTR_STORE_DEFAULT (i2c_dev_attr_store_fn)(1)typedef struct i2c_dev_attr_st_ {const int8_t *ida_name;const char *ida_help;i2c_dev_attr_show_fn ida_show;i2c_dev_attr_store_fn ida_store;int32_t ida_reg;int32_t ida_bit_offset;int32_t ida_n_bits;size_t enable_log_on_write : 1;
} i2c_dev_attr_st;typedef struct i2c_sysfs_attr_st_ {struct device_attribute isa_dev_attr;const i2c_dev_attr_st *isa_i2c_attr;
} i2c_sysfs_attr_st;#define TO_I2C_SYSFS_ATTR(_attr) container_of(_attr, i2c_sysfs_attr_st, isa_dev_attr)typedef struct i2c_dev_data_st_ {struct device *idd_hwmon_dev;struct mutex idd_lock;i2c_sysfs_attr_st *idd_attrs;struct attribute_group idd_attr_group;
} i2c_dev_data_st;int32_t i2c_dev_sysfs_data_init(struct i2c_client *client,i2c_dev_data_st *data,const i2c_dev_attr_st *dev_attrs,int32_t n_attrs);
void i2c_dev_sysfs_data_clean(struct i2c_client *client, i2c_dev_data_st *data);
int32_t i2c_dev_read_byte(struct device *dev, struct device_attribute *attr);
int32_t i2c_dev_read_nbytes(struct device *dev, struct device_attribute *attr, uint8_t values[], int32_t nbytes);
int32_t i2c_dev_read_word_littleendian(struct device *dev, struct device_attribute *attr);
int32_t i2c_dev_read_word_bigendian(struct device *dev, struct device_attribute *attr);
ssize_t i2c_dev_show_label(struct device *dev, struct device_attribute *attr, char *buf);
ssize_t i2c_dev_show_ascii(struct device *dev, struct device_attribute *attr, char *buf);#endif

i2c_dev_sysfs.c

/** i2c_dev_sysfs.c - The i2c device sysfs library** Copyright 2015-present Facebook. All Rights Reserved.** 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.   电压电流传感器接口*/ //#define DEBUG#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include #include "i2c_dev_sysfs.h"#ifdef DEBUG#define PP_DEBUG(fmt, ...)                                                           \do {                                                                             \printk(KERN_DEBUG "%s:%d " fmt "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__); \} while (0)#else /* !DEBUG */#define PP_DEBUG(fmt, ...)#endifssize_t i2c_dev_show_label(struct device *dev, struct device_attribute *attr, char *buf)
{i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);const i2c_dev_attr_st *dev_attr;if (!i2c_attr)return -ENODEV;dev_attr = i2c_attr->isa_i2c_attr;if (!dev_attr)return -ENODEV;if (dev_attr->ida_help) {return snprintf(buf, PAGE_SIZE, "%s\n", dev_attr->ida_help);}return snprintf(buf, PAGE_SIZE, "%s\n", dev_attr->ida_name);
}
EXPORT_SYMBOL_GPL(i2c_dev_show_label);int32_t i2c_dev_read_byte(struct device *dev, struct device_attribute *attr)
{struct i2c_client *client = to_i2c_client(dev);i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);const i2c_dev_attr_st *dev_attr;int32_t val;int32_t val_mask;uint32_t i = 0xFFFFFFFF;if (!i2c_attr)return -ENODEV;dev_attr = i2c_attr->isa_i2c_attr;if (!dev_attr)return -ENODEV;val_mask = ~(((i) >> (dev_attr->ida_n_bits)) << (dev_attr->ida_n_bits));val = i2c_smbus_read_byte_data(client, dev_attr->ida_reg);if (val < 0) {/* error case */return val;}val = (val >> dev_attr->ida_bit_offset) & val_mask;return val;
}
EXPORT_SYMBOL_GPL(i2c_dev_read_byte);int32_t i2c_dev_read_nbytes(struct device *dev, struct device_attribute *attr, uint8_t values[], int32_t nbytes)
{struct i2c_client *client = to_i2c_client(dev);i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);int32_t i;int32_t ret_val;const i2c_dev_attr_st *dev_attr;if (!i2c_attr)return -ENODEV;dev_attr = i2c_attr->isa_i2c_attr;if (!dev_attr)return -ENODEV;for (i = 0; i < nbytes; ++i) {ret_val = i2c_smbus_read_byte_data(client, dev_attr->ida_reg + i);if (ret_val < 0) {return ret_val;}if (ret_val > 255) {return EFAULT;}values[i] = ret_val;}return nbytes;
}
EXPORT_SYMBOL_GPL(i2c_dev_read_nbytes);int32_t i2c_dev_read_word_littleendian(struct device *dev, struct device_attribute *attr)
{uint8_t values[2];int32_t ret_val;ret_val = i2c_dev_read_nbytes(dev, attr, values, 2);if (ret_val < 0) {return ret_val;}// values[0] : LSB// values[1] : MSBreturn ((values[1] << 8) + values[0]);
}
EXPORT_SYMBOL_GPL(i2c_dev_read_word_littleendian);int32_t i2c_dev_read_word_bigendian(struct device *dev, struct device_attribute *attr)
{uint8_t values[2];int32_t ret_val;ret_val = i2c_dev_read_nbytes(dev, attr, values, 2);if (ret_val < 0) {return ret_val;}// values[0] : MSB// values[1] : LSBreturn ((values[0] << 8) + values[1]);
}
EXPORT_SYMBOL_GPL(i2c_dev_read_word_bigendian);ssize_t i2c_dev_show_ascii(struct device *dev, struct device_attribute *attr, char *buf)
{i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);const i2c_dev_attr_st *dev_attr;int32_t nbytes, ret_val;if (!i2c_attr)return -ENODEV;dev_attr = i2c_attr->isa_i2c_attr;if (!dev_attr)return -ENODEV;nbytes = (dev_attr->ida_n_bits) / 8;ret_val = i2c_dev_read_nbytes(dev, attr, buf, nbytes);if (ret_val < 0) {return ret_val;}//buf[] : ascii databuf[nbytes] = '\n';return (nbytes + 1);
}
EXPORT_SYMBOL_GPL(i2c_dev_show_ascii);static ssize_t i2c_dev_sysfs_show(struct device *dev, struct device_attribute *attr, char *buf)
{struct i2c_client *client = to_i2c_client(dev);i2c_sysfs_attr_st *i2c_attr = TO_I2C_SYSFS_ATTR(attr);int32_t val, val_mask, reg_val;const i2c_dev_attr_st *dev_attr;if (!i2c_attr)return -ENODEV;dev_attr = i2c_attr->isa_i2c_attr;if (!dev_attr)return -ENODEV;if (!dev_attr->ida_show) {return -EOPNOTSUPP;}if (client == NULL)return -ENODEV;if (dev_attr->ida_show != I2C_DEV_ATTR_SHOW_DEFAULT) {return dev_attr->ida_show(dev, attr, buf);}val_mask = (1 << (dev_attr->ida_n_bits)) - 1;/* default handling */reg_val = i2c_smbus_read_byte_data(client, dev_attr->ida_reg);if (reg_val < 0) {/* error case */return reg_val;}val = (reg_val >> dev_attr->ida_bit_offset) & val_mask;return scnprintf(buf, PAGE_SIZE,"%#x\n\nNote:\n%s\n""Bit[%d:%d] @ register %#x, register value %#x\n",val, (dev_attr->ida_help) ? dev_attr->ida_help : "", dev_attr->ida_bit_offset + dev_attr->ida_n_bits - 1,dev_attr->ida_bit_offset, dev_attr->ida_reg, reg_val);
}static ssize_t i2c_dev_sysfs_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{struct i2c_client *client = to_i2c_client(dev);i2c_dev_data_st *data = i2c_get_clientdata(client);int32_t val;int32_t req_val;int32_t req_val_mask;uint32_t i = 0xFFFFFFFF;i2c_sysfs_attr_st *i2c_attr;const i2c_dev_attr_st *dev_attr;if (!data)return -ENODEV;i2c_attr = TO_I2C_SYSFS_ATTR(attr);if (!i2c_attr)return -ENODEV;dev_attr = i2c_attr->isa_i2c_attr;if (!dev_attr)return -ENODEV;if (!dev_attr->ida_store) {return -EOPNOTSUPP;}if (dev_attr->ida_store != I2C_DEV_ATTR_STORE_DEFAULT) {return dev_attr->ida_store(dev, attr, buf, count);}/* parse the buffer */if (sscanf(buf, "%i", &req_val) <= 0) {return -EINVAL;}req_val_mask = ~(((i) >> (dev_attr->ida_n_bits)) << (dev_attr->ida_n_bits));req_val &= req_val_mask;/* default handling, first read back the current value */val = i2c_smbus_read_byte_data(client, dev_attr->ida_reg);if (val < 0) {/* fail to read */goto unlock_out;}mutex_lock(&data->idd_lock);/* mask out all bits for the value requested */val &= ~(req_val_mask << dev_attr->ida_bit_offset);val |= req_val << dev_attr->ida_bit_offset;mutex_unlock(&data->idd_lock);val = i2c_smbus_write_byte_data(client, dev_attr->ida_reg, val);unlock_out:if (val < 0) {/* error case */return val;}if (dev_attr->enable_log_on_write) {pr_crit("Wrote %#x to %s -> %s by pid %ld (cmd=%s)\n", req_val, client->name, i2c_attr->isa_dev_attr.attr.name,(ssize_t)current->pid, current->comm);}return count;
}void i2c_dev_sysfs_data_clean(struct i2c_client *client, i2c_dev_data_st *data)
{if (!data) {return;}if (data->idd_hwmon_dev) {hwmon_device_unregister(data->idd_hwmon_dev);}if (data->idd_attr_group.attrs) {sysfs_remove_group(&client->dev.kobj, &data->idd_attr_group);kfree(data->idd_attr_group.attrs);}if (data->idd_attrs) {kfree(data->idd_attrs);}memset(data, 0, sizeof(*data));
}
EXPORT_SYMBOL_GPL(i2c_dev_sysfs_data_clean);int32_t i2c_dev_sysfs_data_init(struct i2c_client *client,i2c_dev_data_st *data,const i2c_dev_attr_st *dev_attrs,int32_t n_attrs)
{int32_t i;int32_t err;i2c_sysfs_attr_st *cur_attr;const i2c_dev_attr_st *cur_dev_attr;struct attribute **cur_grp_attr;memset(data, 0, sizeof(*data)); //devm_kzalloc to create data, and don't need free,remove data interfacei2c_set_clientdata(client, data);mutex_init(&data->idd_lock);/* allocate all attribute */data->idd_attrs = kzalloc(sizeof(*data->idd_attrs) * n_attrs, GFP_KERNEL); //same devm_kzalloc/* allocate the attribute group. +1 for the last NULL */data->idd_attr_group.attrs = kzalloc(sizeof(*data->idd_attr_group.attrs) * (n_attrs + 1), GFP_KERNEL);if (!data->idd_attrs || !data->idd_attr_group.attrs) {err = -ENOMEM;goto exit_cleanup;}PP_DEBUG("Allocated %u attributes", n_attrs);for (i = 0, cur_attr = &data->idd_attrs[0], cur_grp_attr = &data->idd_attr_group.attrs[0], cur_dev_attr = dev_attrs;i < n_attrs; i++, cur_attr++, cur_grp_attr++, cur_dev_attr++) {mode_t mode = S_IRUGO;if (cur_dev_attr->ida_store) {mode |= S_IWUSR;}cur_attr->isa_dev_attr.attr.name = cur_dev_attr->ida_name;cur_attr->isa_dev_attr.attr.mode = mode;cur_attr->isa_dev_attr.show = i2c_dev_sysfs_show;cur_attr->isa_dev_attr.store = i2c_dev_sysfs_store;*cur_grp_attr = &cur_attr->isa_dev_attr.attr;cur_attr->isa_i2c_attr = cur_dev_attr;PP_DEBUG("Created attribute \"%s\"", cur_attr->isa_dev_attr.attr.name);}/* Register sysfs hooks */if ((err = sysfs_create_group(&client->dev.kobj, &data->idd_attr_group))) {goto exit_cleanup;}data->idd_hwmon_dev = hwmon_device_register_with_groups(&client->dev, client->name, NULL, NULL);if (IS_ERR(data->idd_hwmon_dev)) {err = PTR_ERR(data->idd_hwmon_dev);data->idd_hwmon_dev = NULL;goto exit_cleanup;}PP_DEBUG("i2c device sysfs init data done");return 0;exit_cleanup:i2c_dev_sysfs_data_clean(client, data);return err;
}
EXPORT_SYMBOL_GPL(i2c_dev_sysfs_data_init);MODULE_AUTHOR("Tian Fang ");
MODULE_DESCRIPTION("i2c device sysfs attribute library");
MODULE_LICENSE("GPL");

hwmon-sysfs.h

/* SPDX-License-Identifier: GPL-2.0-or-later */
/**  hwmon-sysfs.h - hardware monitoring chip driver sysfs defines**  Copyright (C) 2005 Yani Ioannou     电压电流传感器*/
#ifndef _LINUX_HWMON_SYSFS_H
#define _LINUX_HWMON_SYSFS_H#include struct sensor_device_attribute {struct device_attribute dev_attr;int index;
};
#define to_sensor_dev_attr(_dev_attr) \container_of(_dev_attr, struct sensor_device_attribute, dev_attr)#define SENSOR_ATTR(_name, _mode, _show, _store, _index) \{                                                    \.dev_attr = __ATTR(_name, _mode, _show, _store), \.index = _index                                  \}#define SENSOR_ATTR_RO(_name, _func, _index) \SENSOR_ATTR(_name, 0444, _func##_show, NULL, _index)#define SENSOR_ATTR_RW(_name, _func, _index) \SENSOR_ATTR(_name, 0644, _func##_show, _func##_store, _index)#define SENSOR_ATTR_WO(_name, _func, _index) \SENSOR_ATTR(_name, 0200, NULL, _func##_store, _index)#define SENSOR_DEVICE_ATTR(_name, _mode, _show, _store, _index) \struct sensor_device_attribute sensor_dev_attr_##_name      \= SENSOR_ATTR(_name, _mode, _show, _store, _index)#define SENSOR_DEVICE_ATTR_RO(_name, _func, _index) \SENSOR_DEVICE_ATTR(_name, 0444, _func##_show, NULL, _index)#define SENSOR_DEVICE_ATTR_RW(_name, _func, _index) \SENSOR_DEVICE_ATTR(_name, 0644, _func##_show, _func##_store, _index)#define SENSOR_DEVICE_ATTR_WO(_name, _func, _index) \SENSOR_DEVICE_ATTR(_name, 0200, NULL, _func##_store, _index)struct sensor_device_attribute_2 {struct device_attribute dev_attr;u8 index;u8 nr;
};
#define to_sensor_dev_attr_2(_dev_attr) \container_of(_dev_attr, struct sensor_device_attribute_2, dev_attr)#define SENSOR_ATTR_2(_name, _mode, _show, _store, _nr, _index) \{                                                           \.dev_attr = __ATTR(_name, _mode, _show, _store),        \.index = _index,                                        \.nr = _nr                                               \}#define SENSOR_ATTR_2_RO(_name, _func, _nr, _index) \SENSOR_ATTR_2(_name, 0444, _func##_show, NULL, _nr, _index)#define SENSOR_ATTR_2_RW(_name, _func, _nr, _index) \SENSOR_ATTR_2(_name, 0644, _func##_show, _func##_store, _nr, _index)#define SENSOR_ATTR_2_WO(_name, _func, _nr, _index) \SENSOR_ATTR_2(_name, 0200, NULL, _func##_store, _nr, _index)#define SENSOR_DEVICE_ATTR_2(_name, _mode, _show, _store, _nr, _index) \struct sensor_device_attribute_2 sensor_dev_attr_##_name           \= SENSOR_ATTR_2(_name, _mode, _show, _store, _nr, _index)#define SENSOR_DEVICE_ATTR_2_RO(_name, _func, _nr, _index) \SENSOR_DEVICE_ATTR_2(_name, 0444, _func##_show, NULL, _nr, _index)#define SENSOR_DEVICE_ATTR_2_RW(_name, _func, _nr, _index) \SENSOR_DEVICE_ATTR_2(_name, 0644, _func##_show, _func##_store, _nr, _index)#define SENSOR_DEVICE_ATTR_2_WO(_name, _func, _nr, _index) \SENSOR_DEVICE_ATTR_2(_name, 0200, NULL, _func##_store, _nr, _index)#endif /* _LINUX_HWMON_SYSFS_H */

gpio-ich.c

// SPDX-License-Identifier: GPL-2.0+
/** Intel ICH6-10, Series 5 and 6, Atom C2000 (Avoton/Rangeley) GPIO driver** Copyright (C) 2010 Extreme Engineering Solutions.*/#include 
#include 
#include 
#include 
#include 
#include #define DRV_NAME "gpio_ich"
#define GPIO_LINE_DIRECTION_IN  1
#define GPIO_LINE_DIRECTION_OUT 0/** GPIO register offsets in GPIO I/O space.* Each chunk of 32 GPIOs is manipulated via its own USE_SELx, IO_SELx, and* LVLx registers.  Logic in the read/write functions takes a register and* an absolute bit number and determines the proper register offset and bit* number in that register.  For example, to read the value of GPIO bit 50* the code would access offset ichx_regs[2(=GPIO_LVL)][1(=50/32)],* bit 18 (50%32).* * * 读写gpio,接口在cpld_i2c一样,适配很多cpu*/
enum GPIO_REG {GPIO_USE_SEL = 0,GPIO_IO_SEL,GPIO_LVL,GPO_BLINK
};static const u8 ichx_regs[4][3] = {{0x00, 0x30, 0x40},	/* USE_SEL[1-3] offsets */{0x04, 0x34, 0x44},	/* IO_SEL[1-3] offsets */{0x0c, 0x38, 0x48},	/* LVL[1-3] offsets */{0x18, 0x18, 0x18},	/* BLINK offset */
};static const u8 ichx_reglen[3] = {0x30, 0x10, 0x10,
};static const u8 avoton_regs[4][3] = {{0x00, 0x80, 0x00},{0x04, 0x84, 0x00},{0x08, 0x88, 0x00},
};static const u8 avoton_reglen[3] = {0x10, 0x10, 0x00,
};#define ICHX_WRITE(val, reg, base_res)	outl(val, (reg) + (base_res)->start)
#define ICHX_READ(reg, base_res)	inl((reg) + (base_res)->start)struct ichx_desc {/* Max GPIO pins the chipset can have */uint ngpio;/* chipset registers */const u8 (*regs)[3];const u8 *reglen;/* GPO_BLINK is available on this chipset */bool have_blink;/* Whether the chipset has GPIO in GPE0_STS in the PM IO region */bool uses_gpe0;/* USE_SEL is bogus on some chipsets, eg 3100 */u32 use_sel_ignore[3];/* Some chipsets have quirks, let these use their own request/get */int (*request)(struct gpio_chip *chip, unsigned int offset);int (*get)(struct gpio_chip *chip, unsigned int offset);/** Some chipsets don't let reading output values on GPIO_LVL register* this option allows driver caching written output values*/bool use_outlvl_cache;
};static struct {spinlock_t lock;struct device *dev;struct gpio_chip chip;struct resource *gpio_base;	/* GPIO IO base */struct resource *pm_base;	/* Power Management IO base */struct ichx_desc *desc;	/* Pointer to chipset-specific description */u32 orig_gpio_ctrl;	/* Orig CTRL value, used to restore on exit */u8 use_gpio;		/* Which GPIO groups are usable */int outlvl_cache[3];	/* cached output values */
} ichx_priv;static int modparam_gpiobase = -1;	/* dynamic */
module_param_named(gpiobase, modparam_gpiobase, int, 0444);
MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default.");static int ichx_write_bit(int reg, unsigned int nr, int val, int verify)
{unsigned long flags;u32 data, tmp;int reg_nr = nr / 32;int bit = nr & 0x1f;spin_lock_irqsave(&ichx_priv.lock, flags);if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)data = ichx_priv.outlvl_cache[reg_nr];elsedata = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr],ichx_priv.gpio_base);if (val)data |= BIT(bit);elsedata &= ~BIT(bit);ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr],ichx_priv.gpio_base);if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)ichx_priv.outlvl_cache[reg_nr] = data;tmp = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr],ichx_priv.gpio_base);spin_unlock_irqrestore(&ichx_priv.lock, flags);return (verify && data != tmp) ? -EPERM : 0;
}static int ichx_read_bit(int reg, unsigned int nr)
{unsigned long flags;u32 data;int reg_nr = nr / 32;int bit = nr & 0x1f;spin_lock_irqsave(&ichx_priv.lock, flags);data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr],ichx_priv.gpio_base);if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache)data = ichx_priv.outlvl_cache[reg_nr] | data;spin_unlock_irqrestore(&ichx_priv.lock, flags);return !!(data & BIT(bit));
}static bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned int nr)
{
//	return !!(ichx_priv.use_gpio & BIT(nr / 32));return (ichx_priv.use_gpio & (1 << (nr / 32))) ? 0 : -ENXIO;
}static int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned int nr)
{if (ichx_read_bit(GPIO_IO_SEL, nr))return GPIO_LINE_DIRECTION_IN;return GPIO_LINE_DIRECTION_OUT;
}static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr)
{/** Try setting pin as an input and verify it worked since many pins* are output-only.*/return ichx_write_bit(GPIO_IO_SEL, nr, 1, 1);
}static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr,int val)
{/* Disable blink hardware which is available for GPIOs from 0 to 31. */if (nr < 32 && ichx_priv.desc->have_blink)ichx_write_bit(GPO_BLINK, nr, 0, 0);/* Set GPIO output value. */ichx_write_bit(GPIO_LVL, nr, val, 0);/** Try setting pin as an output and verify it worked since many pins* are input-only.*/return ichx_write_bit(GPIO_IO_SEL, nr, 0, 1);
}static int ichx_gpio_get(struct gpio_chip *chip, unsigned int nr)
{if (!ichx_gpio_check_available(chip, nr))   /return -ENXIO;return ichx_read_bit(GPIO_LVL, nr);
}static int ich6_gpio_get(struct gpio_chip *chip, unsigned int nr)
{unsigned long flags;u32 data;/** GPI 0 - 15 need to be read from the power management registers on* a ICH6/3100 bridge.*/if (nr < 16) {if (!ichx_priv.pm_base)return -ENXIO;spin_lock_irqsave(&ichx_priv.lock, flags);/* GPI 0 - 15 are latched, write 1 to clear*/ICHX_WRITE(BIT(16 + nr), 0, ichx_priv.pm_base);data = ICHX_READ(0, ichx_priv.pm_base);spin_unlock_irqrestore(&ichx_priv.lock, flags);return !!((data >> 16) & BIT(nr));} else {return ichx_gpio_get(chip, nr);}
}static int ichx_gpio_request(struct gpio_chip *chip, unsigned int nr)
{if (!ichx_gpio_check_available(chip, nr))return -ENXIO;/** Note we assume the BIOS properly set a bridge's USE value.  Some* chips (eg Intel 3100) have bogus USE values though, so first see if* the chipset's USE value can be trusted for this specific bit.* If it can't be trusted, assume that the pin can be used as a GPIO.*/if (ichx_priv.desc->use_sel_ignore[nr / 32] & BIT(nr & 0x1f))return 0;return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV;
}static int ich6_gpio_request(struct gpio_chip *chip, unsigned int nr)
{/** Fixups for bits 16 and 17 are necessary on the Intel ICH6/3100* bridge as they are controlled by USE register bits 0 and 1.  See* "Table 704 GPIO_USE_SEL1 register" in the i3100 datasheet for* additional info.*/if (nr == 16 || nr == 17)nr -= 16;return ichx_gpio_request(chip, nr);
}static void ichx_gpio_set(struct gpio_chip *chip, unsigned int nr, int val)
{ichx_write_bit(GPIO_LVL, nr, val, 0);
}static void ichx_gpiolib_setup(struct gpio_chip *chip)
{chip->owner = THIS_MODULE;chip->label = DRV_NAME;chip->parent = ichx_priv.dev;/* Allow chip-specific overrides of request()/get() */chip->request = ichx_priv.desc->request ?ichx_priv.desc->request : ichx_gpio_request;chip->get = ichx_priv.desc->get ?ichx_priv.desc->get : ichx_gpio_get;chip->set = ichx_gpio_set;chip->get_direction = ichx_gpio_get_direction;chip->direction_input = ichx_gpio_direction_input;chip->direction_output = ichx_gpio_direction_output;chip->base = modparam_gpiobase;chip->ngpio = ichx_priv.desc->ngpio;chip->can_sleep = false;chip->dbg_show = NULL;
}/* ICH6-based, 631xesb-based */
static struct ichx_desc ich6_desc = {/* Bridges using the ICH6 controller need fixups for GPIO 0 - 17 */.request = ich6_gpio_request,.get = ich6_gpio_get,/* GPIO 0-15 are read in the GPE0_STS PM register */.uses_gpe0 = true,.ngpio = 50,.have_blink = true,.regs = ichx_regs,.reglen = ichx_reglen,
};/* Intel 3100 */
static struct ichx_desc i3100_desc = {/** Bits 16,17, 20 of USE_SEL and bit 16 of USE_SEL2 always read 0 on* the Intel 3100.  See "Table 712. GPIO Summary Table" of 3100* Datasheet for more info.*/.use_sel_ignore = {0x00130000, 0x00010000, 0x0},/* The 3100 needs fixups for GPIO 0 - 17 */.request = ich6_gpio_request,.get = ich6_gpio_get,/* GPIO 0-15 are read in the GPE0_STS PM register */.uses_gpe0 = true,.ngpio = 50,.regs = ichx_regs,.reglen = ichx_reglen,
};/* ICH7 and ICH8-based */
static struct ichx_desc ich7_desc = {.ngpio = 50,.have_blink = true,.regs = ichx_regs,.reglen = ichx_reglen,
};/* ICH9-based */
static struct ichx_desc ich9_desc = {.ngpio = 61,.have_blink = true,.regs = ichx_regs,.reglen = ichx_reglen,
};/* ICH10-based - Consumer/corporate versions have different amount of GPIO */
static struct ichx_desc ich10_cons_desc = {.ngpio = 61,.have_blink = true,.regs = ichx_regs,.reglen = ichx_reglen,
};
static struct ichx_desc ich10_corp_desc = {.ngpio = 72,.have_blink = true,.regs = ichx_regs,.reglen = ichx_reglen,
};/* Intel 5 series, 6 series, 3400 series, and C200 series */
static struct ichx_desc intel5_desc = {.ngpio = 76,.regs = ichx_regs,.reglen = ichx_reglen,
};/* Avoton */
static struct ichx_desc avoton_desc = {/* Avoton has only 59 GPIOs, but we assume the first set of register* (Core) has 32 instead of 31 to keep gpio-ich compliance*/.ngpio = 60,.regs = avoton_regs,.reglen = avoton_reglen,.use_outlvl_cache = true,
};static int ichx_gpio_request_regions(struct device *dev,struct resource *res_base, const char *name, u8 use_gpio)
{int i;if (!res_base || !res_base->start || !res_base->end)return -ENODEV;for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) {if (!(use_gpio & BIT(i)))continue;if (!devm_request_region(dev,res_base->start + ichx_priv.desc->regs[0][i],ichx_priv.desc->reglen[i], name))return -EBUSY;}return 0;
}static int ichx_gpio_probe(struct platform_device *pdev)
{struct device *dev = &pdev->dev;struct lpc_ich_info *ich_info = dev_get_platdata(dev);struct resource *res_base, *res_pm;int err;if (!ich_info)return -ENODEV;switch (ich_info->gpio_version) {case ICH_I3100_GPIO:ichx_priv.desc = &i3100_desc;break;case ICH_V5_GPIO:ichx_priv.desc = &intel5_desc;break;case ICH_V6_GPIO:ichx_priv.desc = &ich6_desc;break;case ICH_V7_GPIO:ichx_priv.desc = &ich7_desc;break;case ICH_V9_GPIO:ichx_priv.desc = &ich9_desc;break;case ICH_V10CORP_GPIO:ichx_priv.desc = &ich10_corp_desc;break;case ICH_V10CONS_GPIO:ichx_priv.desc = &ich10_cons_desc;break;case AVOTON_GPIO:ichx_priv.desc = &avoton_desc;break;default:return -ENODEV;}ichx_priv.dev = dev;spin_lock_init(&ichx_priv.lock);res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO);err = ichx_gpio_request_regions(dev, res_base, pdev->name,ich_info->use_gpio);if (err)return err;ichx_priv.gpio_base = res_base;ichx_priv.use_gpio = ich_info->use_gpio;/** If necessary, determine the I/O address of ACPI/power management* registers which are needed to read the GPE0 register for GPI pins* 0 - 15 on some chipsets.*/if (!ichx_priv.desc->uses_gpe0)goto init;res_pm = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPE0);if (!res_pm) {dev_warn(dev, "ACPI BAR is unavailable, GPI 0 - 15 unavailable\n");goto init;}if (!devm_request_region(dev, res_pm->start, resource_size(res_pm),pdev->name)) {dev_warn(dev, "ACPI BAR is busy, GPI 0 - 15 unavailable\n");goto init;}ichx_priv.pm_base = res_pm;init:ichx_gpiolib_setup(&ichx_priv.chip);err = gpiochip_add_data(&ichx_priv.chip, NULL);if (err) {dev_err(dev, "Failed to register GPIOs\n");return err;}dev_info(dev, "GPIO from %d to %d\n", ichx_priv.chip.base,ichx_priv.chip.base + ichx_priv.chip.ngpio - 1);return 0;
}static int ichx_gpio_remove(struct platform_device *pdev)
{gpiochip_remove(&ichx_priv.chip);return 0;
}static struct platform_driver ichx_gpio_driver = {.driver		= {.name	= DRV_NAME,},.probe		= ichx_gpio_probe,.remove		= ichx_gpio_remove,
};module_platform_driver(ichx_gpio_driver);MODULE_AUTHOR("Peter Tyser ");
MODULE_DESCRIPTION("GPIO interface for Intel ICH series");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:"DRV_NAME);

fpga_i2c_adapter.c

//switchboard.c,i2coccore.c(驱动) 的设备在这定义

cpu_addr.c

#include 
#include 
#include 
#include 
#include 
#include #define CPU_DRIVER_NAME 	"sys_cpu"
#define CPU_DRIVER_VER		"0.0.1"
/*** cpu register address for read and write.    读msr寄存器,msr:cpu临终状态*/
#define CPU_STATUS_IFU      0x401
#define CPU_STATUS_DCU      0x405
#define CPU_STATUS_DLTB     0x409
#define CPU_STATUS_MLC      0x40d
#define CPU_STATUS_PCU      0x411
#define CPU_STATUS_HA       0x41D
#define CPU_STATUS_IMC0     0x425
#define CPU_STATUS_IMC1     0x429
#define CPU_STATUS_CBO0     0x445
#define CPU_STATUS_CBO1     0x449
#define CPU_STATUS_CBO2     0x44d// obmc-server:/dev/cpu$ ls
// 0  10  12  14  16  18  2   21  23  25  27  29  30  32  34  36  38  4  6  8  microcode
// 1  11  13  15  17  19  20  22  24  26  28  3   31  33  35  37  39  5  7  9static struct kobject * g_kobj = NULL;struct cpu_hq_data {struct mutex       cpu_lock;uint32_t           read_addr;uint32_t           cpu_num;
};static ssize_t get_cpu_cbo2_status(struct device *dev, struct device_attribute *attr, char *buf)
{uint32_t len = 0;uint32_t data[2];int32_t err = 0;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);mutex_lock(&cpu_data->cpu_lock);err = rdmsr_safe_on_cpu(cpu_data->cpu_num, CPU_STATUS_CBO2, &data[0], &data[1]);   //读mutex_unlock(&cpu_data->cpu_lock);if (err < 0)return err;len = snprintf(buf, PAGE_SIZE, "0x%8.8x%8.8x\n", data[1],data[0]);return len;
}static ssize_t set_cpu_cbo2(struct device *dev, struct device_attribute *devattr,const char *buf, size_t count)
{uint32_t cpu;size_t value;ssize_t ret = 0;int32_t len = count;int8_t clone[count];int8_t *pclone = clone;int8_t *tok;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);if (buf[count - 1] == '\0' || buf[count - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}cpu = (uint32_t)value;mutex_lock(&cpu_data->cpu_lock);cpu_data->cpu_num = cpu;mutex_unlock(&cpu_data->cpu_lock);return count;
}
static DEVICE_ATTR(cpu_status_cbo2, 0600, get_cpu_cbo2_status, set_cpu_cbo2);static ssize_t get_cpu_cbo1_status(struct device *dev, struct device_attribute *attr, char *buf)
{uint32_t len = 0;uint32_t data[2];int32_t err = 0;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);mutex_lock(&cpu_data->cpu_lock);err = rdmsr_safe_on_cpu(cpu_data->cpu_num, CPU_STATUS_CBO1, &data[0], &data[1]);mutex_unlock(&cpu_data->cpu_lock);if (err < 0)return err;len = snprintf(buf, PAGE_SIZE, "0x%8.8x%8.8x\n", data[1],data[0]);return len;
}static ssize_t set_cpu_cbo1(struct device *dev, struct device_attribute *devattr,const char *buf, size_t count)
{uint32_t cpu;size_t value;ssize_t ret = 0;int32_t len = count;int8_t clone[count];int8_t *pclone = clone;int8_t *tok;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);if (buf[count - 1] == '\0' || buf[count - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}cpu = (uint32_t)value;mutex_lock(&cpu_data->cpu_lock);cpu_data->cpu_num = cpu;mutex_unlock(&cpu_data->cpu_lock);return count;
}
static DEVICE_ATTR(cpu_status_cbo1, 0600, get_cpu_cbo1_status, set_cpu_cbo1);static ssize_t get_cpu_cbo0_status(struct device *dev, struct device_attribute *attr, char *buf)
{uint32_t len = 0;uint32_t data[2];int32_t err = 0;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);mutex_lock(&cpu_data->cpu_lock);err = rdmsr_safe_on_cpu(cpu_data->cpu_num, CPU_STATUS_CBO0, &data[0], &data[1]);mutex_unlock(&cpu_data->cpu_lock);if (err < 0)return err;len = snprintf(buf, PAGE_SIZE, "0x%8.8x%8.8x\n", data[1],data[0]);return len;
}static ssize_t set_cpu_cbo0(struct device *dev, struct device_attribute *devattr,const char *buf, size_t count)
{uint32_t cpu;size_t value;ssize_t ret = 0;int32_t len = count;int8_t clone[count];int8_t *pclone = clone;int8_t *tok;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);if (buf[count - 1] == '\0' || buf[count - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " "); // strsep去掉空格if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}cpu = (uint32_t)value;mutex_lock(&cpu_data->cpu_lock);cpu_data->cpu_num = cpu;mutex_unlock(&cpu_data->cpu_lock);return count;
}
static DEVICE_ATTR(cpu_status_cbo0, 0600, get_cpu_cbo0_status, set_cpu_cbo0);static ssize_t get_cpu_imc1_status(struct device *dev, struct device_attribute *attr, char *buf)
{uint32_t len = 0;uint32_t data[2];int32_t err = 0;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);mutex_lock(&cpu_data->cpu_lock);err = rdmsr_safe_on_cpu(cpu_data->cpu_num, CPU_STATUS_IMC1, &data[0], &data[1]);mutex_unlock(&cpu_data->cpu_lock);if (err < 0)return err;len = snprintf(buf, PAGE_SIZE, "0x%8.8x%8.8x\n", data[1],data[0]);return len;
}static ssize_t set_cpu_imc1(struct device *dev, struct device_attribute *devattr,const char *buf, size_t count)
{uint32_t cpu;size_t value;ssize_t ret = 0;int32_t len = count;int8_t clone[count];int8_t *pclone = clone;int8_t *tok;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);if (buf[count - 1] == '\0' || buf[count - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}cpu = (uint32_t)value;mutex_lock(&cpu_data->cpu_lock);cpu_data->cpu_num = cpu;mutex_unlock(&cpu_data->cpu_lock);return count;
}
static DEVICE_ATTR(cpu_status_imc1, 0600, get_cpu_imc1_status, set_cpu_imc1);static ssize_t get_cpu_imc0_status(struct device *dev, struct device_attribute *attr, char *buf)
{uint32_t len = 0;uint32_t data[2];int32_t err = 0;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);mutex_lock(&cpu_data->cpu_lock);err = rdmsr_safe_on_cpu(cpu_data->cpu_num, CPU_STATUS_IMC0, &data[0], &data[1]);mutex_unlock(&cpu_data->cpu_lock);if (err < 0)return err;len = snprintf(buf, PAGE_SIZE, "0x%8.8x%8.8x\n", data[1],data[0]);return len;
}static ssize_t set_cpu_imc0(struct device *dev, struct device_attribute *devattr,const char *buf, size_t count)
{uint32_t cpu;size_t value;ssize_t ret = 0;int32_t len = count;int8_t clone[count];int8_t *pclone = clone;int8_t *tok;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);if (buf[count - 1] == '\0' || buf[count - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}cpu = (uint32_t)value;mutex_lock(&cpu_data->cpu_lock);cpu_data->cpu_num = cpu;mutex_unlock(&cpu_data->cpu_lock);return count;
}
static DEVICE_ATTR(cpu_status_imc0, 0600, get_cpu_imc0_status, set_cpu_imc0);static ssize_t get_cpu_ha_status(struct device *dev, struct device_attribute *attr, char *buf)
{uint32_t len = 0;uint32_t data[2];int32_t err = 0;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);mutex_lock(&cpu_data->cpu_lock);err = rdmsr_safe_on_cpu(cpu_data->cpu_num, CPU_STATUS_HA, &data[0], &data[1]);mutex_unlock(&cpu_data->cpu_lock);if (err < 0)return err;len = snprintf(buf, PAGE_SIZE, "0x%8.8x%8.8x\n", data[1],data[0]);return len;
}static ssize_t set_cpu_ha(struct device *dev, struct device_attribute *devattr,const char *buf, size_t count)
{uint32_t cpu;size_t value;ssize_t ret = 0;int32_t len = count;int8_t clone[count];int8_t *pclone = clone;int8_t *tok;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);if (buf[count - 1] == '\0' || buf[count - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}cpu = (uint32_t)value;mutex_lock(&cpu_data->cpu_lock);cpu_data->cpu_num = cpu;mutex_unlock(&cpu_data->cpu_lock);return count;
}
static DEVICE_ATTR(cpu_status_ha, 0600, get_cpu_ha_status, set_cpu_ha);static ssize_t get_cpu_pcu_status(struct device *dev, struct device_attribute *attr, char *buf)
{uint32_t len = 0;uint32_t data[2];int32_t err = 0;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);mutex_lock(&cpu_data->cpu_lock);err = rdmsr_safe_on_cpu(cpu_data->cpu_num, CPU_STATUS_PCU, &data[0], &data[1]);mutex_unlock(&cpu_data->cpu_lock);if (err < 0)return err;len = snprintf(buf, PAGE_SIZE, "0x%8.8x%8.8x\n", data[1],data[0]);return len;
}static ssize_t set_cpu_pcu(struct device *dev, struct device_attribute *devattr,const char *buf, size_t count)
{uint32_t cpu;size_t value;ssize_t ret = 0;int32_t len = count;int8_t clone[count];int8_t *pclone = clone;int8_t *tok;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);if (buf[count - 1] == '\0' || buf[count - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}cpu = (uint32_t)value;mutex_lock(&cpu_data->cpu_lock);cpu_data->cpu_num = cpu;mutex_unlock(&cpu_data->cpu_lock);return count;
}
static DEVICE_ATTR(cpu_status_pcu, 0600, get_cpu_pcu_status, set_cpu_pcu);static ssize_t get_cpu_mlc_status(struct device *dev, struct device_attribute *attr, char *buf)
{uint32_t len = 0;uint32_t data[2];int32_t err = 0;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);mutex_lock(&cpu_data->cpu_lock);err = rdmsr_safe_on_cpu(cpu_data->cpu_num, CPU_STATUS_MLC, &data[0], &data[1]);mutex_unlock(&cpu_data->cpu_lock);if (err < 0)return err;len = snprintf(buf, PAGE_SIZE, "0x%8.8x%8.8x\n", data[1],data[0]);return len;
}static ssize_t set_cpu_mlc(struct device *dev, struct device_attribute *devattr,const char *buf, size_t count)
{uint32_t cpu;size_t value;ssize_t ret = 0;int32_t len = count;int8_t clone[count];int8_t *pclone = clone;int8_t *tok;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);if (buf[count - 1] == '\0' || buf[count - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}cpu = (uint32_t)value;mutex_lock(&cpu_data->cpu_lock);cpu_data->cpu_num = cpu;mutex_unlock(&cpu_data->cpu_lock);return count;
}
static DEVICE_ATTR(cpu_status_mlc, 0600, get_cpu_mlc_status, set_cpu_mlc);static ssize_t get_cpu_dltb_status(struct device *dev, struct device_attribute *attr, char *buf)
{uint32_t len = 0;uint32_t data[2];int32_t err = 0;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);mutex_lock(&cpu_data->cpu_lock);err = rdmsr_safe_on_cpu(cpu_data->cpu_num, CPU_STATUS_DLTB, &data[0], &data[1]);mutex_unlock(&cpu_data->cpu_lock);if (err < 0)return err;len = snprintf(buf, PAGE_SIZE, "0x%8.8x%8.8x\n", data[1],data[0]);return len;
}static ssize_t set_cpu_dltb(struct device *dev, struct device_attribute *devattr,const char *buf, size_t count)
{uint32_t cpu;size_t value;ssize_t ret = 0;int32_t len = count;int8_t clone[count];int8_t *pclone = clone;int8_t *tok;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);if (buf[count - 1] == '\0' || buf[count - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}cpu = (uint32_t)value;mutex_lock(&cpu_data->cpu_lock);cpu_data->cpu_num = cpu;mutex_unlock(&cpu_data->cpu_lock);return count;
}
static DEVICE_ATTR(cpu_status_dltb, 0600, get_cpu_dltb_status, set_cpu_dltb);static ssize_t get_cpu_dcu_status(struct device *dev, struct device_attribute *attr, char *buf)
{uint32_t len = 0;uint32_t data[2];int32_t err = 0;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);mutex_lock(&cpu_data->cpu_lock);err = rdmsr_safe_on_cpu(cpu_data->cpu_num, CPU_STATUS_DCU, &data[0], &data[1]);mutex_unlock(&cpu_data->cpu_lock);if (err < 0)return err;len = snprintf(buf, PAGE_SIZE, "0x%8.8x%8.8x\n", data[1],data[0]);return len;
}static ssize_t set_cpu_dcu(struct device *dev, struct device_attribute *devattr,const char *buf, size_t count)
{uint32_t cpu;size_t value;ssize_t ret = 0;int32_t len = count;int8_t clone[count];int8_t *pclone = clone;int8_t *tok;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);if (buf[count - 1] == '\0' || buf[count - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}cpu = (uint32_t)value;mutex_lock(&cpu_data->cpu_lock);cpu_data->cpu_num = cpu;mutex_unlock(&cpu_data->cpu_lock);return count;
}
static DEVICE_ATTR(cpu_status_dcu, 0600, get_cpu_dcu_status, set_cpu_dcu);static ssize_t get_cpu_ifu_status(struct device *dev, struct device_attribute *attr, char *buf)
{uint32_t len = 0;uint32_t data[2];int32_t err = 0;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);mutex_lock(&cpu_data->cpu_lock);err = rdmsr_safe_on_cpu(cpu_data->cpu_num, CPU_STATUS_IFU, &data[0], &data[1]);mutex_unlock(&cpu_data->cpu_lock);if (err < 0)return err;len = snprintf(buf, PAGE_SIZE, "0x%8.8x%8.8x\n", data[1],data[0]);return len;
}static ssize_t set_cpu_ifu(struct device *dev, struct device_attribute *devattr,const char *buf, size_t count)
{uint32_t cpu;size_t value;ssize_t ret = 0;int32_t len = count;int8_t clone[count];int8_t *pclone = clone;int8_t *tok;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);if (buf[count - 1] == '\0' || buf[count - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}cpu = (uint32_t)value;mutex_lock(&cpu_data->cpu_lock);cpu_data->cpu_num = cpu;mutex_unlock(&cpu_data->cpu_lock);return count;
}
static DEVICE_ATTR(cpu_status_ifu, 0600, get_cpu_ifu_status, set_cpu_ifu);static ssize_t get_cpu_reg_address(struct device *dev, struct device_attribute *attr, char *buf)
{uint32_t len = 0;uint32_t data[2];int32_t err = 0;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);mutex_lock(&cpu_data->cpu_lock);err = rdmsr_safe_on_cpu(cpu_data->cpu_num, cpu_data->read_addr, &data[0], &data[1]);mutex_unlock(&cpu_data->cpu_lock);if (err < 0)return err;len = snprintf(buf, PAGE_SIZE, "0x%8.8x%8.8x\n", data[1],data[0]);return len;
}static ssize_t set_cpu_reg_address(struct device *dev, struct device_attribute *devattr,const char *buf, size_t count)
{uint32_t addr;uint32_t cpu;size_t value;ssize_t ret = 0;int32_t len = count;int8_t clone[count];int8_t *pclone = clone;int8_t *tok;struct cpu_hq_data *cpu_data = dev_get_drvdata(dev);if (buf[count - 1] == '\0' || buf[count - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}cpu = (uint32_t)value;tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}ret = kstrtoul(tok, 16, &value);if (ret < 0) {return -EINVAL;}addr = (uint32_t)value;mutex_lock(&cpu_data->cpu_lock);cpu_data->read_addr = addr;cpu_data->cpu_num = cpu;mutex_unlock(&cpu_data->cpu_lock);return count;
}
static DEVICE_ATTR( getreg, 0600, get_cpu_reg_address, set_cpu_reg_address);static struct attribute *cpu_hq_attrs[] = {&dev_attr_getreg.attr,&dev_attr_cpu_status_ifu.attr,&dev_attr_cpu_status_dcu.attr,&dev_attr_cpu_status_dltb.attr,&dev_attr_cpu_status_mlc.attr,&dev_attr_cpu_status_pcu.attr,&dev_attr_cpu_status_ha.attr,&dev_attr_cpu_status_imc0.attr,&dev_attr_cpu_status_imc1.attr,&dev_attr_cpu_status_cbo0.attr,&dev_attr_cpu_status_cbo1.attr,&dev_attr_cpu_status_cbo2.attr,NULL,
};static struct attribute_group cpu_hq_attrs_group = {.attrs = cpu_hq_attrs,
};static void cpu_hq_dev_release( struct device * dev)
{return;
}static struct platform_device cpu_hq_dev = {.name           = CPU_DRIVER_NAME,.id             = -1,.dev = {.release = cpu_hq_dev_release,}
};static int32_t cpu_hq_drv_remove(struct platform_device *pdev)
{if(cpu_hq_attrs_group.attrs)sysfs_remove_group(&pdev->dev.kobj, &cpu_hq_attrs_group);if(g_kobj) {kobject_del(g_kobj);kobject_put(g_kobj);sysfs_remove_link(g_kobj, "status");}return 0;
}static int32_t cpu_hq_drv_probe(struct platform_device *pdev)
{int32_t err = 0;struct cpu_hq_data *cpu_data;cpu_data = devm_kzalloc(&pdev->dev, sizeof(struct cpu_hq_data), GFP_KERNEL);if(!cpu_data)return -ENOMEM;dev_set_drvdata(&pdev->dev, cpu_data);mutex_init(&cpu_data->cpu_lock);err = sysfs_create_group(&pdev->dev.kobj, &cpu_hq_attrs_group);if(err) {printk(KERN_ERR "Cannot create sysfs for system cpu\n");return err;}g_kobj = kobject_create_and_add("ott_cpu",NULL);if(!g_kobj) {err = -EAGAIN;pr_err("create ott_cpu kobject failed.\n");goto err_remove_cpu_link;}err = sysfs_create_link(g_kobj,&pdev->dev.kobj,"status");if(err) {pr_err("create ott_cpu sysfs link failed.\n");goto err_remove_cpu_sys;}return 0;err_remove_cpu_sys:kobject_del(g_kobj);kobject_put(g_kobj);err_remove_cpu_link:sysfs_remove_group(&pdev->dev.kobj, &cpu_hq_attrs_group);return err;}static struct platform_driver cpu_hq_drv = {.probe = cpu_hq_drv_probe,.remove = __exit_p(cpu_hq_drv_remove),.driver = {.name = CPU_DRIVER_NAME,},
};static int32_t __init cpu_hq_init(void)
{/*Register Platform device and Platform Driver*/platform_device_register(&cpu_hq_dev);platform_driver_register(&cpu_hq_drv);printk(KERN_INFO "%s: version %s loaded successfully\n", CPU_DRIVER_NAME, CPU_DRIVER_VER);return 0;
}static void __exit cpu_hq_exit(void)
{/*Unregister Platform device and Platform Driver*/platform_driver_unregister(&cpu_hq_drv);platform_device_unregister(&cpu_hq_dev);printk(KERN_INFO "%s: unloaded successfully\n", CPU_DRIVER_NAME);
}module_init(cpu_hq_init);
module_exit(cpu_hq_exit);MODULE_AUTHOR("Huaqin Technology Co.,Ltd.");
MODULE_DESCRIPTION("Hua Qin Common cpu");
MODULE_VERSION(CPU_DRIVER_VER);
MODULE_LICENSE("GPL");

cpld_lpc.c

//lpc方式连的设备:baseboard_cpld & come_cpld,inb  outb
#include 
#include 
#include 
#include 
#include #define CPLD_DRIVER_NAME    "lpc_cpld_drv"
#define CPLD_DRIVER_VER     "0.2.0"
#define CPLD_BASEBOARD_NAME "baseboard_cpld"
#define CPLD_COME_NAME      "come_cpld"
/*** CPLD register address for read and write.*/
/** COMe CPLD:0xA1E0 ~ 0xA1FF* */
#define VERSION_ADDR        0xA1E0#define COME_CPLD_ADDR      0xA1E0
#define COME_PCB_VER_ADDR   0xA1E0
#define COME_H_VER_ADDR     0xA1E1
#define COME_M_VER_ADDR     0xA1E2
#define COME_L_VER_ADDR     0xA1E3
#define COME_SCRATCH_ADDR   0xA1E4
#define COME_CPLD_END_ADDR  0xA1FF#define CPLD_REGISTER_SIZE  0x1Fstruct cpld_lpc_data {struct mutex cpld_lock;uint16_t read_addr;uint16_t base_addr;
};
static struct kobject * g_kobj = NULL;static ssize_t get_come_cpld_version(struct device *dev, struct device_attribute *attr, char *buf)
{int32_t len = 0;len = snprintf(buf, PAGE_SIZE, "%x.%x.%x\n", inb(COME_H_VER_ADDR), inb(COME_M_VER_ADDR), inb(COME_L_VER_ADDR));return len;
}
static DEVICE_ATTR(come_cpld_v, 0400, get_come_cpld_version, NULL);static ssize_t get_cpld_scratch_value(struct device *dev, struct device_attribute *attr, char *buf)
{int32_t len = 0;struct cpld_lpc_data *cpld_data = dev_get_drvdata(dev);if (cpld_data == NULL)return -ENODEV;len = snprintf(buf, PAGE_SIZE, "0x%2.2x\n", inb(COME_SCRATCH_ADDR));return len;
}static ssize_t set_cpld_scratch_value(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count)
{size_t value_get = 0;uint16_t value = 0;ssize_t status = 0;struct cpld_lpc_data *cpld_data = dev_get_drvdata(dev);if (cpld_data == NULL)return -ENODEV;status = kstrtoul(buf, 16, &value_get);if (status < 0)return status;value = (uint16_t)value_get;outb(value, COME_SCRATCH_ADDR);status = (ssize_t)count;return status;
}
static DEVICE_ATTR(scratch, 0600, get_cpld_scratch_value, set_cpld_scratch_value);static ssize_t get_cpld_reg_address(struct device *dev, struct device_attribute *attr, char *buf)
{int32_t len = 0;struct cpld_lpc_data *cpld_data = dev_get_drvdata(dev);if (cpld_data == NULL)return -ENODEV;len = snprintf(buf, PAGE_SIZE, "0x%2.2x\n", inb((cpld_data->read_addr)));return len;
}/*** Store the register address* @param  buf     address wanted to be read value of* @return         number of bytes stored, or an error code*/
static ssize_t set_cpld_reg_address(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count)
{size_t addr_get = 0;uint16_t addr = 0;ssize_t status = 0;struct cpld_lpc_data *cpld_data = dev_get_drvdata(dev);if (cpld_data == NULL)return -ENODEV;status = kstrtoul(buf, 16, &addr_get);if (status < 0)return status;addr = (uint16_t)addr_get;cpld_data->read_addr = cpld_data->base_addr + addr;status = (ssize_t)count;return status;
}static DEVICE_ATTR(getreg, 0600, get_cpld_reg_address, set_cpld_reg_address);static ssize_t setreg_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count)
{// CPLD register is one bytesize_t addr_get = 0;size_t value_get = 0;uint16_t addr;uint8_t value;int8_t *tok;int8_t clone[count];int8_t *pclone = clone;ssize_t status;int32_t len = count;struct cpld_lpc_data *cpld_data = dev_get_drvdata(dev);if (cpld_data == NULL)return -ENODEV;if (buf[count - 1] == '\0' || buf[count - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}status = kstrtoul(tok, 16, &addr_get);if (status < 0)return status;addr = (uint16_t)addr_get;tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}status = kstrtoul(tok, 16, &value_get);if (status < 0)return status;value = (uint8_t)value_get;outb(value, cpld_data->base_addr + addr);status = (ssize_t)count;return status;
}
static DEVICE_ATTR(setreg, 0200, NULL, setreg_store);/*** Read all CPLD register in binary mode.* @return number of byte read.*/
static ssize_t
dump_read(struct file *filp, struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count)
{size_t i = 0;ssize_t status;struct device *dev = kobj_to_dev(kobj);struct cpld_lpc_data *cpld_data = dev_get_drvdata(dev);if (cpld_data == NULL)return -ENODEV;if (off + count > CPLD_REGISTER_SIZE)return -EINVAL;mutex_lock(&cpld_data->cpld_lock);while (i < count) {buf[i++] = inb(VERSION_ADDR + off);off++;msleep(1);}status = count;mutex_unlock(&cpld_data->cpld_lock);return status;
}static BIN_ATTR_RO(dump, CPLD_REGISTER_SIZE);static struct attribute *cpld_lpc_attrs[] = {&dev_attr_getreg.attr,&dev_attr_setreg.attr,&dev_attr_come_cpld_v.attr,&dev_attr_scratch.attr,NULL,
};static struct bin_attribute *cpld_lpc_bin_attrs[] = {&bin_attr_dump,NULL,
};static struct attribute_group cpld_lpc_attrs_group = {.attrs = cpld_lpc_attrs,.bin_attrs = cpld_lpc_bin_attrs,
};static struct platform_device *cpld_come_dev;static int32_t cpld_lpc_dev_remove(struct platform_device *pdev)
{pr_info("%s: unregistered successfully\n", pdev->name);sysfs_remove_group(&pdev->dev.kobj, &cpld_lpc_attrs_group);if(g_kobj) {kobject_del(g_kobj);kobject_put(g_kobj);sysfs_remove_link(g_kobj, "lpc_cpld");}return 0;
}static int32_t cpld_lpc_dev_probe(struct platform_device *pdev)
{struct resource *resource;int32_t err = 0;struct cpld_lpc_data *cpld_data;cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct cpld_lpc_data), GFP_KERNEL);if (!cpld_data)return -ENOMEM;dev_set_drvdata(&pdev->dev, cpld_data);mutex_init(&cpld_data->cpld_lock);resource = platform_get_resource(pdev, IORESOURCE_IO, 0);if (unlikely(!resource)) {pr_err("Specified Resource Not Available...\n");return -ENODEV;}cpld_data->read_addr = resource->start;cpld_data->base_addr = resource->start;err = sysfs_create_group(&pdev->dev.kobj, &cpld_lpc_attrs_group);if (err) {pr_err("Cannot create sysfs for system CPLD\n");return err;}g_kobj = kobject_create_and_add("ott_lpc_cpld",NULL);if(!g_kobj) {err = -EAGAIN;pr_err("create ott_lpc_cpld kobject failed.\n");goto err_remove_cpld_link;}err = sysfs_create_link(g_kobj,&pdev->dev.kobj,"lpc_cpld");if(err) {pr_err("create ott_lpc_cpld sysfs link failed.\n");goto err_remove_cpld_sys;}pr_info("CPLD Probe driver");pr_info("COMe CPLD Address:0x%2.2x\n", cpld_data->base_addr);return 0;err_remove_cpld_sys:kobject_del(g_kobj);kobject_put(g_kobj);err_remove_cpld_link:sysfs_remove_group(&pdev->dev.kobj, &cpld_lpc_attrs_group);return err;
}static const struct platform_device_id cpld_lpc_hq_ids[] = {  //**********************设备,不是i2c设备,不用通过fpga_i2c_adapter match{.name = CPLD_BASEBOARD_NAME,},{.name = CPLD_COME_NAME,},{/* sentinel */}};
MODULE_DEVICE_TABLE(platform, cpld_lpc_hq_ids);static struct platform_driver cpld_lpc_drv = {.probe = cpld_lpc_dev_probe,.remove = cpld_lpc_dev_remove,.driver = {.name = CPLD_DRIVER_NAME,},.id_table = cpld_lpc_hq_ids,
};static int32_t __init cpld_hq_init(void)
{int32_t retval = 0;struct resource cpld_come_resources = {.start = COME_CPLD_ADDR,.end = COME_CPLD_END_ADDR,.flags = IORESOURCE_IO,};/*Register Platform device and Platform Driver*/platform_driver_register(&cpld_lpc_drv);cpld_come_dev = platform_device_alloc(CPLD_COME_NAME, -1);if (!cpld_come_dev)return -ENOMEM;cpld_come_dev->id = -1;retval = platform_device_add_resources(cpld_come_dev, &cpld_come_resources, 1);if (retval) {pr_err("Device resource addition failed (%d)\n", retval);goto exit_device_put;}retval = platform_device_add(cpld_come_dev);if (retval < 0) {platform_device_put(cpld_come_dev);cpld_come_dev = NULL;return retval;}pr_info("%s: version %s loaded successfully\n", cpld_come_dev->name, CPLD_DRIVER_VER);return 0;exit_device_put:platform_device_put(cpld_come_dev);cpld_come_dev = NULL;return retval;
}static void __exit cpld_hq_exit(void)
{/*Unregister Platform device and Platform Driver*/platform_device_unregister(cpld_come_dev);platform_driver_unregister(&cpld_lpc_drv);pr_info("%s: unloaded successfully\n", CPLD_DRIVER_NAME);
}module_init(cpld_hq_init);
module_exit(cpld_hq_exit);MODULE_AUTHOR("Simon Sun & Carl Wang");
MODULE_DESCRIPTION("Hua Qin Common LPC CPLD");
MODULE_VERSION(CPLD_DRIVER_VER);
MODULE_LICENSE("GPL");

cpld_i2c.c

//i2c连的设备:cpld_lc
#include 
#include 
#include #define CPLD_DRIVER_NAME     "cpld_i2c"
#define CPLD_DRIVER_VER      "0.1.0"/* lc cpld register address for read and write.*//* lc_cpld_version */
#define HIGH_VERSION         0x01
#define MIDDLE_VERSION       0x02
#define LOW_VERSION          0x03/* watch dog start : 读写cpu寄存器,gpio(高低电平)有几个寄存器控制它选择什么样功能,【普通功能】设置输入输出(设置寄存器),【特殊功能】(i2c,spi,时序(内核和硬件做好了)控制输入输出)不用设置输入输出*/
#define GPIOBASE_ADDR        0x500
#define WDT_FEED             15     // gpio15 pin脚 喂狗
#define G_PIN_SEL_ADDRESS    (GPIOBASE_ADDR + 0x0)   // 设置功能选择
#define G_PIN_IN_OUT_ADDRESS (GPIOBASE_ADDR + 0x04)  // 设置输入
#define G_WDT_OUT_ADDRESS    (GPIOBASE_ADDR + 0x0C)  // 设置输出
#define G_WDT_FEED           (1 << WDT_FEED)   // 1000 0000 0000 0000 , 用来取第15位
#define G_VALUE_ONE          0x1
#define G_VALUE_ZERO         0x0
#define CPLD_SCRATCH         0x04
#define WDT_MASK             0xd1   // 屏蔽,写入不起作用
#define CLK_STATE            0x0Fstruct cpld_hq_data {struct mutex cpld_lock;struct mutex wdt_lock;uint8_t read_addr;uint8_t base_addr;
};
static struct kobject * g_kobj = NULL;static void write_wdt_port(uint32_t pin_addr, uint32_t a_ucpins, uint32_t a_ucvalue)
{uint32_t p_reg_val;p_reg_val = inl_p(pin_addr);   // inl_p 读寄存器,  pin_addr: 0x.., pio可以inl_p 。 comecpld连在cpu上用inb, outb读if (a_ucvalue) { //1p_reg_val = (a_ucpins | p_reg_val);  // 或:有1为1, 第15位被置1} else { //0p_reg_val = (~a_ucpins & p_reg_val); // 与:有0为0,第15位被置0}outl_p(p_reg_val, pin_addr); //写
}static uint32_t read_wdt_port(uint32_t pin_addr, uint32_t a_ucpins)
{uint32_t ret = 0;if (inl_p(pin_addr) & a_ucpins) {   // pin_addr第15位为1ret = 0x01;} else {ret = 0x00;}return ret;
}static ssize_t wdt_feed_show(struct device *dev, struct device_attribute *attr, char *buf)
{uint32_t value;struct i2c_client *client = to_i2c_client(dev);struct cpld_hq_data *cpld_data = i2c_get_clientdata(client);if (cpld_data == NULL)return -ENODEV;value = read_wdt_port(G_WDT_OUT_ADDRESS, G_WDT_FEED);return snprintf(buf, PAGE_SIZE, "0x%.2x\n", value);
}static ssize_t wdt_feed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{uint32_t value;ssize_t status = 0;struct i2c_client *client = to_i2c_client(dev);struct cpld_hq_data *cpld_data = i2c_get_clientdata(client);if (cpld_data == NULL)return -ENODEV;mutex_lock(&cpld_data->wdt_lock);  //读写一对,中间不会被打断value = read_wdt_port(G_WDT_OUT_ADDRESS, G_WDT_FEED);value = (~value) & G_VALUE_ONE;write_wdt_port(G_WDT_OUT_ADDRESS, G_WDT_FEED, value);mutex_unlock(&cpld_data->wdt_lock);status = (ssize_t)size;return status;
}
struct device_attribute dev_attr_watchdog_feed = __ATTR(wdt_feed, 0600, wdt_feed_show, wdt_feed_store);static ssize_t cpld_i2c_wdt_mask_show(struct device *dev, struct device_attribute *attr, char *buf)
{int32_t data;struct i2c_client *client = to_i2c_client(dev);struct cpld_hq_data *cpld_data = i2c_get_clientdata(client);if (cpld_data == NULL)return -ENODEV;data = i2c_smbus_read_byte_data(client, WDT_MASK);if (data < 0)return data;return snprintf(buf, PAGE_SIZE, "0x%2.2x\n", data);
}static ssize_t cpld_i2c_wdt_mask_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{uint8_t value;size_t value_get = 0;ssize_t status;struct i2c_client *client = to_i2c_client(dev);struct cpld_hq_data *cpld_data = i2c_get_clientdata(client);if (cpld_data == NULL)return -ENODEV;status = kstrtoul(buf, 16, &value_get);if (status < 0)return status;value = (uint8_t)value_get;status = i2c_smbus_write_byte_data(client, WDT_MASK, value);if (status < 0)return status;status = (ssize_t)size;return status;
}
struct device_attribute dev_attr_cpld_i2c_wdt_mask = __ATTR(wdt_mask, 0600, cpld_i2c_wdt_mask_show, cpld_i2c_wdt_mask_store);  //ff,喂狗关闭,0打开/****************************************************************************watch dog end *************************************************************/static ssize_t get_lc_cpld_board_version_show(struct device *dev, struct device_attribute *attr, char *buf)
{int32_t data1;int32_t data2;int32_t data3;int32_t value = -EINVAL;struct i2c_client *client = to_i2c_client(dev);struct cpld_hq_data *cpld_data = i2c_get_clientdata(client);if (cpld_data == NULL)return -ENODEV;data1 = i2c_smbus_read_byte_data(client, HIGH_VERSION);data2 = i2c_smbus_read_byte_data(client, MIDDLE_VERSION);data3 = i2c_smbus_read_byte_data(client, LOW_VERSION);if (data1 < 0 || data2 < 0 || data3 < 0)return -EINVAL;value = snprintf(buf, PAGE_SIZE, "%x.%x.%x\n", data1, data2, data3);return value;
}
struct device_attribute dev_attr_get_lc_cpld_board_version = __ATTR(getv_lc_cpld, 0400, get_lc_cpld_board_version_show, NULL);static ssize_t get_lc_cpld_external_100clk_show(struct device *dev, struct device_attribute *attr, char *buf)
{int32_t data;int32_t value = -EINVAL;struct i2c_client *client = to_i2c_client(dev);struct cpld_hq_data *cpld_data = i2c_get_clientdata(client);if (cpld_data == NULL)return -ENODEV;data = i2c_smbus_read_byte_data(client, CLK_STATE);if (data < 0)return -EINVAL;data = (data >> G_VALUE_ONE) & G_VALUE_ONE;value = snprintf(buf, PAGE_SIZE, "%x\n", data);return value;
}
struct device_attribute dev_attr_get_clk_100_stat = __ATTR(get_clk_100_stat, 0400, get_lc_cpld_external_100clk_show, NULL);static ssize_t get_lc_cpld_external_156clk_show(struct device *dev, struct device_attribute *attr, char *buf)
{int32_t data;int32_t value = -EINVAL;struct i2c_client *client = to_i2c_client(dev);struct cpld_hq_data *cpld_data = i2c_get_clientdata(client);if (cpld_data == NULL)return -ENODEV;data = i2c_smbus_read_byte_data(client, CLK_STATE);if (data < 0)return -EINVAL;data = data & G_VALUE_ONE;value = snprintf(buf, PAGE_SIZE, "%x\n", data);return value;
}
struct device_attribute dev_attr_get_clk_156_stat = __ATTR(get_clk_156_stat, 0400, get_lc_cpld_external_156clk_show, NULL);  //检测时钟好不好,不好1,好0static ssize_t cpld_i2c_getreg_show(struct device *dev, struct device_attribute *attr, char *buf)
{int32_t data;struct i2c_client *client = to_i2c_client(dev);struct cpld_hq_data *cpld_data = i2c_get_clientdata(client);if (cpld_data == NULL)return -ENODEV;data = i2c_smbus_read_byte_data(client, cpld_data->read_addr);if (data < 0)return data;return snprintf(buf, PAGE_SIZE, "0x%2.2x\n", data);
}static ssize_t cpld_i2c_getreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{uint8_t addr;ssize_t status = 0;size_t addr_get = 0;struct i2c_client *client = to_i2c_client(dev);struct cpld_hq_data *cpld_data = i2c_get_clientdata(client);if (cpld_data == NULL)return -ENODEV;status = kstrtoul(buf, 16, &addr_get);if (status < 0)return status;addr = (uint8_t)addr_get;cpld_data->read_addr = addr;status = (ssize_t)size;return status;
}struct device_attribute dev_attr_cpld_i2c_getreg = __ATTR(getreg, 0600, cpld_i2c_getreg_show, cpld_i2c_getreg_store);static ssize_t cpld_i2c_scratch_show(struct device *dev, struct device_attribute *attr, char *buf)
{// CPLD register is one byteint32_t value;struct i2c_client *client = to_i2c_client(dev);struct cpld_hq_data *cpld_data = i2c_get_clientdata(client);if (cpld_data == NULL)return -ENODEV;value = i2c_smbus_read_byte_data(client, CPLD_SCRATCH);if (value < 0)return value;return snprintf(buf, PAGE_SIZE, "0x%.2x\n", value);
}static ssize_t cpld_i2c_scratch_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{// CPLD register is one byteuint8_t value;ssize_t status;struct i2c_client *client = to_i2c_client(dev);struct cpld_hq_data *cpld_data = i2c_get_clientdata(client);if (cpld_data == NULL)return -ENODEV;status = kstrtou8(buf, 0, &value);if (status != 0) {return status;}status = i2c_smbus_write_byte_data(client, CPLD_SCRATCH, value);if (status < 0)return status;status = (ssize_t)size;return status;
}
struct device_attribute dev_attr_cpld_i2c_scratch = __ATTR(scratch, 0600, cpld_i2c_scratch_show, cpld_i2c_scratch_store);static ssize_t cpld_i2c_setreg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
{uint8_t addr, value;size_t addr_get = 0;size_t value_get = 0;struct i2c_client *client = to_i2c_client(dev);int8_t *tok;int8_t clone[size];int8_t *pclone = clone;ssize_t status;int8_t len = size;if (client == NULL)return -ENODEV;if (buf[size - 1] == '\0' || buf[size - 1] == '\n')len -= 1;if (len == 0 || len >= sizeof(clone))return -EINVAL;strncpy(clone, buf, len);clone[len] = '\0';tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}status = kstrtoul(tok, 16, &addr_get);if (status < 0)return status;addr = (uint8_t)addr_get;tok = strsep((char **)&pclone, " ");if (tok == NULL) {return -EINVAL;}status = kstrtoul(tok, 16, &value_get);if (status < 0)return status;value = (uint8_t)value_get;status = i2c_smbus_write_byte_data(client, addr, value);if (status < 0)return status;status = (ssize_t)size;return status;
}
struct device_attribute dev_attr_cpld_i2c_setreg = __ATTR(setreg, 0200, NULL, cpld_i2c_setreg_store);static struct attribute *cpld_i2c_attrs[] = {&dev_attr_cpld_i2c_getreg.attr,&dev_attr_cpld_i2c_scratch.attr,&dev_attr_cpld_i2c_setreg.attr,&dev_attr_cpld_i2c_wdt_mask.attr,&dev_attr_watchdog_feed.attr,&dev_attr_get_lc_cpld_board_version.attr,&dev_attr_get_clk_100_stat.attr,&dev_attr_get_clk_156_stat.attr,NULL,
};static struct attribute_group cpld_i2c_attr_grp = {.attrs = cpld_i2c_attrs,
};static int32_t cpld_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{struct i2c_adapter *adapter = client->adapter; // 找到adapterstruct cpld_hq_data *cpld_data;int32_t ret = 0;struct platform_device *switch_dev;if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA | I2C_FUNC_SMBUS_READ_BYTE))  //检查控制器能不能用,能用给下面client用return -EPFNOSUPPORT;cpld_data = devm_kzalloc(&client->dev, sizeof(struct cpld_hq_data), GFP_KERNEL);if (!cpld_data)return -ENOMEM;i2c_set_clientdata(client, cpld_data);mutex_init(&cpld_data->cpld_lock);mutex_init(&cpld_data->wdt_lock);cpld_data->read_addr = 0;cpld_data->base_addr = 0;write_wdt_port(G_PIN_SEL_ADDRESS, G_WDT_FEED, G_VALUE_ONE);write_wdt_port(G_PIN_IN_OUT_ADDRESS, G_WDT_FEED, G_VALUE_ZERO);write_wdt_port(G_WDT_OUT_ADDRESS, G_WDT_FEED, G_VALUE_ONE);ret = sysfs_create_group(&client->dev.kobj, &cpld_i2c_attr_grp);if (ret != 0) {pr_err("Cannot create CPLD sysfs attributes\n");goto err_remove_cpld;}switch_dev = dev_get_platdata(&client->dev);if (switch_dev) {pr_info("switch device %s found \n", switch_dev->name);ret = sysfs_create_link(&switch_dev->dev.kobj, &client->dev.kobj,client->name); // we can use this create link from cpld, link switch to cpld kobjif (ret != 0) {pr_err("%s create link to switch device failed \n", client->name);goto err_remove_cpld_link;}} else {pr_err("switch device not passed\n");ret = -EAGAIN;goto err_remove_cpld_link;}g_kobj = kobject_create_and_add("ott_lc_cpld",NULL);if(!g_kobj) {ret = -EAGAIN;pr_err("create ott_lc_cpld kobject failed.\n");goto err_remove_cpld_link;}ret = sysfs_create_link(g_kobj,&client->dev.kobj,"lc_cpld");if(ret) {pr_err("create ott_lc_cpld sysfs link failed.\n");goto err_remove_cpld_sys;}return 0;err_remove_cpld_sys:kobject_del(g_kobj);kobject_put(g_kobj);err_remove_cpld_link:sysfs_remove_group(&client->dev.kobj, &cpld_i2c_attr_grp);err_remove_cpld:return ret;
}static int32_t cpld_i2c_remove(struct i2c_client *client)
{struct platform_device *switch_dev;switch_dev = dev_get_platdata(&client->dev);if (switch_dev != NULL) {if (&switch_dev->dev.kobj != NULL)sysfs_remove_link(&switch_dev->dev.kobj, client->name);}sysfs_remove_group(&client->dev.kobj, &cpld_i2c_attr_grp);if(g_kobj) {kobject_del(g_kobj);kobject_put(g_kobj);sysfs_remove_link(g_kobj, "lc_cpld");}return 0;
}static const struct i2c_device_id cpld_i2c_id[] = {{"cpld_lc", 0}, {}}; //cpld_lc匹配字符串 fpga_i2c_adapter, 总线,设备,驱动
MODULE_DEVICE_TABLE(i2c, cpld_i2c_id);static struct i2c_driver cpld_i2c_driver = {.driver = {.name = CPLD_DRIVER_NAME,.owner = THIS_MODULE,},.probe = cpld_i2c_probe,.remove = cpld_i2c_remove,.id_table = cpld_i2c_id,
};module_i2c_driver(cpld_i2c_driver);MODULE_AUTHOR("Simon Sun simon.sun@huaqin.com");
MODULE_DESCRIPTION("Hua Qin Common CPLD");
MODULE_VERSION(CPLD_DRIVER_VER);
MODULE_LICENSE("GPL");

相关内容

热门资讯

海南全岛封关时间定了!啥是封关... 国家发展改革委副主任王昌林7月23日在国新办发布会上表示,关于海南自贸港封关的具体时间,经党中央批准...
华能国际完成发行20亿元科技创... 7月23日早间,华能国际发布公告称,公司已于近日完成2025年面向专业投资者公开发行科技创新可续期公...
AWS的智能体基础设施布局:开... 智能体基础设施正在快速成为人工智能下一次飞跃的支柱——不仅仅是实现智能化,更是协调其安全、高效和大规...
中国移动、中国电信、中国联通,... 莫名其妙订了新业务、套餐资费眼花缭乱、接到境外骚扰电话,这些都是电信用户常见的消费痛点。近日,中国移...
上海黄金回收价高秤准还懂老物件... 上海宝易埠珠宝:黄金回收背后的故事 在上海这个繁华喧嚣的大都市,每一条街道都诉说着独特的故事,每一家...
厉害!浙大95后博导白天搞科研... 白天,他是数字法学界的“破壁者”。傍晚,他是“浙BA”球场上的“破局者”。五冠加身的荣耀,科研攻坚的...
宏润建设:7月22日融资买入1... 证券之星消息,7月22日,宏润建设(002062)融资买入1454.54万元,融资偿还8319.83...
苹果在华销售额二季度同比下滑1... 7月23日消息,据多家媒体报道,根据市场调研机构Counterpoint最新数据,2025年第二季度...
恒生电子:7月22日融券卖出2... 证券之星消息,7月22日,恒生电子(600570)融资买入2.37亿元,融资偿还3.05亿元,融资净...
上交所:苏州创元投资发展(集团... 7月23日,上交所发布关于苏州创元投资发展(集团)有限公司2025年面向专业投资者公开发行科技创新公...
和讯投顾赵冰忆:水电站概念盘活... 7月22日,和讯投顾赵冰忆表示,眼下水电站概念足以盘活市场。一方面,水电站有定远方面的业务支撑;另一...
注册资本150亿元,中国聚变能... 可控核聚变概念图 图片来源:视觉中国 7月22日晚间,中国核电发布消息称,当日由其参股的中国聚变能源...
天力复合:7月22日融资买入1... 证券之星消息,7月22日,天力复合(873576)融资买入145.39万元,融资偿还168.55万元...
“3C”标志非商品 违法制售要... 马云骢 “禁止旅客携带没有3C标识、3C标识不清晰、被召回型号或批次的充电宝乘坐境内航班。”近期,民...
亚通股份被责令改正,时任董事长... 雷达财经 文|冯秀语 编|李亦辉 7月22日,上海亚通股份有限公司(证券简称:亚通股份,证券代码:6...
京东美团杀入了同一片战场 作者 | 周智宇 编辑 | 张晓玲 在具身智能的牌桌上,美团一直是那个下注最凶的玩家。它早已将触角伸...
业务创新 | 商业银行谱写养老... 文/中国建设银行平台运营中心 张丰安 肖璧微 我国人口老龄化问题加剧,养老金融发展面临严峻挑战,20...
多行业“反内卷”,持续推进中! 汽车、光伏、水泥、钢铁,不同行业,同在“反内卷”!从7月1日中央财经委员会第六次会议,到近期国务院常...
运输规模稳步增长!今年上半年我... (央视财经《经济信息联播》)今天(21日),民航局相关负责人在国新办新闻发布会上介绍,“十四五”期间...
对话Outer创始人刘佳科:6... 作者:欧雪 编辑:彭孝秋 Outer又有新动作了,这次是推出第二个大单品。 2018年,Outer第...