📄 i2c-keywest.c
字号:
/* 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 */ DBG("using interrupt mode...\n"); wait_for_completion(&iface->complete); #endif /* POLLED_MODE */ rc = iface->result; DBG("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 */ up(&iface->sem); return rc;}/* * Generic i2c master transfer entrypoint */static intkeywest_xfer( struct i2c_adapter *adap, struct i2c_msg msgs[], int num){ struct keywest_chan* chan = (struct keywest_chan*)adap->data; struct keywest_iface* iface = chan->iface; struct i2c_msg *pmsg; int i, completed; int rc = 0; down(&iface->sem); /* 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; } DBG("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; iface->stopretry = 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)); /* Arm timeout */ iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; add_timer(&iface->timeout_timer); /* Start sending address & enable interrupt*/ write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR); write_reg(reg_ier, KW_I2C_IRQ_MASK);#ifdef POLLED_MODE DBG("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 */88 DBG("using interrupt mode...\n"); wait_for_completion(&iface->complete); #endif /* POLLED_MODE */ rc = iface->result; if (rc == 0) completed++; DBG("transfer done, result: %d\n", rc); } /* Release sem */ up(&iface->sem); 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;}static voidkeywest_inc(struct i2c_adapter *adapter){ MOD_INC_USE_COUNT;}static voidkeywest_dec(struct i2c_adapter *adapter){ MOD_DEC_USE_COUNT;}/* 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){ unsigned long steps, *psteps, *prate; unsigned bsteps, tsize, i, nchan, addroffset; struct keywest_iface* iface; int rc; psteps = (unsigned long *)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 (!strcmp(np->parent->name, "uni-n")) { 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"); return -ENOMEM; } memset(iface, 0, tsize); init_MUTEX(&iface->sem); spin_lock_init(&iface->lock); init_completion(&iface->complete); 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); return -ENOMEM; } init_timer(&iface->timeout_timer); iface->timeout_timer.function = keywest_timeout; iface->timeout_timer.data = (unsigned long)iface; /* Select interface rate */ iface->cur_mode = KW_I2C_MODE_100KHZ; prate = (unsigned long *)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", *prate); } /* Select standard sub mode */ iface->cur_mode |= KW_I2C_MODE_STANDARDSUB; /* 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, 0, "keywest i2c", iface); if (rc) { printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq); iounmap((void *)iface->base); kfree(iface); return -ENODEV; }#endif /* POLLED_MODE */ 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.inc_use = keywest_inc; chan->adapter.dec_use = keywest_dec; chan->adapter.client_register = NULL; chan->adapter.client_unregister = NULL; chan->adapter.data = chan; rc = i2c_add_adapter(&chan->adapter); if (rc) { printk("i2c-keywest.c: Adapter %s registration failed\n", chan->adapter.name); chan->adapter.data = 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); iface->next = ifaces; ifaces = iface; return 0;}static voiddispose_iface(struct keywest_iface *iface){ int i, rc; ifaces = iface->next; /* Make sure we stop all activity */ down(&iface->sem);#ifndef POLLED_MODE spin_lock_irq(&iface->lock); while (iface->state != state_idle) { spin_unlock_irq(&iface->lock); schedule(); 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 */ up(&iface->sem); /* Release all channels */ for (i=0; i<iface->chan_count; i++) { struct keywest_chan* chan = &iface->channels[i]; if (!chan->adapter.data) continue; rc = i2c_del_adapter(&chan->adapter); chan->adapter.data = 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); kfree(iface);}static int __initi2c_keywest_init(void){ struct device_node *np; int rc = -ENODEV; np = find_compatible_devices("i2c", "keywest"); while (np != 0) { if (np->n_addrs >= 1 && np->n_intrs >= 1) rc = create_iface(np); np = np->next; } if (ifaces) rc = 0; return rc;}static void __exiti2c_keywest_cleanup(void){ while(ifaces) dispose_iface(ifaces);}module_init(i2c_keywest_init);module_exit(i2c_keywest_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -