📄 i2c-keywest.c
字号:
rc = iface->result; pr_debug("transfer done, result: %d\n", rc); if (rc == 0 && size == I2C_SMBUS_WORD_DATA && read_write == I2C_SMBUS_READ) data->word = le16_to_cpu(cur_word); /* Release sem */ pmac_low_i2c_unlock(iface->node); return rc;}/* * Generic i2c master transfer entrypoint */static intkeywest_xfer( struct i2c_adapter *adap, struct i2c_msg msgs[], int num){ struct keywest_chan* chan = i2c_get_adapdata(adap); struct keywest_iface* iface = chan->iface; struct i2c_msg *pmsg; int i, completed; int rc = 0; if (iface->state == state_dead) return -ENXIO; if (pmac_low_i2c_lock(iface->node)) return -ENXIO; /* Set adapter to standard mode */ iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK; iface->cur_mode |= KW_I2C_MODE_STANDARD; completed = 0; for (i = 0; rc >= 0 && i < num;) { u8 addr; pmsg = &msgs[i++]; addr = pmsg->addr; if (pmsg->flags & I2C_M_TEN) { printk(KERN_ERR "i2c-keywest: 10 bits addr not supported !\n"); rc = -EINVAL; break; } pr_debug("xfer: chan: %d, doing %s %d bytes to 0x%02x - %d of %d messages\n", chan->chan_no, pmsg->flags & I2C_M_RD ? "read" : "write", pmsg->len, addr, i, num); /* Setup channel & clear pending irqs */ write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4)); write_reg(reg_isr, read_reg(reg_isr)); write_reg(reg_status, 0); iface->data = pmsg->buf; iface->datalen = pmsg->len; iface->state = state_addr; iface->result = 0; if (pmsg->flags & I2C_M_RD) iface->read_write = I2C_SMBUS_READ; else iface->read_write = I2C_SMBUS_WRITE; /* Set up address and r/w bit */ if (pmsg->flags & I2C_M_REV_DIR_ADDR) addr ^= 1; write_reg(reg_addr, (addr << 1) | ((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));#ifndef POLLED_MODE /* Arm timeout */ iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; add_timer(&iface->timeout_timer);#endif /* Start sending address & enable interrupt*/ write_reg(reg_ier, KW_I2C_IRQ_MASK); write_reg(reg_control, KW_I2C_CTL_XADDR);#ifdef POLLED_MODE pr_debug("using polled mode...\n"); /* State machine, to turn into an interrupt handler */ while(iface->state != state_idle) { u8 isr = wait_interrupt(iface); handle_interrupt(iface, isr); }#else /* POLLED_MODE */ pr_debug("using interrupt mode...\n"); wait_for_completion(&iface->complete); #endif /* POLLED_MODE */ rc = iface->result; if (rc == 0) completed++; pr_debug("transfer done, result: %d\n", rc); } /* Release sem */ pmac_low_i2c_unlock(iface->node); return completed;}static u32keywest_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;}/* For now, we only handle combined mode (smbus) */static struct i2c_algorithm keywest_algorithm = { .name = "Keywest i2c", .id = I2C_ALGO_SMBUS, .smbus_xfer = keywest_smbus_xfer, .master_xfer = keywest_xfer, .functionality = keywest_func,};static intcreate_iface(struct device_node *np, struct device *dev){ unsigned long steps; unsigned bsteps, tsize, i, nchan, addroffset; struct keywest_iface* iface; u32 *psteps, *prate; int rc; if (pmac_low_i2c_lock(np)) return -ENODEV; psteps = (u32 *)get_property(np, "AAPL,address-step", NULL); steps = psteps ? (*psteps) : 0x10; /* Hrm... maybe we can be smarter here */ for (bsteps = 0; (steps & 0x01) == 0; bsteps++) steps >>= 1; if (np->parent->name[0] == 'u') { nchan = 2; addroffset = 3; } else { addroffset = 0; nchan = 1; } tsize = sizeof(struct keywest_iface) + (sizeof(struct keywest_chan) + 4) * nchan; iface = (struct keywest_iface *) kmalloc(tsize, GFP_KERNEL); if (iface == NULL) { printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n"); pmac_low_i2c_unlock(np); return -ENOMEM; } memset(iface, 0, tsize); spin_lock_init(&iface->lock); init_completion(&iface->complete); iface->node = of_node_get(np); iface->bsteps = bsteps; iface->chan_count = nchan; iface->state = state_idle; iface->irq = np->intrs[0].line; iface->channels = (struct keywest_chan *) (((unsigned long)(iface + 1) + 3UL) & ~3UL); iface->base = (unsigned long)ioremap(np->addrs[0].address + addroffset, np->addrs[0].size); if (iface->base == 0) { printk(KERN_ERR "i2c-keywest: can't map inteface !\n"); kfree(iface); pmac_low_i2c_unlock(np); return -ENOMEM; }#ifndef POLLED_MODE init_timer(&iface->timeout_timer); iface->timeout_timer.function = keywest_timeout; iface->timeout_timer.data = (unsigned long)iface;#endif /* Select interface rate */ iface->cur_mode = KW_I2C_MODE_100KHZ; prate = (u32 *)get_property(np, "AAPL,i2c-rate", NULL); if (prate) switch(*prate) { case 100: iface->cur_mode = KW_I2C_MODE_100KHZ; break; case 50: iface->cur_mode = KW_I2C_MODE_50KHZ; break; case 25: iface->cur_mode = KW_I2C_MODE_25KHZ; break; default: printk(KERN_WARNING "i2c-keywest: unknown rate %ldKhz, using 100KHz\n", (long)*prate); } /* Select standard mode by default */ iface->cur_mode |= KW_I2C_MODE_STANDARD; /* Write mode */ write_reg(reg_mode, iface->cur_mode); /* Switch interrupts off & clear them*/ write_reg(reg_ier, 0x00); write_reg(reg_isr, KW_I2C_IRQ_MASK);#ifndef POLLED_MODE /* Request chip interrupt */ rc = request_irq(iface->irq, keywest_irq, SA_INTERRUPT, "keywest i2c", iface); if (rc) { printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq); iounmap((void *)iface->base); kfree(iface); pmac_low_i2c_unlock(np); return -ENODEV; }#endif /* POLLED_MODE */ pmac_low_i2c_unlock(np); dev_set_drvdata(dev, iface); for (i=0; i<nchan; i++) { struct keywest_chan* chan = &iface->channels[i]; u8 addr; sprintf(chan->adapter.name, "%s %d", np->parent->name, i); chan->iface = iface; chan->chan_no = i; chan->adapter.id = I2C_ALGO_SMBUS; chan->adapter.algo = &keywest_algorithm; chan->adapter.algo_data = NULL; chan->adapter.client_register = NULL; chan->adapter.client_unregister = NULL; i2c_set_adapdata(&chan->adapter, chan); chan->adapter.dev.parent = dev; rc = i2c_add_adapter(&chan->adapter); if (rc) { printk("i2c-keywest.c: Adapter %s registration failed\n", chan->adapter.name); i2c_set_adapdata(&chan->adapter, NULL); } if (probe) { printk("Probe: "); for (addr = 0x00; addr <= 0x7f; addr++) { if (i2c_smbus_xfer(&chan->adapter,addr, 0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) printk("%02x ", addr); } printk("\n"); } } printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n", np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps); return 0;}static intdispose_iface(struct device *dev){ struct keywest_iface *iface = dev_get_drvdata(dev); int i, rc; /* Make sure we stop all activity */ if (pmac_low_i2c_lock(iface->node)) return -ENODEV;#ifndef POLLED_MODE spin_lock_irq(&iface->lock); while (iface->state != state_idle) { spin_unlock_irq(&iface->lock); set_task_state(current,TASK_UNINTERRUPTIBLE); schedule_timeout(HZ/10); spin_lock_irq(&iface->lock); }#endif /* POLLED_MODE */ iface->state = state_dead;#ifndef POLLED_MODE spin_unlock_irq(&iface->lock); free_irq(iface->irq, iface);#endif /* POLLED_MODE */ pmac_low_i2c_unlock(iface->node); /* Release all channels */ for (i=0; i<iface->chan_count; i++) { struct keywest_chan* chan = &iface->channels[i]; if (i2c_get_adapdata(&chan->adapter) == NULL) continue; rc = i2c_del_adapter(&chan->adapter); i2c_set_adapdata(&chan->adapter, NULL); /* We aren't that prepared to deal with this... */ if (rc) printk("i2c-keywest.c: i2c_del_adapter failed, that's bad !\n"); } iounmap((void *)iface->base); dev_set_drvdata(dev, NULL); of_node_put(iface->node); kfree(iface); return 0;}static intcreate_iface_macio(struct macio_dev* dev, const struct of_match *match){ return create_iface(dev->ofdev.node, &dev->ofdev.dev);}static intdispose_iface_macio(struct macio_dev* dev){ return dispose_iface(&dev->ofdev.dev);}static intcreate_iface_of_platform(struct of_device* dev, const struct of_match *match){ return create_iface(dev->node, &dev->dev);}static intdispose_iface_of_platform(struct of_device* dev){ return dispose_iface(&dev->dev);}static struct of_match i2c_keywest_match[] = { { .name = OF_ANY_MATCH, .type = "i2c", .compatible = "keywest" }, {},};static struct macio_driver i2c_keywest_macio_driver = { .name = "i2c-keywest", .match_table = i2c_keywest_match, .probe = create_iface_macio, .remove = dispose_iface_macio};static struct of_platform_driver i2c_keywest_of_platform_driver = { .name = "i2c-keywest", .match_table = i2c_keywest_match, .probe = create_iface_of_platform, .remove = dispose_iface_of_platform};static int __initi2c_keywest_init(void){ of_register_driver(&i2c_keywest_of_platform_driver); macio_register_driver(&i2c_keywest_macio_driver); return 0;}static void __exiti2c_keywest_cleanup(void){ of_unregister_driver(&i2c_keywest_of_platform_driver); macio_unregister_driver(&i2c_keywest_macio_driver);}module_init(i2c_keywest_init);module_exit(i2c_keywest_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -