📄 i2c-algo-ip0105.c
字号:
retval = interruptible_sleep_on_timeout(&(busptr->iic_wait_master), (5*HZ)); if (retval == 0) { int i2c_state = read_IP0105_I2C_STATUS(busptr); // I2CSTATIN( device ); int i2c_intstate = read_IP0105_I2C_INT_STATUS(busptr); dev_dbg(&i2c_adap->dev, "I2C Status 0%x, int stat %x\n", i2c_state, i2c_intstate); return errids_IsI2cHardwareError; } return busptr->mst_status; }static int IP0105_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num){ struct i2c_msg *pmsg; void * wr_buf = NULL; void * rd_buf = NULL; int i, wr_len = 0, rd_len = 0; unsigned char addr = msgs[0].addr; int ret=0; dev_dbg(&i2c_adap->dev, "IP0105 xfer nr %d\n", num); ASSERT(num > 0 && num <= 2); for (i = 0; i < num; i++) { pmsg = &msgs[i]; if (i == 0) { if (pmsg->flags & I2C_M_TEN) { // addr = 10 bit addr, not supported yet } else { // addr = 7 bit addr addr &= 0x7f; addr <<= 1; } } /* wr_write handles all master read/write commands, including repeat start (I2C_M_NOSTART) */ if (pmsg->flags & I2C_M_RD ) { /* read bytes into buffer*/ rd_buf = pmsg->buf; rd_len = pmsg->len; } else { /* write bytes from buffer */ wr_buf = pmsg->buf; wr_len = pmsg->len; } } if (num != 0) { switch(ret = i2c_write_read(i2c_adap, addr, wr_buf, wr_len, rd_buf, rd_len)) { case errids_Ok: break; case errids_IsI2cHardwareError: num = -1; dev_dbg(&i2c_adap->dev, "Hardware error\n"); IP0105_reset(i2c_adap); break; case errids_IsI2cDeviceError: num = -1; dev_dbg(&i2c_adap->dev, "Device error\n"); IP0105_reset(i2c_adap); break; case errids_IsI2cWriteError: num = -1; dev_dbg(&i2c_adap->dev, "Write error\n"); IP0105_reset(i2c_adap); break; default: num = -1; dev_dbg(&i2c_adap->dev, "Error Unkonwn\n"); IP0105_reset(i2c_adap); break; } } return num;}static int algo_control(struct i2c_adapter *i2c_adap, unsigned int cmd, unsigned long arg){ struct I2cBusObject * busptr = (struct I2cBusObject *)i2c_adap->algo_data; switch (cmd) { case I2C_SET_SLAVE_ADDRESS: if (busptr->slv_enabled) return -EBUSY; else { write_IP0105_I2C_ADDRESS( busptr, I2CADDRESS( arg )); /* >> 1 */; /* 7 bits address, No General call support */dev_dbg(&i2c_adap->dev, "Set Own adress to %x\n", read_IP0105_I2C_ADDRESS(busptr)); } break; case I2C_SET_SLAVE_ENABLE: if (arg) { if( !busptr->slv_enabled ) { unsigned int len = (unsigned int)arg; len++; // Need an extra byte for the length busptr->slv_buf = kmalloc(len, GFP_KERNEL); if (NULL != busptr->slv_buf) { busptr->slv_usr_notify = &i2c_adap->fasync; busptr->slv_bufindex = 1; busptr->slv_buflen = 0; // todo : slave transmitter, but we can only reveive busptr->slv_bufsize = len; busptr->slv_enabled = TRUE; AAOUT( busptr, 1 ); /* ACK bit will be returned after slave address reception */ dev_dbg(&i2c_adap->dev, "Enable Slave\n"); } else return -ENOMEM; } else return -EBUSY; } else { busptr->slv_usr_notify = NULL; busptr->slv_bufsize = 0; AAOUT( busptr, 0 ); /* ACK will not be sent after slave address reception */ busptr->slv_enabled = FALSE; if (NULL != busptr->slv_buf) { kfree(busptr->slv_buf); // kfree returns void, no check needed } busptr->slv_bufindex = 0; busptr->slv_buflen = 0;dev_dbg(&i2c_adap->dev, "Disable Slave\n"); } break; case I2C_GET_SLAVE_DATA: { unsigned long ret; unsigned char * user_data = (unsigned char *)arg; unsigned char nr_of_bytes = busptr->slv_bufindex -1; busptr->slv_buf[0] = nr_of_bytes; ret = copy_to_user(user_data, busptr->slv_buf, busptr->slv_bufindex); busptr->slv_bufindex = 1; if (busptr->slv_enabled == TRUE) { AAOUT( busptr, 1); /* ACK bit will be returned after slave address reception */ } if (0 == busptr->slv_buf[0]) { return -ENODATA; } } break; } return 0;}static u32 IP0105_func(struct i2c_adapter *adap){ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; }/* -----exported algorithm data: ------------------------------------- */static struct i2c_algorithm IP0105_algo_0 = { .name = "IP0105 dev0", .id = I2C_ALGO_EXP, .master_xfer = IP0105_xfer, .algo_control = algo_control, /* ioctl */ .functionality = IP0105_func, /* functionality */};static struct i2c_algorithm IP0105_algo_1 = { .name = "IP0105 dev1", .id = I2C_ALGO_EXP, .master_xfer = IP0105_xfer, .algo_control = algo_control, .functionality = IP0105_func,};static struct i2c_algorithm * IP0105_algo[NR_I2C_DEVICES] = { &IP0105_algo_0, &IP0105_algo_1 };/* * registering functions to load algorithms at runtime */int i2c_IP0105_add_bus(int device, struct i2c_adapter * i2c_adap){ int res; dev_dbg(&i2c_adap->dev, "i2c-algo-IP0105.o: i2c IP0105 algorithm module\n"); DEB2(printk("i2c-algo-viper.o: hw routines for %s registered.\n", i2c_adap->name)); /* register new adapter to i2c module... */ i2c_adap->algo = IP0105_algo[device]; i2c_adap->id |= i2c_adap->algo->id; i2c_adap->timeout = 100; /* default values, should */ i2c_adap->retries = 3; /* be replaced by defines */ dev_dbg(&i2c_adap->dev, "Initialise IP0105 device %d\n", device); IP0105_init(i2c_adap, device); if ((res = i2c_add_adapter(i2c_adap)) < 0) { dev_dbg(&i2c_adap->dev, "i2c-algo-IP0105 %d: Unable to register with I2C\n", device); return -ENODEV; } dev_dbg(&i2c_adap->dev, "add adapter %d returned %x\n", device, res); /* Todo : scan bus */ return 0;}int i2c_IP0105_del_bus(struct i2c_adapter *i2c_adap){ struct I2cBusObject *busptr; int res; dev_dbg(&i2c_adap->dev, "exit bus %x\n", device); busptr = (struct I2cBusObject *)i2c_adap->algo_data; if ((res = i2c_del_adapter(i2c_adap)) < 0) return res; DEB2(dev_dbg(&i2c_adap->dev, "i2c-algo-IP0105.o: adapter unregistered: %s\n",i2c_adap->name)); return 0;}static struct i2c_adapter IP0105_ops_0 = { .name = "IP0105 0", // name .id = FAST_I2C_PORT_3, // id .algo_data = &IP0105_i2cbus[0], // algo_data};static struct i2c_adapter IP0105_ops_1 = { .name = "IP0105 1", .id = FAST_I2C_PORT_4, .algo_data = &IP0105_i2cbus[1], // algo_data};static struct i2c_adapter * IP0105_ops[NR_I2C_DEVICES] = { &IP0105_ops_0, &IP0105_ops_1 };int __init i2c_algo_IP0105_init (void){ printk("i2c-algo-IP0105.o: i2c IP0105 algorithm module\n"); int device; for (device = 0; device < NR_I2C_DEVICES; device++) { if (i2c_IP0105_add_bus(device, IP0105_ops[device]) < 0) { printk("i2c-algo-IP0105 %d: Unable to register with I2C\n", device); return -ENODEV; } } return 0;}void __exit i2c_algo_IP0105_exit(void){ struct I2cBusObject *busptr; int device; for( device = 0; device < NR_I2C_DEVICES; device++ ) { printk("exit bus %x\n", device); busptr = &IP0105_i2cbus[device]; DISABLE_I2C_INTERRUPT( busptr ); DISABLE_I2C_CONTROLLER( busptr ); /* Disable I2C controller */ disable_irq(busptr->int_pin); /* Enable i2c interrupt in Interrupt controller */ free_irq(busptr->int_pin, (void *)&IP0105_i2cbus[device]); enable_irq(busptr->int_pin); /* Enable i2c interrupt in Interrupt controller */ i2c_IP0105_del_bus(IP0105_ops[device]); }}MODULE_AUTHOR("Willem van Beek <willem.van.beek@philips.com>");MODULE_DESCRIPTION("I2C-Bus adapter routines for IP0105");MODULE_LICENSE("GPL");/* Called when module is loaded or when kernel is initialized. * If MODULES is defined when this file is compiled, then this function will * resolve to init_module (the function called when insmod is invoked for a * module). Otherwise, this function is called early in the boot, when the * kernel is intialized. Check out /include/init.h to see how this works. */subsys_initcall(i2c_algo_IP0105_init);/* Resolves to module_cleanup when MODULES is defined. */module_exit(i2c_algo_IP0105_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -