Hi, For the past month I've been working on porting NetBSD to Openmoko GTA02 phone. The port is mostly based on existing s3c2xx0 platform already supported by NetBSD. One of the sub-components of S3C2440 SOC not supported by the existing port is iic controller. GTA02 has at least 3 components attached to this bus so it's a rather critical to have a working iic bus. Writing a driver for the controller is not a very complicated thing to do, I actually have it working already, but there are a couple of issues I have encountered.
When reading trough the sources of some existing iic bus drivers I've noticed that all of them transfer the data synchronously. In most cases data is being written to the transmitter, start condition is generated, some loop is entered in which the driver actively waits for hardware event indicating either acknowledge or transmit failure. The loop usually has a limited number of iterations to handle transmit timeouts. This whole scheme seems fine if you consider most of the i2c device drivers NetBSD currently supports (eproms, rtcs). One of the components of GTA02 is a slightly more complicated piece of silicon - NXP/Philips PCF50633 [1]. Servicing this device in some circumstances might require several i2c transactions per second. For such workloads it's probably better idea to use interrupt based transfers. The question is how to implement support for such transfers using current iic driver interface? My current approach uses standard NetBSD iic interface (iic_acquire_bus, iic_exec, iic_release_bus). The only difference is that I've added additional flag I2C_F_INTR. When I2C_F_POLL is set the driver works in a way described above. When I2C_F_POLL is set the underlying driver: 1. Populates a work queue with simple operations describing iic transactions that have to be performed. 2. Acquires a spin mutex (IPL SERIAL priority, same as interrupt handler for the driver). 3. Initiates the transfer by filling tx register with slave address, enabling interrupts and generating start condition. 4. Starts waiting on a condition variable, cv_timedwait (mutex from step 2). Now all work is being done by the interrupt handler. Single run of this handler retrieves new task from the work queue (step 1), sets up the hardware to perform it and exits. The hardware is set in a way which triggers another interrupt when transfer has been finished or an error occurred. After all the tasks have been performed the interrupt handler disables interrupts, signals the condition variable and exits. Then it's just a matter of retrieving the results of all the iic transactions performed and returning them to the caller of iic_exec. This scheme works, but: 1. I'm not exactly sure if condition variable is the best synchronization mechanism for this particular use case. I don't know all the facilities NetBSD has to offer (I'm pretty new to NetBSD kernel programming). Is there something else that would be better for this particular job? 2. Condition variables (according to manual pages) put some constrains on where they can be used. Those will obviously also apply to iic_exec calls with with I2C_F_INTR flag. I feel that at least some of those constrains already apply to iic_exec interface. (I wouldn't call it from any interrupt handler for example). The question is if it puts any new constrains on the iic_exec? 3. Right now to indicate that the driver can sleep/use interrupt based transfers I use I2C_F_INTR flag. The question is if a new flag is necessary? I2C_F_POLL is used to tell the driver not to sleep, but actively wait for the transfer to finish. When not specified we could treat it as an indication that interrupt based transfer is allowed/desired. Should a new flag be added? /ptw [1] http://people.openmoko.org/tony_tu/GTA02/datasheet/PMU/PCF50633DS_02.pdf
