Gumstix Overo, RC Servos, and PWM Signal Generation

What I want to do: Control RC Servos from a Gumstix Overo

I have a project where I need to drive standard RC servos from a Gumstix Overo.  It doesn’t appear that the Overo ships with any built in PWM drivers.  I did quite a bit of googling, and still couldn’t find a single drop-in driver that worked well for driving RC servos.  I did find some great help though, rolled up my sleeves, and stitched pieces together to make the mother of all RC servo drivers.
Scott Ellis @ jumpnowtek.com has a nice introduction to programming the Overo hardware PWM signal generators: http://www.jumpnowtek.com/index.php?option=com_content&view=article&id=56&Itemid=63
The Overo has 4 available PWM signal generators on 4 specific GPIO lines.  Scott provides a simple driver that demonstrates how to configure PWM10 to generate a signal at any frequency and duty cycle.

What is PWM?  Frequency?  Duty Cycle?

PWM stands for “pulse width modulation”.  It is a common approach for computer servo control.  Essentially the computer sends a short signal pulse (raises the signal line high.)  The exact length of this pulse tells the servo where to position itself.  The computer sends the pulse at a regular rate and varies the “width” (or the time span) of the pulse to control the position of the servo.  This is how all standard RC servos work.  The number of pulses we send per second is called the “frequency”.  Typical RC systems use a frequency of 50hz.  The ratio of the on versus off time of the signal is called the “duty cycle”.  A duty cycle of 0% means no pulse at all.  A duty cycle of 100% means the pulse is always on.

For a standard RC system running at 50hz, there will be a pulse generated every 20,000 us.  (1 sec = 1,000,000 us; and 1,000,000us / 50hz = 20,000us).  The pulse length to center a servo is 1500 us and the useful pulse range to run the servo through it’s full range of motion is about 1000 us – 2000 us.  If you send a 1500us pulse every 20,000us, then the duty cycle is 1500 / 20,000 or 7.5%.  The duty cycle range for controlling a servo at 50hz is then between 5% and 10%.

Scott Ellis’s “Basic” PWM Kernel Driver

Scott Ellis on the page linked above makes a basic pwm.c driver available.  This driver only sets up one PWM (PWM10 aka GPIO145).  This is routed to pin 28 on the “standard” 40 pin breakout header included on many overo expansion boards.  This was a great start, but has some limitations.

  • It only supports one PWM line (PWM10)
  • Duty cycle is entered as an integer percentage.  RC servos operate across the range of about 5-10% so that only gives me 6 unique positions, not nearly the granularity I want

Signal (Logic) Level Translation

A quick note on something that can turn into a really tricky headache for newcomers to the Overo.  The Overo uses 1.8v logic for all it’s output.  This means that even though you are generating a perfect PWM signal to drive your servo, nothing will probably happen because the servo is expecting 3.3v (or maybe even 5v) signal logic.  It may not see or respond correctly to 1.8v logic.  This is also a more general issue for any external communication with the gumstix overo and is something embedded hardware engineers encounter every day.  There are many ways to address this issue, but one quick and easy solution is to buy a logic level converter from sparkfun.com: http://www.sparkfun.com/products/8745

This sparkfun board supports level shifting for 4 lines at the same time.  I soldered 0.1″ male header pins onto both sides and then used sparkfun 6″ single wire jumpers to connect things together.  It is slick and relatively easy and with the color coded wires it even looks cool, especially on a glass desk with the office lights off and all the LED’s blinking.  🙂  All you have to do is tie your grounds together.  Then connect 1.8v (pin #16 on the 40 pin header) to the LV side.  Connect 3.3v (pin #2 on the 40 pin header) to the HV side, and then pipe the signal line through to the servo.  Despite the RX/TX labelling, I believe the signal conversion is bi-directional on the latest version of this sparkfun level shifter board.

Jack Elston’s Driver Extension to Support all Four PWM Lines

Scott emailed me an update to his pwm.c which expands support to all 4 hardware PWM signal generators.  This is a great next step.  However this version of the driver also had some limitations:

  • PWM10 and PWM11 used the 32Khz clock (which is the default).  Leaving the details aside, the 32Khz clock can only achieve about 32 unique positions across the typical RC servo range of motion.
  • I believe there is some integer overflow for PWM8 and PWM9 when computing the duty cycle which leads to odd results.
  • Part way into the project I decided I wanted to generate PWM pulses with sub us resolution.

13Mhz Versus 32Ghz Clock

Scott Ellis to the rescue again.  Scott emailed me an older testing driver he had built called “pulse.c” (note: Scott makes all his drivers available github.com under the GPL license.)  The pulse.c driver includes code to set the PWM10 and PWM11 timers to use the 13Mhz clock.
The 13Mhz clock allows us to have 259,998 duty cycle steps.  In other words 0 corresponds to 0% duty cycle and 259,998 corresponds to a 100% duty cycle.  Since an RC servo is expecting a 5-10% duty cycle at 50hz, this gives us a numeric range of about 13,000 values to work with.  We are interested in a pulse with range of 1000-2000us (a range of 1000us) so 1000us / 13,000 step sizes gives us better than 0.1us resolution.
0.1 us resolution gives us 10,000 unique positions across the range of motion of a typical RC servo.  For reference, if we were driving a pan servo on a camera system that was setup for 180 degree coverage, we would have approximately 0.02 degree resolution.
Now, whether or not an RC servo can resolve input signals down to this level of accuracy is a different discussion, but servo technology does continue to improve steadily.

Integer Overflow!

Integer overflow is never any fun.  The math proceeds without reporting any errors and you get the wrong answer.  Grrr.  Note that INT_MAX for an unsigned 32bit integer is 4294967295.  tmar is the integer duty cycle percentage ranging from 0 to 259,998.  num_freq is the max number of duty cycle steps (in our case 259,998 for the 13Mhz clock.)  The formula to compute the tmar value is then: pulse_us * frequency * num_freq / 1000000.
Here’s the problem, when computing this formula with a pulse of 1500us, you get an intermediate value of 19499850000 before dividing by 1,000,000.  This is way larger than INT_MAX so the math wraps around and the result after the divide is totally wrong.
As a work around I observe that frequency (50) divides evenly into 1,000,000 so I can rearrange terms and do that division first.  This keeps all the intermediate values less than INT_MAX.

Getting to 0.1 us Resolution

So far so good if I’m specifying integer us pulse widths to the kernel.  However I want to have 0.1 us resolution because the 13Mhz clock offers that level of resolution.
Doing floating point math inside a kernel driver is considered bad form, and you have to do a lot of horsing around just to get proper machine code generated and linked with the right libraries.  We don’t want to go there, so no floating point.
Instead I will specify timing values in 10ths of a us.  So to request a 1500us pulse I would write a value of 1500us*10 or 15,000.  Writing a value of 15,001 to the driver will give me a 1500.1 us pulse.
Back to integer overflow again.  Specifying a larger input value in the range of 10,000 to 20,000 suddenly pushes me back into integer overflow territory with my intermediate values.  259,998 / INT_MAX = 16519.2 so any pulse longer that 1651.9 us will push me back into int overflow.  The solution is that I observe that 259,998 is divisible by 2, so I can pre-divide this number by 2 and earlier divide 1,000,000 by 2 to get an equivalent answer.  This allows me to specify signal widths of up to 3303.8 us which is well beyond that standard RC range again.  I realize this is a pretty specific solution for this particular hardware and this particular clock frequency, but when dealing with embedded systems, you often have to get specific.

What’s so special about 259,998?

When dealing with low level hardware and clocks, you end up running into very odd ball numbers that some CPU hardware designer somewhere must have thought was cool.  259,998 is an annoying number.  Prime factorization is 2 • 3 • 17 • 2,549.  This means it’s hard to divide evenly with anything and it can be a challenge to try to simplify integer math expressions to eliminate intermediate integer overflow!
Observe that 259,998 * 50hz = 12,999,900.  In computers, kilo often refers to 1000 and mega refers to 1,000,000.  So 12,999,900 / 1,000,000 = 12.9999 Mhz.  Let’s round that up to 13 and I think you see this is the number of clock ticks per second a 13Mhz clock generates.  259,998 is the number of ticks per 1/50 of a second.  (You see, it all makes perfect sense!)

Getting the Updated Driver Code (Driver to Command and Control 4 High Resolution PWM Signals on a Gumstix Overo)

Scott was kind enough to commit my version of the pwm driver to a branch of his omap3-pwm project on github.  You can access the branch here (called “four-channel”):  https://github.com/scottellis/omap3-pwm/tree/four-channel

Future Enhancements

Scott suggested that a nice extension would be to allow the user to select which of the 4 PWM channels are activated and configured when the module is loaded (or via a platform device whatever that is.)

Join the Conversation

11 Comments

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.

  1. Thanks for the quick reply Curtis. For the time being I will use the Pinto-TH as a vehicle-mounted board and a Summit for prototyping and firmware flashing. For the future: Your autopilot board on atiak.com looks very interesting, will this be aimed at small UAV’s or at larger vehicles?

  2. Hi Curtis, Excellent article. I want to use this for controlling a quadrotor vehicle using high-level C++ code running on the Overo, which gets its information from a serial IMU and I2C visual sensor. What kind of expansion board to you use to connect to the Overo? Regards.

    1. Hi Wesley, for bread-boarding I’ve used both the Tobi and the Pinto-TH, but we are also developing our own custom board that will integrate sensors and comms and power management that the overo will plug right into: http://www.atiak.com

  3. Hi Steven, I don’t own a beagle board, but I think there is a very good chance that beagle and gumstix don’t always use the same IO lines for the same purposes. So it could be that something the gumstix pwm driver does is stepping on the lines used for usb by the beagleboard? I’m just guessing though. I’m happy to tell you what I know and have figured out, but I’ve never run a beagleboard myself.

  4. H curt, thank you so much for the guide, i now understand how pwm works and i also successfully cross compiled the driver you liked above. I ported it to my beagleboard and every things worked when i use serial connection from my Ubuntu labtop to the beagleboard. Except when I used the GUI from the beagleboard. When i typed insmomd pwm.ko and pressed enter, my mouse and keyboard(connected to beagleboard) did no work anymore. So i had to reboot my beagleboard. Is this a side effect of using this driver or i did something wrong? hope you could help me. Thanks so much..

  5. Yeah, you need to compile it for your overo. This is where embedded systems can get “fun”. You need to create the cross compiler development environment for your target system. There are howto’s on the gumstix wiki that are relatively straight forward if you follow the instructions carefully. But expect glitches along the way that you’ll need to research and fix. It’s a learning process and expect it to require some substantial time to get up to speed and figure everything out that you need.

  6. Ok, that makes sense. I think the part I am missing is compiling the module on my host machine. All I did was download the .zip file. Do I need to compile it on a linux based machine?

  7. Hi,
    I am trying to load the module for the PWM driver to control two servos. I commented out the initialization of the PWM 10 and 11 on the .c file since I am only using PWM 8 and 9. I really need help loading the driver onto my Gumstix Overo. I am knew to linux and have no idea how to go about doing this. I am sure I will have no problem creating the PWM once I load the driver. Could you possibly help me? I looked at the readme file on the omap3-pwm but it was just confusing and I had no idea now to even begin.

    Thanks. And this page is really helpful.

    1. Hi Cheryl,

      When you compile the module on your host machine, it should produce a file with a .ko extension. You want to copy this to your gumstix (it doesn’t matter where — for testing I just copy it to root’s home directory.) Then on the gumstix just run “insmod .ko”. Does that help?

      Curt.

  8. Hi Rodrigo,

    I don’t own a beagle board, but here are a couple random thoughts.

    – It would be interesting to strip away all the kernel messages not related to the pwm driver.

    – What is your module load command? I use “insmod pwm.ko” or “insmod pwm.ko frequency=X” if I want to set a frequency. I noticed an “unknown parameter 50” at t=590 in your log which looks suspect.

    – Is it possible that the beagleboard kernel/u-boot has pre-configured the PWM generator lines in some other mode, or is already using them for something else, or already has it’s own driver for these PWM lines?

    Good luck!

  9. any luck on getting this to run on a beagleboard?
    i managed to load the module, but i fails when i try to set a duty cycle (ie, when i try to get it to run)
    this is my dmesg:

    ] Disabling unused clock “gpio1_dbck”
    [ 12.155914] Disabling unused clock “gpt1_fck”
    [ 12.155944] Disabling unused clock “cam_mclk”
    [ 12.156005] Disabling unused clock “des1_ick”
    [ 12.156005] Disabling unused clock “sha11_ick”
    [ 12.156036] Disabling unused clock “rng_ick”
    [ 12.156036] Disabling unused clock “aes1_ick”
    [ 12.156066] Disabling unused clock “ssi_ick”
    [ 12.156097] Disabling unused clock “mailboxes_ick”
    [ 12.156097] Disabling unused clock “mcbsp_ick”
    [ 12.156127] Disabling unused clock “mcbsp_ick”
    [ 12.156158] Disabling unused clock “gpt10_ick”
    [ 12.156158] Disabling unused clock “gpt11_ick”
    [ 12.156188] Disabling unused clock “hdq_ick”
    [ 12.156219] Disabling unused clock “mspro_ick”
    [ 12.156219] Disabling unused clock “des2_ick”
    [ 12.156250] Disabling unused clock “sha12_ick”
    [ 12.156280] Disabling unused clock “aes2_ick”
    [ 12.156280] Disabling unused clock “icr_ick”
    [ 12.156311] Disabling unused clock “pka_ick”
    [ 12.156341] Disabling unused clock “ssi_ssr_fck”
    [ 12.156341] Disabling unused clock “hdq_fck”
    [ 12.156372] Disabling unused clock “mcbsp_fck”
    [ 12.156402] Disabling unused clock “mcbsp_fck”
    [ 12.156402] Disabling unused clock “mspro_fck”
    [ 12.156433] Disabling unused clock “gpt11_fck”
    [ 12.156463] Disabling unused clock “gpt10_fck”
    [ 12.156463] Disabling unused clock “sad2d_ick”
    [ 12.156524] Disabling unused clock “dpll4_m6x2_ck”
    [ 12.156524] Disabling unused clock “dpll3_m3x2_ck”
    [ 12.156555] Disabling unused clock “sys_clkout1”
    [ 12.157348] ————[ cut here ]————
    [ 12.162048] WARNING: at arch/arm/mach-omap2/dpll.c:439 omap3_noncore_dpll_set_rate+0x228/0x26c()
    [ 12.170928] Modules linked in:
    [ 12.174041] [] (unwind_backtrace+0x0/0xdc) from [] (warn_slowpath_common+0x4c/0x80)
    [ 12.183532] [] (warn_slowpath_common+0x4c/0x80) from [] (omap3_noncore_dpll_set_rate+0x228/0x26c)
    [ 12.194244] [] (omap3_noncore_dpll_set_rate+0x228/0x26c) from [] (omap2_clk_set_rate+0x24/0x34)
    [ 12.204772] [] (omap2_clk_set_rate+0x24/0x34) from [] (clk_set_rate+0x4c/0xac)
    [ 12.213836] [] (clk_set_rate+0x4c/0xac) from [] (program_opp+0xe0/0x180)
    [ 12.222351] [] (program_opp+0xe0/0x180) from [] (resource_set_opp_level+0xf0/0x16c)
    [ 12.231842] [] (resource_set_opp_level+0xf0/0x16c) from [] (set_opp+0x3c/0x100)
    [ 12.240966] [] (set_opp+0x3c/0x100) from [] (update_resource_level+0xa8/0xcc)
    [ 12.249908] [] (update_resource_level+0xa8/0xcc) from [] (set_freq+0x110/0x138)
    [ 12.259063] [] (set_freq+0x110/0x138) from [] (update_resource_level+0xa8/0xcc)
    [ 12.268188] [] (update_resource_level+0xa8/0xcc) from [] (omap_target+0x5c/0x78)
    [ 12.277404] [] (omap_target+0x5c/0x78) from [] (__cpufreq_driver_target+0x5c/0x78)
    [ 12.286804] [] (__cpufreq_driver_target+0x5c/0x78) from [] (cpufreq_governor_performance+0x48/0x5c)
    [ 12.297698] [] (cpufreq_governor_performance+0x48/0x5c) from [] (__cpufreq_governor+0x160/0x1bc)
    [ 12.308319] [] (__cpufreq_governor+0x160/0x1bc) from [] (__cpufreq_set_policy+0x190/0x220)
    [ 12.318420] [] (__cpufreq_set_policy+0x190/0x220) from [] (cpufreq_add_dev+0x3dc/0x564)
    [ 12.328247] [] (cpufreq_add_dev+0x3dc/0x564) from [] (sysdev_driver_register+0xb0/0x120)
    [ 12.338195] [] (sysdev_driver_register+0xb0/0x120) from [] (cpufreq_register_driver+0xec/0x1cc)
    [ 12.348724] [] (cpufreq_register_driver+0xec/0x1cc) from [] (do_one_initcall+0x5c/0x1bc)
    [ 12.358642] [] (do_one_initcall+0x5c/0x1bc) from [] (kernel_init+0xa4/0x128)
    [ 12.367523] [] (kernel_init+0xa4/0x128) from [] (kernel_thread_exit+0x0/0x8)
    [ 12.376403] —[ end trace a50eb8876048cc81 ]—
    [ 12.381317] VFP support v0.3: implementor 41 architecture 3 part 30 variant c rev 1
    [ 12.389739] registered taskstats version 1
    [ 12.409637] Console: switching to colour frame buffer device 80×30
    [ 12.436004] regulator_init_complete: incomplete constraints, leaving VAUX3 on
    [ 12.448394] regulator_init_complete: incomplete constraints, leaving VDAC on
    [ 12.460693] omap_vout omap_vout: probed for an unknown device
    [ 12.471343] Waiting 2sec before mounting root device…
    [ 12.618164] mmc0: new SDHC card at address e624
    [ 12.627685] mmcblk0: mmc0:e624 SD08G 7.40 GiB
    [ 12.636932] mmcblk0: p1 p2
    [ 14.877777] EXT3-fs (mmcblk0p2): warning: maximal mount count reached, running e2fsck is recommended
    [ 14.895751] kjournald starting. Commit interval 5 seconds
    [ 14.908721] EXT3-fs (mmcblk0p2): using internal journal
    [ 14.918243] EXT3-fs (mmcblk0p2): recovery complete
    [ 14.930053] EXT3-fs (mmcblk0p2): mounted filesystem with writeback data mode
    [ 14.941314] VFS: Mounted root (ext3 filesystem) on device 179:2.
    [ 14.959960] devtmpfs: mounted
    [ 14.966888] Freeing init memory: 204K
    [ 15.715850] udev: starting version 151
    [ 206.189971] usb0: MAC 16:0f:15:5a:e1:20
    [ 206.209228] usb0: HOST MAC 16:0f:15:5a:e1:21
    [ 206.227478] g_ether gadget: Ethernet Gadget, version: Memorial Day 2008
    [ 206.243408] g_ether gadget: g_ether ready
    [ 465.081878] g_ether gadget: high speed config #1: CDC Ethernet (ECM)
    [ 590.146575] pwm: Unknown parameter `50′
    [ 704.158233] Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa086024
    [ 704.172790] Internal error: : 1028 [#1] PREEMPT
    [ 704.180145] last sysfs file: /sys/kernel/uevent_seqnum
    [ 704.188049] Modules linked in: pwm g_ether [last unloaded: pwm]
    [ 704.196899] CPU: 0 Tainted: G W (2.6.32 #3)
    [ 704.205017] PC is at pwm_write+0x128/0x178 [pwm]
    [ 704.212615] LR is at pwm_write+0x10c/0x178 [pwm]
    [ 704.220184] pc : [] lr : [] psr: a0000013
    [ 704.220184] sp : cfb41f48 ip : 48086000 fp : 000a3008
    [ 704.237762] r10: 00000001 r9 : cfb40000 r8 : cfb41f80
    [ 704.246032] r7 : 00000003 r6 : bf01d9f0 r5 : 00000032 r4 : bf01d9f0
    [ 704.255676] r3 : fffffff7 r2 : fa086000 r1 : 00001000 r0 : fa086000
    [ 704.265289] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
    [ 704.275695] Control: 10c5387d Table: 8fb68019 DAC: 00000015
    [ 704.284790] Process sh (pid: 802, stack limit = 0xcfb402f0)
    [ 704.293731] Stack: (0xcfb41f48 to 0xcfb42000)
    [ 704.301452] 1f40: cfb839c0 4001e000 cfb41f80 4001e000 00000003 c00ebf90
    [ 704.316558] 1f60: 00000003 00000007 00000000 00000000 cfb839c0 4001e000 00000003 c00ec13c
    [ 704.331878] 1f80: 00000000 00000000 c003c144 00000000 00000003 4001e000 401bc5d0 00000004
    [ 704.347381] 1fa0: c003c144 c003bfc0 00000003 4001e000 00000001 4001e000 00000003 00000000
    [ 704.363128] 1fc0: 00000003 4001e000 401bc5d0 00000004 00000003 000a33f0 00000001 000a3008
    [ 704.378936] 1fe0: 00000000 bee095f0 400fa028 4014d32c 60000010 00000001 00ffff00 00bfff00
    [ 704.394989] [] (pwm_write+0x128/0x178 [pwm]) from [] (vfs_write+0xac/0x1a0)
    [ 704.411804] [] (vfs_write+0xac/0x1a0) from [] (sys_write+0x40/0x6c)
    [ 704.428344] [] (sys_write+0x40/0x6c) from [] (ret_fast_syscall+0x0/0x2c)
    [ 704.445617] Code: eb51a9b8 ea000006 e5943068 e5823038 (e5923024)
    [ 704.456573] BUG: scheduling while atomic: sh/802/0x00000002
    [ 704.466857] Modules linked in: pwm g_ether [last unloaded: pwm]
    [ 704.477783] [] (unwind_backtrace+0x0/0xdc) from [] (schedule+0x78/0x534)
    [ 704.495483] [] (schedule+0x78/0x534) from [] (schedule_timeout+0x2b8/0x2f8)
    [ 704.513641] [] (schedule_timeout+0x2b8/0x2f8) from [] (wait_for_common+0xf0/0x1a4)
    [ 704.532623] [] (wait_for_common+0xf0/0x1a4) from [] (omap_i2c_xfer+0x1fc/0x30c)
    [ 704.551391] [] (omap_i2c_xfer+0x1fc/0x30c) from [] (i2c_transfer+0x9c/0xf0)
    [ 704.569824] [] (i2c_transfer+0x9c/0xf0) from [] (twl_i2c_read+0xd4/0x128)
    [ 704.588073] [] (twl_i2c_read+0xd4/0x128) from [] (twlreg_grp+0x1c/0x2c)
    [ 704.606170] [] (twlreg_grp+0x1c/0x2c) from [] (twlreg_is_enabled+0x8/0x2c)
    [ 704.624542] [] (twlreg_is_enabled+0x8/0x2c) from [] (_regulator_enable+0x88/0x138)
    [ 704.643676] [] (_regulator_enable+0x88/0x138) from [] (regulator_enable+0x20/0x38)
    [ 704.662780] [] (regulator_enable+0x20/0x38) from [] (dsi_pll_init+0xa0/0x1a4)
    [ 704.681457] [] (dsi_pll_init+0xa0/0x1a4) from [] (dpi_display_resume+0x54/0xec)
    [ 704.700408] [] (dpi_display_resume+0x54/0xec) from [] (omapfb_blank+0x98/0x16c)
    [ 704.719512] [] (omapfb_blank+0x98/0x16c) from [] (fb_blank+0x3c/0x68)
    [ 704.737792] [] (fb_blank+0x3c/0x68) from [] (fbcon_blank+0xe8/0x1f4)
    [ 704.755950] [] (fbcon_blank+0xe8/0x1f4) from [] (do_unblank_screen+0xd4/0x164)
    [ 704.774993] [] (do_unblank_screen+0xd4/0x164) from [] (bust_spinlocks+0x20/0x44)
    [ 704.794250] [] (bust_spinlocks+0x20/0x44) from [] (die+0x1fc/0x2a0)
    [ 704.812286] [] (die+0x1fc/0x2a0) from [] (baddataabort+0x0/0x50)
    [ 704.830078] [] (baddataabort+0x0/0x50) from [] (0x1b6)
    [ 704.847045] BUG: scheduling while atomic: sh/802/0x00000002
    [ 704.857818] Modules linked in: pwm g_ether [last unloaded: pwm]
    [ 704.868957] [] (unwind_backtrace+0x0/0xdc) from [] (schedule+0x78/0x534)
    [ 704.887268] [] (schedule+0x78/0x534) from [] (schedule_timeout+0x2b8/0x2f8)
    [ 704.905822] [] (schedule_timeout+0x2b8/0x2f8) from [] (wait_for_common+0xf0/0x1a4)
    [ 704.925018] [] (wait_for_common+0xf0/0x1a4) from [] (omap_i2c_xfer+0x1fc/0x30c)
    [ 704.943939] [] (omap_i2c_xfer+0x1fc/0x30c) from [] (i2c_transfer+0x9c/0xf0)
    [ 704.962493] [] (i2c_transfer+0x9c/0xf0) from [] (twl_i2c_read+0xd4/0x128)
    [ 704.980865] [] (twl_i2c_read+0xd4/0x128) from [] (twlreg_grp+0x1c/0x2c)
    [ 704.999053] [] (twlreg_grp+0x1c/0x2c) from [] (twlreg_is_enabled+0x8/0x2c)
    [ 705.017517] [] (twlreg_is_enabled+0x8/0x2c) from [] (_regulator_enable+0x88/0x138)
    [ 705.036712] [] (_regulator_enable+0x88/0x138) from [] (regulator_enable+0x20/0x38)
    [ 705.055908] [] (regulator_enable+0x20/0x38) from [] (dsi_pll_init+0xa0/0x1a4)
    [ 705.074645] [] (dsi_pll_init+0xa0/0x1a4) from [] (dpi_display_resume+0x54/0xec)
    [ 705.093627] [] (dpi_display_resume+0x54/0xec) from [] (omapfb_blank+0x98/0x16c)
    [ 705.112762] [] (omapfb_blank+0x98/0x16c) from [] (fb_blank+0x3c/0x68)
    [ 705.131011] [] (fb_blank+0x3c/0x68) from [] (fbcon_blank+0xe8/0x1f4)
    [ 705.149200] [] (fbcon_blank+0xe8/0x1f4) from [] (do_unblank_screen+0xd4/0x164)
    [ 705.168243] [] (do_unblank_screen+0xd4/0x164) from [] (bust_spinlocks+0x20/0x44)
    [ 705.187469] [] (bust_spinlocks+0x20/0x44) from [] (die+0x1fc/0x2a0)
    [ 705.205535] [] (die+0x1fc/0x2a0) from [] (baddataabort+0x0/0x50)
    [ 705.223297] [] (baddataabort+0x0/0x50) from [] (0x1b6)
    [ 705.237426] BUG: scheduling while atomic: sh/802/0x00000002
    [ 705.248168] Modules linked in: pwm g_ether [last unloaded: pwm]
    [ 705.259307] [] (unwind_backtrace+0x0/0xdc) from [] (schedule+0x78/0x534)
    [ 705.277587] [] (schedule+0x78/0x534) from [] (schedule_timeout+0x2b8/0x2f8)
    [ 705.296173] [] (schedule_timeout+0x2b8/0x2f8) from [] (wait_for_common+0xf0/0x1a4)
    [ 705.315338] [] (wait_for_common+0xf0/0x1a4) from [] (omap_i2c_xfer+0x1fc/0x30c)
    [ 705.334289] [] (omap_i2c_xfer+0x1fc/0x30c) from [] (i2c_transfer+0x9c/0xf0)
    [ 705.352844] [] (i2c_transfer+0x9c/0xf0) from [] (twl_i2c_read+0xd4/0x128)
    [ 705.371246] [] (twl_i2c_read+0xd4/0x128) from [] (twlreg_enable+0x20/0x54)
    [ 705.389709] [] (twlreg_enable+0x20/0x54) from [] (_regulator_enable+0xbc/0x138)
    [ 705.408660] [] (_regulator_enable+0xbc/0x138) from [] (regulator_enable+0x20/0x38)
    [ 705.427856] [] (regulator_enable+0x20/0x38) from [] (dsi_pll_init+0xa0/0x1a4)
    [ 705.446624] [] (dsi_pll_init+0xa0/0x1a4) from [] (dpi_display_resume+0x54/0xec)
    [ 705.465576] [] (dpi_display_resume+0x54/0xec) from [] (omapfb_blank+0x98/0x16c)
    [ 705.484588] [] (omapfb_blank+0x98/0x16c) from [] (fb_blank+0x3c/0x68)
    [ 705.502807] [] (fb_blank+0x3c/0x68) from [] (fbcon_blank+0xe8/0x1f4)
    [ 705.520996] [] (fbcon_blank+0xe8/0x1f4) from [] (do_unblank_screen+0xd4/0x164)
    [ 705.540069] [] (do_unblank_screen+0xd4/0x164) from [] (bust_spinlocks+0x20/0x44)
    [ 705.559295] [] (bust_spinlocks+0x20/0x44) from [] (die+0x1fc/0x2a0)
    [ 705.577392] [] (die+0x1fc/0x2a0) from [] (baddataabort+0x0/0x50)
    [ 705.595184] [] (baddataabort+0x0/0x50) from [] (0x1b6)
    [ 705.609191] BUG: scheduling while atomic: sh/802/0x00000002
    [ 705.619934] Modules linked in: pwm g_ether [last unloaded: pwm]
    [ 705.631011] [] (unwind_backtrace+0x0/0xdc) from [] (schedule+0x78/0x534)
    [ 705.649291] [] (schedule+0x78/0x534) from [] (schedule_timeout+0x2b8/0x2f8)
    [ 705.667877] [] (schedule_timeout+0x2b8/0x2f8) from [] (wait_for_common+0xf0/0x1a4)
    [ 705.687072] [] (wait_for_common+0xf0/0x1a4) from [] (omap_i2c_xfer+0x1fc/0x30c)
    [ 705.705993] [] (omap_i2c_xfer+0x1fc/0x30c) from [] (i2c_transfer+0x9c/0xf0)
    [ 705.724548] [] (i2c_transfer+0x9c/0xf0) from [] (twl_i2c_write+0xbc/0x110)
    [ 705.743041] [] (twl_i2c_write+0xbc/0x110) from [] (twl_i2c_write_u8+0x20/0x28)
    [ 705.761871] [] (twl_i2c_write_u8+0x20/0x28) from [] (twlreg_enable+0x4c/0x54)
    [ 705.780609] [] (twlreg_enable+0x4c/0x54) from [] (_regulator_enable+0xbc/0x138)
    [ 705.799530] [] (_regulator_enable+0xbc/0x138) from [] (regulator_enable+0x20/0x38)
    [ 705.818756] [] (regulator_enable+0x20/0x38) from [] (dsi_pll_init+0xa0/0x1a4)
    [ 705.837493] [] (dsi_pll_init+0xa0/0x1a4) from [] (dpi_display_resume+0x54/0xec)
    [ 705.856506] [] (dpi_display_resume+0x54/0xec) from [] (omapfb_blank+0x98/0x16c)
    [ 705.875640] [] (omapfb_blank+0x98/0x16c) from [] (fb_blank+0x3c/0x68)
    [ 705.893890] [] (fb_blank+0x3c/0x68) from [] (fbcon_blank+0xe8/0x1f4)
    [ 705.912048] [] (fbcon_blank+0xe8/0x1f4) from [] (do_unblank_screen+0xd4/0x164)
    [ 705.931121] [] (do_unblank_screen+0xd4/0x164) from [] (bust_spinlocks+0x20/0x44)
    [ 705.950347] [] (bust_spinlocks+0x20/0x44) from [] (die+0x1fc/0x2a0)
    [ 705.968414] [] (die+0x1fc/0x2a0) from [] (baddataabort+0x0/0x50)
    [ 705.986206] [] (baddataabort+0x0/0x50) from [] (0x1b6)
    [ 706.008331] —[ end trace a50eb8876048cc83 ]—

    thanks!