📄 em8xxx_i2c.c
字号:
/***************************************** Copyright © 2007 Sigma Designs, Inc. Proprietary and Confidential *****************************************//** @file em8xxx_i2c.c @brief I2C driver for the EM8xxx series. Strategy : @author Alan Hightower - Wegener Communications, Inc @date 2007-04-21*/#ifndef __I2CEM8XXX_C__#define __I2CEM8XXX_C__#define ALLOW_OS_CODE 1#include "../../../emhwlib/include/emhwlib.h"#include "../../../emhwlib/include/emhwlib_properties_1000.h"#include "../../../emhwlib/include/emhwlib_chipspecific.h"#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/config.h>#include <linux/stddef.h>#include <linux/version.h>#include <linux/fs.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/i2c.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)#include <linux/moduleparam.h>#endif#include "../../../llad/kinclude/kernelcalls.h"#include "../include/em8xxx_uk.h"#include "em8xxx.h"#include "em8xxx_proc.h"#include "../../../gbuslib/include/gbus_time.h"typedef struct _st_i2cprivate{ /** * Whether the I2C module for this chip has been started */ int active; /** * Chip number for this context info block (index into * this i2cinfo array) */ int instance; /** * I2C subsystem adpater instance information for this * chip's bus */ struct i2c_adapter adapter;} i2cprivate_t;static i2cprivate_t i2cinfo[MAXLLAD];#define I2C_CLOCK_LINE GPIOId_Sys_0#define I2C_DATA_LINE GPIOId_Sys_1#define I2C_API_VERSION 1// uSec delay between bits in i2c#define I2C_DEFAULT_BIT_DELAY 10// frequency of the I2C bit transfer, in kHz#define I2C_DEFAULT_CLOCK_RATE 100static int i2c_bit_delay = I2C_DEFAULT_BIT_DELAY;static int i2c_clock_rate = I2C_DEFAULT_CLOCK_RATE;module_param(i2c_bit_delay, int, 0);module_param(i2c_clock_rate, int, 0);MODULE_PARM_DESC(i2c_bit_delay, "Delay between bits (default " __MODULE_STRING(I2C_DEFAULT_BIT_DELAY) " uSecs).");MODULE_PARM_DESC(i2c_clock_rate, "Bus clock rate (default " __MODULE_STRING(I2C_DEFAULT_CLOCK_RATE) " kHz).");extern struct em8xxxprivate Etable[MAXLLAD];MODULE_DESCRIPTION("EM8XXX I2C SMBus Driver");MODULE_AUTHOR("Alan Hightower <alan@alanlee.org>");MODULE_LICENSE("Proprietary");static int sigma_i2c_master( struct i2c_adapter *adap, struct i2c_msg *msgs, int num){ i2cprivate_t *info = (i2cprivate_t *) adap->algo_data; struct i2c_msg *pmsg; int i, completed = 0; RMstatus err; struct EMhwlibI2CDeviceParameter i2c; struct I2C_WriteData_type i2c_write; struct I2C_QueryData_in_type i2c_param; struct I2C_QueryData_out_type i2c_res; for (i = 0; i < num; i++) { pmsg = &msgs[i];#ifdef I2C_DEBUG_BUS dev_info (&adap->dev, "I2C transaction setup: " "%s %d bytes to 0x%02x - %d of %d messages\n", pmsg->flags & I2C_M_RD ? "read" : "write", pmsg->len, pmsg->addr, i + 1, num);#endif // Setup transaction i2c.APIVersion = I2C_API_VERSION; i2c.Clock = I2C_CLOCK_LINE; i2c.Data = I2C_DATA_LINE; i2c.Delay = i2c_bit_delay; i2c.Speed = i2c_clock_rate; i2c.DevAddr = pmsg->addr << 1;#if 0 if (pmsg->flags & I2C_M_RD) i2c.DevAddr |= 0x01;#endif kc_spin_lock_bh (Etable[info->instance].lock); err = EMhwlibSetProperty (Etable[info->instance].pemhwlib, EMHWLIB_MODULE(I2C, 0), RMI2CPropertyID_DeviceParameter, &i2c, sizeof(i2c)); kc_spin_unlock_bh (Etable[info->instance].lock); if (RMFAILED(err)) { dev_err (&adap->dev, "Unable to set device xfer parameters\n"); continue; } if (pmsg->flags & I2C_M_RD) { i2c_param.UseSubAddr = 0; i2c_param.SubAddr = 0; i2c_param.DataSize = pmsg->len; kc_spin_lock_bh (Etable[info->instance].lock); err = EMhwlibExchangeProperty(Etable[info->instance].pemhwlib, EMHWLIB_MODULE(I2C, 0), RMI2CPropertyID_QueryData, &i2c_param, sizeof(i2c_param), &i2c_res, sizeof(i2c_res)); kc_spin_unlock_bh (Etable[info->instance].lock); if (RMFAILED(err)) { dev_err (&adap->dev, "Unable to perform I2C read - %d\n", err); continue; } memcpy (pmsg->buf, i2c_res.Data, pmsg->len); } else { i2c_write.UseSubAddr = 0; i2c_write.SubAddr = 0; i2c_write.DataSize = pmsg->len; memcpy (i2c_write.Data, pmsg->buf, pmsg->len); kc_spin_lock_bh (Etable[info->instance].lock); err = EMhwlibSetProperty(Etable[info->instance].pemhwlib, EMHWLIB_MODULE(I2C, 0), RMI2CPropertyID_WriteData, &i2c_write, sizeof(i2c_write)); kc_spin_unlock_bh (Etable[info->instance].lock); if (RMFAILED(err)) { dev_err (&adap->dev, "Unable to perform I2C write\n"); continue; } }#ifdef I2C_DEBUG_BUS dev_info (&adap->dev, "I2C transaction completed successfully\n");#endif } return completed;} // end of "sigma_i2c_master ()"static int sigma_i2c_smbus( struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data){ int usesub; int datalen = 0; RMstatus err; i2cprivate_t *info = (i2cprivate_t *) adap->algo_data; struct EMhwlibI2CDeviceParameter i2c; struct I2C_WriteData_type i2c_write; struct I2C_QueryData_in_type i2c_param; struct I2C_QueryData_out_type i2c_res;#ifdef I2C_DEBUG_BUS dev_info(&adap->dev, "%s was called with the following parameters:\n", __FUNCTION__); dev_info(&adap->dev, "addr = %.4x\n", addr); dev_info(&adap->dev, "flags = %.4x\n", flags); dev_info(&adap->dev, "read_write = %s\n", read_write == I2C_SMBUS_WRITE ? "write" : "read"); dev_info(&adap->dev, "command = %d\n", command);#endif switch (size) { case I2C_SMBUS_QUICK:#ifdef I2C_DEBUG_BUS dev_info(&adap->dev, "size = I2C_SMBUS_QUICK (0)\n");#endif usesub = FALSE; datalen = 0; break; case I2C_SMBUS_BYTE:#ifdef I2C_DEBUG_BUS dev_info(&adap->dev, "size = I2C_SMBUS_BYTE (1)\n");#endif usesub = FALSE; datalen = 1; if (read_write == I2C_SMBUS_WRITE) i2c_write.Data[0] = data ? data->byte : 0x00; break; case I2C_SMBUS_BYTE_DATA:#ifdef I2C_DEBUG_BUS dev_info(&adap->dev, "size = I2C_SMBUS_BYTE_DATA (1)\n");#endif usesub = TRUE; datalen = 1; if (read_write == I2C_SMBUS_WRITE) i2c_write.Data[0] = data->byte; break; case I2C_SMBUS_WORD_DATA:#ifdef I2C_DEBUG_BUS dev_info(&adap->dev, "size = I2C_SMBUS_WORD_DATA (2)\n");#endif usesub = TRUE; datalen = 2; if (read_write == I2C_SMBUS_WRITE) { i2c_write.Data[0] = data->word & 0xff; i2c_write.Data[1] = (data->word >> 8) & 0xff; } break; case I2C_SMBUS_BLOCK_DATA: usesub = TRUE; datalen = min_t(u8, data->block[0], 32); if (read_write == I2C_SMBUS_WRITE) memcpy (i2c_write.Data, &data->block[1], datalen);#ifdef I2C_DEBUG_BUS dev_info(&adap->dev, "size = I2C_SMBUS_BLOCK_DATA (%d)\n", datalen);#endif break; case I2C_SMBUS_I2C_BLOCK_DATA: usesub = TRUE; if (read_write == I2C_SMBUS_WRITE) { memcpy (i2c_write.Data, &data->block[1], datalen); datalen = data->block[0]; } else data->block[0] = datalen = 32;#ifdef I2C_DEBUG_BUS dev_info(&adap->dev, "size = I2C_SMBUS_I2C_BLOCK_DATA (%d)\n", datalen);#endif break; default: goto exit_unsupported; } // Setup transaction i2c.APIVersion = I2C_API_VERSION; i2c.Clock = I2C_CLOCK_LINE; i2c.Data = I2C_DATA_LINE; i2c.Delay = i2c_bit_delay; i2c.Speed = i2c_clock_rate; i2c.DevAddr = addr << 1;#if 0 if (read_write == I2C_SMBUS_READ) i2c.DevAddr |= 0x01;#endif kc_spin_lock_bh (Etable[info->instance].lock); err = EMhwlibSetProperty (Etable[info->instance].pemhwlib, EMHWLIB_MODULE(I2C, 0), RMI2CPropertyID_DeviceParameter, &i2c, sizeof(i2c)); kc_spin_unlock_bh (Etable[info->instance].lock); if (RMFAILED(err)) { dev_err (&adap->dev, "Unable to set device xfer parameters" " (addr=0x%04x)\n", addr); return -EINVAL; }#ifdef I2C_DEBUG_BUS dev_info(&adap->dev, "Transaction setup complete\n");#endif if (read_write == I2C_SMBUS_READ) { i2c_param.UseSubAddr = usesub ? 1 : 0; i2c_param.SubAddr = command; i2c_param.DataSize = datalen; kc_spin_lock_bh (Etable[info->instance].lock); err = EMhwlibExchangeProperty(Etable[info->instance].pemhwlib, EMHWLIB_MODULE(I2C, 0), RMI2CPropertyID_QueryData, &i2c_param, sizeof(i2c_param), &i2c_res, sizeof(i2c_res)); kc_spin_unlock_bh (Etable[info->instance].lock); if (RMFAILED(err)) { dev_err (&adap->dev, "Unable to perform I2C read - %d\n", err); return -EINVAL; } switch (size) { case I2C_SMBUS_BYTE: case I2C_SMBUS_BYTE_DATA: data->byte = i2c_res.Data[0]; break; case I2C_SMBUS_WORD_DATA: data->word = i2c_res.Data[0] + (i2c_res.Data[0] << 8); break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA: memcpy (&data->block[1], i2c_res.Data, datalen); break; } } else { i2c_write.UseSubAddr = usesub; i2c_write.SubAddr = command; i2c_write.DataSize = datalen; kc_spin_lock_bh (Etable[info->instance].lock); err = EMhwlibSetProperty(Etable[info->instance].pemhwlib, EMHWLIB_MODULE(I2C, 0), RMI2CPropertyID_WriteData, &i2c_write, sizeof(i2c_write)); kc_spin_unlock_bh (Etable[info->instance].lock); if (RMFAILED(err)) { dev_err (&adap->dev, "Unable to perform I2C write\n"); return -EINVAL; } } return 0;exit_unsupported: dev_warn (&adap->dev, "Unsupported command invoked! (0x%02x)\n", size); return -EINVAL;} // end of "sigma_i2c_smbus ()"static u32 sigma_i2c_func (struct i2c_adapter *adapter){ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_I2C_BLOCK;}static struct i2c_algorithm sigma_i2c_algorithm = { .smbus_xfer = sigma_i2c_smbus, .master_xfer = sigma_i2c_master, .functionality = sigma_i2c_func,};int __init init_module (void){ int i, rc; printk ("em8xxxi2c init begin (bit delay = %d uSec / clock rate = %d KHz)\n", i2c_bit_delay, i2c_clock_rate); for (i = 0 ; i < MAXLLAD; i++) { if ((&Etable[i])->pllad != NULL) { memset (&i2cinfo[i], 0, sizeof (i2cprivate_t)); i2cinfo[i].adapter.owner = THIS_MODULE; i2cinfo[i].adapter.class = I2C_CLASS_HWMON; i2cinfo[i].adapter.algo = &sigma_i2c_algorithm; i2cinfo[i].adapter.algo_data = &i2cinfo[i]; strncpy (i2cinfo[i].adapter.name, "Sigma I2C Driver", I2C_NAME_SIZE - 1); rc = i2c_add_adapter (&i2cinfo[i].adapter); if (rc < 0) { printk ("Unable to register i2c driver for chip %d\n", i); } else { printk ("Registered I2C driver for chip %d\n", i); i2cinfo[i].active = TRUE; i2cinfo[i].instance = i; } } } printk ("em8xxxi2c init end\n"); return 0; } // end of "init_module ()"void __exit cleanup_module (void){ int i; printk ("em8xxxi2c cleanup begin\n"); for (i = 0 ; i < MAXLLAD ; i++) { if (i2cinfo[i].active) { i2c_del_adapter (&i2cinfo[i].adapter); } } printk ("em8xxxi2c cleanup end\n"); return;} // end of "cleanup_module ()"#endif // __I2CEM8XXX_C__
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -