C6333
Posted 码农编程录
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C6333相关的知识,希望对你有一定的参考价值。
mc24lc64t.c
/*================================================================
* Copyright (C) 2020,Huaqin Technology Co.,Ltd.
* All rights reserved.
* Building 10, No, 399, Keyuan Road, Pudong, Shanghai
*
*
* File Name : mc24lc64t.c
* Author : carl.wang (carl.wang@huaqin.com)
* Created Time: Thu Dec 14 16:12:51 2020
* Description : mc24lc64t.c -- the driver for Microchip 24LC64T.
* Copyright (C) 2020 Huaqin Corp.
*
* 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 0 of the License, Or (at
* your option) any later version. eeprom驱动
*
================================================================*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#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 <peter@korsgaard.com>
*/
#ifndef _LINUX_I2C_OCORES_H
#define _LINUX_I2C_OCORES_H
struct 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 <peter@korsgaard.com>
*
* Support for the GRLIB port of the controller by
* Andreas Larsson <andreas@gaisler.com> 节点:i2c-1,控制器属性
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
//#include <linux/platform_data/i2c-ocores.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/log2.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
#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 0x3e0
static 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, rs485转TTL电平的芯片