title: Calling spi_write periodically in a linux driver
body: <p>I am writing a driver for an LCD display. According to the application note, I need to write a dummy SPI write to the command periodically to maximize its contrast. To accomplish this, I set up a timer and attempt to write the contrast-maximizing 2-byte dummy command from the timer handler.</p>
  
  <p>However, something goes wrong because the spi_write function causes a complete kernel crash with the following error:</p>
  
  <pre><code>BUG: scheduling while atomic: swapper/1/0/0x00000102
  </code></pre>
  
  <p>Based on the following post:
  <a href="https://stackoverflow.com/questions/3537252/how-to-solve-bug-scheduling-while-atomic-swapper-0x00000103-0-cpu0-in-ts">How to solve &quot;BUG: scheduling while atomic: swapper /0x00000103/0, CPU#0&quot;? in TSC2007 Driver?</a></p>
  
  <blockquote>
    <p>"Scheduling while atomic" indicates that you've tried to sleep
    somewhere that you shouldn't - like within a spinlock-protected
    critical section or an interrupt handler.</p>
  </blockquote>
  
  <p>Maybe the call to spi_write triggers some sort of sleep behavior. It would make sense to disallow sleeping here, because based on the stack trace, I see that the code is in a soft IRQ state:</p>
  
  <pre><code>[&lt;404ec600&gt;] (schedule_timeout) from [&lt;404eac3c&gt;] (wait_for_common+0x114/0x15c)
  [&lt;404eac3c&gt;] (wait_for_common) from [&lt;4031c7a4&gt;] (spi_sync+0x70/0x88)
  [&lt;4031c7a4&gt;] (spi_sync) from [&lt;3f08a6b0&gt;] (plt_lcd_send_toggle_comin_cmd+0x7c/0x84 [plt_lcd_spi])
  [&lt;3f08a6b0&gt;] (plt_lcd_send_toggle_comin_cmd [plt_lcd_spi]) from [&lt;3f08a6c4&gt;] (plt_lcd_timer_handler+0xc/0x2c [plt_lcd_spi])
  [&lt;3f08a6c4&gt;] (plt_lcd_timer_handler [plt_lcd_spi]) from [&lt;40058818&gt;] (call_timer_fn.isra.26+0x20/0x30)
  [&lt;40058818&gt;] (call_timer_fn.isra.26) from [&lt;40058f30&gt;] (run_timer_softirq+0x1ec/0x21c)
  [&lt;40058f30&gt;] (run_timer_softirq) from [&lt;40023414&gt;] (__do_softirq+0xe0/0x1c8)
  [&lt;40023414&gt;] (__do_softirq) from [&lt;400236f0&gt;] (irq_exit+0x58/0xac)
  [&lt;400236f0&gt;] (irq_exit) from [&lt;4004ee4c&gt;] (__handle_domain_irq+0x80/0xa0)
  [&lt;4004ee4c&gt;] (__handle_domain_irq) from [&lt;400085ac&gt;] (gic_handle_irq+0x38/0x5c)
  [&lt;400085ac&gt;] (gic_handle_irq) from [&lt;40011740&gt;] (__irq_svc+0x40/0x74)
  </code></pre>
  
  <p><strong>My question is: what is the right way to implement such periodic behavior, where an SPI transaction needs to occur periodically?</strong></p>
  
  <p>The following is a summary of the timer handler (albeit with some manual modifications to make the names more generic -- I might have inserted some typos in the process)</p>
  
  <pre><code>static void lcd_timer_handler(unsigned long data)
  {
      // priv is a private structure that contains private info for the 
      // driver: timer structure, timer timeout, context for the dummy command
      lcd_priv * const priv = (memlcd_priv *) data;
  
      unsigned char dummy[2];
      dummy[0] = get_dummy_command_code(priv);
      dummy[1] = 0; // command must be terminated by a 0.
  
      // This is the call that causes the failure.
      // priv-&gt;spi is a struct spi_device *
      spi_write(priv-&gt;spi, ((const void *) dummy), 2);
  
      // Re-arm the timer
      mod_timer(&amp;priv-&gt;timer, jiffies + priv-&gt;timer_timeout);
  }
  </code></pre>
  
  <p>Thanks!</p>
  
  <p>EDIT: Here is what I came up with after implementing the recommendations from the answer below. Works nicely, but using delayed_work involved having to jump through a few hoops.</p>
  
  <pre><code>typedef struct lcd_priv {
      /* private stuff: */
      /* ... */
  
      /* workqueue stuff: */
      struct workqueue_struct * wq;
      struct delayed_work periodic_work;
  } lcd_priv;
  
  
  void lcd_periodic_work(struct work_struct * work_struct_ptr)
  {
      /*
       * Old documentation refers to a "data" pointer, but the API
       * no longer supports it. The developer is invited to put the work_struct
       * inside what would have been pointed to by "data" and to use container_of()
       * to recover this master struct.
       * See http://lwn.net/Articles/211279/ for more info.
      */
  
      struct delayed_work * delayed = container_of(work_struct_ptr, struct delayed_work, work);
      lcd_priv * priv = container_of(delayed, lcd_priv, periodic_work);
  
      /* (prepare spi buffer in priv-&gt;spi_buf) */
      /* ... */
  
      /* This could be any activity that goes to sleep: */
      spi_write(priv-&gt;spi, ((const void *) &amp;priv-&gt;spi_buf[0]), 2);
  
      queue_delayed_work(priv-&gt;wq, &amp;priv-&gt;periodic_work, TOGGLE_FREQUENCY);
  }
  
  static void lcd_start_workqueue(lcd_priv * const priv) {
      priv-&gt;wq = create_singlethread_workqueue("lcd_periodic_st_wq");
  
      INIT_DELAYED_WORK(&amp;priv-&gt;periodic_work, lcd_periodic_work);
      queue_delayed_work(priv-&gt;wq, &amp;priv-&gt;periodic_work, TOGGLE_FREQUENCY);
  }
  
  static void lcd_stop_workqueue(lcd_priv * const priv) {
      destroy_workqueue(priv-&gt;wq);
  }
  </code></pre>