Share Pastebin
Guest
Public paste!

Untitled

By: a guest | Sep 2nd, 2010 | Syntax: None | Size: 28.18 KB | Hits: 29 | Expires: Never
Copy text to clipboard
  1. /*
  2.     microp-klt.c - i2c chip driver for microp-led
  3.  
  4.     Joe Hansche <madcoder@gmail.com>
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; version 2 of the License.
  9. */
  10.  
  11. #include <linux/module.h>
  12. #include <linux/init.h>
  13. #include <linux/slab.h>
  14. #include <linux/i2c.h>
  15. #include <linux/leds.h>
  16. #include <linux/delay.h>
  17. #include <linux/mutex.h>
  18. #include <asm/io.h>
  19. #include <asm/gpio.h>
  20. #include <mach/vreg.h>
  21. #include <mach/msm_iomap.h>
  22. #include <linux/err.h>
  23. #include <linux/debugfs.h>
  24. #include <asm/uaccess.h>
  25. #include <linux/unistd.h>
  26. #include <linux/earlysuspend.h>
  27.  
  28. #include <linux/bma150.h>
  29. #include <linux/microp-klt.h>
  30.  
  31. #include <asm/mach-types.h>
  32. #include "../../../arch/arm/mach-msm/proc_comm_wince.h"
  33.  
  34. int micropklt_set_lcd_state(int on);
  35.  
  36. #define MODULE_NAME "microp-klt"
  37.  
  38. #define I2C_READ_RETRY_TIMES 10
  39. #define I2C_WRITE_RETRY_TIMES 10
  40.  
  41. #if 0
  42.  #define D(fmt, arg...) printk(KERN_DEBUG "[KLT] %s: " fmt "\n", __FUNCTION__, ## arg);
  43. #else
  44.  #define D(fmt, arg...) do {} while(0)
  45. #endif
  46. #define GP_NS_REG (0x005c)
  47.  
  48. static int micropklt_read(struct i2c_client *, uint8_t, uint8_t *, int);
  49. static int micropklt_write(struct i2c_client *, uint8_t *, int);
  50. static unsigned int color_led_address;
  51. static unsigned int auto_bl;
  52.  
  53. extern int bma150_probe(struct microp_klt*);
  54.  
  55. static void micropklt_led_brightness_set(struct led_classdev *led_cdev,
  56.                                          enum led_brightness brightness)
  57. {
  58.         struct microp_klt *data;
  59.         struct i2c_client *client;
  60.         uint8_t buffer[4] = { 0, 0, 0, 0 };
  61.         int idx, b, state;
  62.  
  63.         if ( !strcmp(led_cdev->name, "klt::home") )
  64.                 idx = 0;
  65.         else if ( !strcmp(led_cdev->name, "klt::back") )
  66.                 idx = 1;
  67.         else if ( !strcmp(led_cdev->name, "klt::end") )
  68.                 idx = 2;
  69.         else if ( !strcmp(led_cdev->name, "klt::send") )
  70.                 idx = 3;
  71.         else if ( !strcmp(led_cdev->name, "klt::action") )
  72.                 idx = 4;
  73.         else if ( !strcmp(led_cdev->name, "klt::lcd-bkl") || !strcmp(led_cdev->name, "lcd-backlight"))
  74.                 idx = 5;
  75.         else if ( !strcmp(led_cdev->name, "klt::keypad-bkl") || !strcmp(led_cdev->name, "button-backlight"))
  76.                 idx = 6;
  77.         else
  78.                 return;
  79.  
  80.         data = container_of(led_cdev, struct microp_klt, leds[idx]);
  81.         client = data->client;
  82.  
  83.         mutex_lock(&data->lock);
  84.  
  85.         state = data->led_states;
  86.  
  87.         // idx 5 and 6 are bits 13 and 14
  88.         if ( idx > 4 )
  89.                 idx += 8;
  90.  
  91.         b = 1U << idx;
  92.  
  93.         if ( brightness == LED_OFF )
  94.                 state &= ~b;
  95.         else
  96.                 state |= b;
  97.  
  98.         if (idx == 6+8) //button-backlight
  99.         {
  100.                 if (machine_is_htckovsky())
  101.                 {
  102.                         buffer[0]=MICROP_KLT_ID_KEYPAD_BRIGHTNESS_KOVS;
  103.                         if (brightness)
  104.                         {
  105.                                 buffer[1]=0x80;
  106.                                 buffer[2]=brightness/4;
  107.                         }
  108.  
  109.                         printk(KERN_INFO MODULE_NAME ": Setting %s brightness to %d\n", led_cdev->name, buffer[2]);
  110.                         micropklt_write(client, buffer, 3);
  111.                 }
  112.         }
  113.  
  114.         // lcd-backlight lets us do varied brightness
  115.         if ( idx==5+8 /*&& brightness>0*/) {
  116.                 //microp version ?
  117.                 if(machine_is_htcrhodium()) {
  118.                         buffer[0] = MICROP_KLT_ID_LCD_BRIGHTNESS2;
  119.                         //Scale from 0 to 9
  120.                         buffer[1] = (brightness*9)/255;
  121.  
  122.                         printk(KERN_INFO MODULE_NAME ": Setting %s brightness2 to: %d/10\n",
  123.                                 led_cdev->name, buffer[1]);
  124.                         micropklt_write(client, buffer, 2);
  125.                         //msleep(1);
  126.                 } else if (machine_is_htckovsky()) {
  127.                         buffer[0] = MICROP_KLT_ID_LCD_BRIGHTNESS_KOVS;
  128.                         if (brightness == 0) {
  129.                                 buffer[1] = LED_OFF;
  130.                                 printk(KERN_INFO MODULE_NAME ": brightness==0, turn %s OFF\n", led_cdev->name);
  131.                         } else {
  132.                                 buffer[1] = LED_FULL; // at least 0x80 is needed
  133.                                 printk(KERN_INFO MODULE_NAME ": Setting %s brightness to: 0x%02x\n",
  134.                                 led_cdev->name, brightness);
  135.                         }
  136.                         buffer[2] = brightness;
  137.                         micropklt_write(client, buffer, 3);
  138.                 } else {
  139.                         buffer[0] = MICROP_KLT_ID_LCD_BRIGHTNESS;
  140.                         buffer[1] = brightness/2 & 0xf0;
  141.  
  142.                         printk(KERN_INFO MODULE_NAME ": Setting %s brightness to: 0x%02x\n",
  143.                                 led_cdev->name, buffer[1]);
  144.                         micropklt_write(client, buffer, 2);
  145.                 }
  146.         }
  147.  
  148.         if ( data->led_states != state ) {
  149.                 buffer[0] = MICROP_KLT_ID_LED_STATE;
  150.                 buffer[1] = 0xff & state;
  151.                 buffer[2] = 0xff & (state >> 8);
  152.                 data->led_states = state;
  153.                 micropklt_write(client, buffer, 3);
  154.         }
  155.  
  156.         mutex_unlock(&data->lock);
  157. }
  158.  
  159. /**
  160.  * set_misc_states
  161.  * function to set the micropklt misc register.
  162.  * note: experimental and not used yet.
  163.  * note: its used for enabling the LCM clock ( pure guess ) on the HTC RAPH
  164.  * note: can be used to cleanup the "send_command" hacks in micropklt_lcd_ctrl.
  165.  *
  166.  * example:
  167.  * - micropklt_set_misc_states(0xFF, 4) would set bit 3.
  168.  * - micropklt_set_misc_states(0x0, 4) would clear bit 3.
  169.  */
  170. int micropklt_set_misc_states( unsigned mask, unsigned bit_flag )
  171. {
  172.         struct microp_klt *data;
  173.         struct i2c_client *client;
  174.         unsigned state;
  175.         int result;
  176.         uint8_t buffer[2] = { MICROP_I2C_WCMD_MISC, 0x00 };
  177.  
  178.         data = micropklt_t;
  179.         if ( !data ) return -EAGAIN;
  180.         client = data->client;
  181.         state = data->misc_states;
  182.  
  183.         mutex_lock(&data->lock);
  184.  
  185.         if ( bit_flag &  MISC_MICP_ISP) {
  186.                 printk( "micropklt, MISC_MICP_ISP bit should NOT be enabled, removing bit!\n" );
  187.                 bit_flag = bit_flag & ~MISC_MICP_ISP;
  188.         }
  189.  
  190.         if ( bit_flag & MISC_CAP_SEN_RES_CTRL1 && bit_flag & MISC_CAP_SEN_RES_CTRL2 ) {
  191.                 // its evil to have them both enabled... its one or the other...
  192.                 printk( "microp, MISC_CAP_SEN_RES_CTRL1, MISC_CAP_SEN_RES_CTRL2 are both enabled\n" );
  193.  
  194.                 // log the cmd that set this for debug purposes.
  195.                 D( "microp, pre bit_flag: 0x%X\n", bit_flag );
  196.                 bit_flag = bit_flag & ~( MISC_CAP_SEN_RES_CTRL1 | MISC_CAP_SEN_RES_CTRL2 );
  197.                 D( "microp, post bit_flag: 0x%X\n", bit_flag );
  198.         }
  199.  
  200.         data->misc_states = data->misc_states & ~bit_flag;                                      // remove the bit
  201.         data->misc_states = data->misc_states | ( bit_flag & mask );            // set or not set the bit
  202.  
  203.         // only send if it has actualy changed
  204.         if ( data->misc_states != state ) {
  205.                 state = data->misc_states;
  206.                 buffer[1] = data->misc_states & 0xFF;
  207.                 result = micropklt_write(client, buffer, 2);
  208.                 D("microp, 0x%X -> 0x%X\n", state, data->misc_states);
  209.                
  210.         } else {
  211.                 result = 0;
  212.         }
  213.  
  214.         // don't store the reset flags
  215.         if( data->misc_states & ( MISC_CAP_SEN_RES_CTRL2 | MISC_CAP_SEN_RES_CTRL1 ) )
  216.                 data->misc_states = data->misc_states & ~( MISC_CAP_SEN_RES_CTRL2 | MISC_CAP_SEN_RES_CTRL1 );
  217.        
  218.         mutex_unlock(&data->lock);
  219.         return result;
  220. }
  221.  
  222. int micropklt_set_led_states(unsigned leds_mask, unsigned leds_values)
  223. {
  224.         struct microp_klt *data;
  225.         struct i2c_client *client;
  226.         unsigned state;
  227.         uint8_t buffer[4] = { 0, 0, 0, 0 };
  228.         int r;
  229.  
  230.         data = micropklt_t;
  231.         if (!data) return -EAGAIN;
  232.         client = data->client;
  233.  
  234.         mutex_lock(&data->lock);
  235.         state = data->led_states | (leds_mask & leds_values);
  236.         state &= MICROP_KLT_ALL_LEDS & ~(leds_mask & ~leds_values);
  237.         if (data->led_states != state) {
  238.                 data->led_states = state;
  239.                 buffer[0] = MICROP_KLT_ID_LED_STATE;
  240.                 buffer[1] = 0xff & state;
  241.                 buffer[2] = 0xff & (state >> 8);
  242.                 data->led_states = state;
  243.                 r = micropklt_write(client, buffer, 3);
  244.         } else {
  245.                 r = 0;
  246.         }
  247.         mutex_unlock(&data->lock);
  248.         return r;
  249. }
  250. EXPORT_SYMBOL(micropklt_set_led_states);
  251.  
  252. int micropklt_set_color_led_state(int state)
  253. {
  254.         struct microp_klt *data;
  255.         struct i2c_client *client;
  256.         uint8_t buffer[5] = { 0, 0, 0, 0, 0 };
  257.         int r;
  258.  
  259.         data = micropklt_t;
  260.         if (!data) return -EAGAIN;
  261.         client = data->client;
  262.  
  263.         mutex_lock(&data->lock);
  264.                 buffer[0] = color_led_address;
  265.                 buffer[1] = 0;
  266.                 buffer[2] = state;
  267.                 buffer[3] = 0xff;
  268.                 buffer[4] = 0xff;
  269.         r = micropklt_write(client, buffer, 5);
  270.         mutex_unlock(&data->lock);
  271.         return 0;
  272. }
  273.  
  274. int micropklt_set_lcd_state(int on)
  275. {
  276.         return micropklt_set_led_states(1 << MICROP_KLT_BKL_LCD,on ? 1 << MICROP_KLT_BKL_LCD : 0);
  277. }
  278. EXPORT_SYMBOL(micropklt_set_lcd_state);
  279.  
  280. int micropklt_set_kbd_state(int on)
  281. {
  282.         return micropklt_set_led_states(1 << MICROP_KLT_BKL_KBD,on ? 1 << MICROP_KLT_BKL_KBD : 0);
  283. }
  284. EXPORT_SYMBOL(micropklt_set_kbd_state);
  285.  
  286. #define send_command(x) micropklt_write(client, x,ARRAY_SIZE(x));
  287.  
  288. void micropklt_lcd_ctrl(int v)
  289. {
  290.         struct microp_klt *data;
  291.         struct i2c_client *client;
  292.  
  293.         // for power up
  294.         uint8_t c1[]={MICROP_I2C_WCMD_MISC,0x48};
  295.         uint8_t c2[]={MICROP_I2C_WCMD_MISC,0x0c};
  296.         uint8_t c3[]={MICROP_I2C_WCMD_AUTO_BL_CTL,0,0};
  297.  
  298.         // for power down
  299.         uint8_t c7[]={MICROP_I2C_WCMD_MISC,0x4c};
  300.         uint8_t c8[]={MICROP_KLT_ID_LED_STATE,0x10,0x00};
  301.         uint8_t c9[]={MICROP_I2C_WCMD_MISC,0x08};
  302.         printk("Something used micropklt_lcd_ctrl. This function should no longer be used.\n");
  303.  
  304.         // this function is obsolete
  305.         return;
  306.  
  307.     data = micropklt_t;
  308.     if (!data) return;
  309.     client = data->client;
  310.  
  311.         mutex_lock(&data->lock);
  312.  
  313.         switch(v) {
  314.         case 1: // power up
  315.                 send_command(c1);
  316.                 break;
  317.         case 2:
  318.                 send_command(c2);
  319.  
  320.                 break;
  321.         case 3:
  322.                 send_command(c3);
  323.                 break;
  324.         case 4: // power down
  325.                 send_command(c7);
  326.                 send_command(c3);
  327.                 send_command(c8);
  328.                 send_command(c3);
  329.                 break;
  330.         case 5:
  331.                 send_command(c9);
  332.                 break;
  333.         }
  334.  
  335.         mutex_unlock(&data->lock);
  336. }
  337.  
  338. EXPORT_SYMBOL(micropklt_lcd_ctrl);
  339.  
  340. void micropklt_lcd_precess_spi_table(uint16_t spicmd, struct microp_spi_table *spi_table, size_t count)
  341. {
  342.         int i;
  343.         struct microp_klt *data;
  344.         uint16_t delay;
  345.         uint8_t c0[4];
  346.  
  347.         data = micropklt_t;
  348.         if (!data) return;
  349.  
  350.  
  351.         mutex_lock(&data->lock);
  352.  
  353.         for(i = 0; i < count; i++) {
  354.                 delay = spi_table[i].delay;
  355.                 c0[0] = spicmd; c0[1] = spi_table[i].value1; c0[2] = spi_table[i].value2; c0[3] = spi_table[i].value3;
  356.                 micropklt_write(data->client, c0, ARRAY_SIZE(c0));
  357.                 udelay(50);
  358.                 if(delay)
  359.                         msleep(delay);
  360.         }
  361.  
  362.         mutex_unlock(&data->lock);
  363. }
  364.  
  365. void micropklt_lcd_precess_cmd(char* cmd, size_t count)
  366. {
  367.         struct microp_klt *data;
  368.         data = micropklt_t;
  369.         if (!data) return;
  370.  
  371.         msleep(1);
  372.  
  373.         mutex_lock(&data->lock);
  374.         micropklt_write(data->client, cmd, count);
  375.         mutex_unlock(&data->lock);
  376.         udelay(50);
  377. }
  378.  
  379. #ifdef CONFIG_HAS_EARLYSUSPEND
  380. void micropklt_early_suspend(struct early_suspend *h)
  381. {
  382.         if(machine_is_htctopaz())
  383.                 micropklt_set_led_states(0x1, 0x0);
  384. }
  385.  
  386. void micropklt_early_resume(struct early_suspend *h)
  387. {
  388.         if(machine_is_htctopaz())
  389.                 micropklt_set_led_states(0x1, 0x1);
  390. }
  391. #endif
  392.  
  393. static int micropklt_remove(struct i2c_client *client)
  394. {
  395.         struct microp_klt *data;
  396.         int i;
  397.  
  398.         data = i2c_get_clientdata(client);
  399.  
  400.         micropklt_set_led_states(MICROP_KLT_ALL_LEDS, MICROP_KLT_DEFAULT_LED_STATES);
  401.  
  402.         for (i=0; i<ARRAY_SIZE(data->leds); i++) {
  403.                 led_classdev_unregister(&data->leds[i]);
  404.         }
  405. #ifdef CONFIG_HAS_EARLYSUSPEND
  406.         if (data->enable_early_suspend) {
  407.                 unregister_early_suspend(&data->early_suspend);
  408.         }
  409. #endif
  410.  
  411.         kfree(data);
  412.         micropklt_t = NULL;
  413.         return 0;
  414. }
  415.  
  416. void init_mic()
  417. {
  418.  
  419.         struct microp_klt *data;
  420.         struct i2c_client *client;
  421.         uint8_t buffer[5] = { 0, 0, 0, 0, 0 };
  422.  
  423.         data = micropklt_t;
  424.         if (!data) return;
  425.         client = data->client;
  426.  
  427.         printk(KERN_INFO MODULE_NAME ": Sending mic init\n");
  428.  
  429.         uint8_t buf[5];
  430.         buf[0] = 0x50;
  431.         buf[1] = 0;
  432.         buf[2] = 0;
  433.         buf[3] = 0;
  434.         buf[4] = 0;
  435.         micropklt_write(client, buf, 5);
  436.  
  437.         buf[1] = 0x2;
  438.         buf[3] = 0xff;
  439.         buf[4] = 0xff;
  440.         micropklt_write(client, buf, 5);
  441.  
  442.         buf[0] = 0x25;
  443.         buf[1] = 0x04;
  444.         micropklt_write(client, buf, 2);
  445.  
  446.         buf[1] = 0x14;
  447.         micropklt_write(client, buf, 2);
  448.  
  449.         buf[1] = 0x04;
  450.         micropklt_write(client, buf, 2);
  451. /*
  452.         buf[0] = 0x25;
  453.         buf[1] = 0x40;
  454.         micropklt_write(client, buf, 2);
  455.  
  456.         buf[1] = 0x44;
  457.         micropklt_write(client, buf, 2);*/
  458. }
  459.  
  460. EXPORT_SYMBOL(init_mic);
  461.  
  462.  
  463. void init_mic_post_adc()
  464. {
  465.  
  466.         struct microp_klt *data;
  467.         struct i2c_client *client;
  468.         uint8_t buffer[5] = { 0, 0, 0, 0, 0 };
  469.  
  470.         data = micropklt_t;
  471.         if (!data) return;
  472.         client = data->client;
  473.  
  474.         printk(KERN_INFO MODULE_NAME ": Sending mic init\n");
  475.  
  476.         uint8_t buf[5];
  477.  
  478.         buf[0] = 0x25;
  479.         buf[1] = 0x40;
  480. //      micropklt_write(client, buf, 2);
  481. }
  482.  
  483. EXPORT_SYMBOL(init_mic_post_adc);
  484.  
  485. static int micropklt_probe(struct i2c_client *client, const struct i2c_device_id *id)
  486. {
  487.         struct microp_klt *data;
  488.         int supported, r, i;
  489.         uint8_t buf[3] = { 0, 0, 0 };
  490.         int id_version;
  491.  
  492.         auto_bl = 0;
  493.  
  494.         printk(KERN_INFO MODULE_NAME ": Initializing MicroP-LED chip driver at "
  495.                "addr: 0x%02x\n", client->addr);
  496.  
  497.  
  498.         if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
  499.                 printk(KERN_ERR MODULE_NAME ": i2c bus not supported\n");
  500.                 return -EINVAL;
  501.         }
  502.  
  503.         data = kzalloc(sizeof *data, GFP_KERNEL);
  504.         if (data < 0) {
  505.                 printk(KERN_ERR MODULE_NAME ": Not enough memory\n");
  506.                 return -ENOMEM;
  507.         }
  508.  
  509.         // maybe seperate the read and write mutex.
  510.         mutex_init(&data->lock);
  511.         mutex_lock(&data->lock);
  512.  
  513.         data->client = client;
  514.         i2c_set_clientdata(client, data);
  515.         data->enable_early_suspend=1;
  516.         micropklt_t = data;
  517.  
  518.         // Read version
  519.         if (machine_is_htckovsky()) {
  520.                 id_version = MICROP_KLT_ID_VERSION_KOVS;
  521.         } else {
  522.                 id_version = MICROP_KLT_ID_VERSION;
  523.         }
  524.         if( micropklt_read(client, id_version, buf, 2) < 0 ) {
  525.                 printk( KERN_ERR MODULE_NAME" : unable to read microp firmware version\n" );
  526.                 r = -EIO;
  527.                 goto fail;
  528.         }
  529.  
  530.         /* Check version against what we think we should support
  531.          * Known supported versions:
  532.          *   0105, 0205, 0a05, 0b05, 0d02
  533.          *   8182, 8185
  534.          *   0c82, 0c85
  535.          *   060d
  536.          *   kovsky:
  537.          *   0787
  538.          */
  539.         supported = 0;
  540.         data->version = (buf[0] << 8) | buf[1];
  541.         switch (buf[0]) {
  542.         case 0x01:
  543.         case 0x02:
  544.         case 0x0a:
  545.         case 0x0b:
  546.                 switch (buf[1]) {
  547.                 case 0x0e: /* topa100 */
  548.                         bma150_probe(data);
  549.                 case 0x88: /* rhod210 */
  550.                 case 0x01:
  551.                 case 0x05:
  552.                 case 0x81: /* diam500 */
  553.                         supported = 1;
  554.                         break;
  555.                 }
  556.                 break;
  557.         case 0x0d:
  558.                 switch (buf[1]) {
  559.                 case 0x02:
  560.                         supported = 1;
  561.                         break;
  562.                 case 0x0a: /* raph300 */
  563.                         supported = 1;
  564.                         break;
  565.                 }
  566.                 break;
  567.         case 0x81:
  568.         case 0x0c:
  569.                 switch (buf[1]) {
  570.                 case 0x82:
  571.                 case 0x85:
  572.                         supported = 1;
  573.                         break;
  574.                 }
  575.                 break;
  576.         case 0x06:
  577.                 switch (buf[1]) {
  578.                 case 0x0d:
  579.                         supported = 1;
  580.                         break;
  581.                 }
  582.                 break;
  583.         case 0x07:
  584.                 switch (buf[1]) {
  585.                 case 0x87:
  586.                         supported = 1;
  587.                         break;
  588.                 }
  589.                 break;
  590.         }
  591.  
  592.         // microp misc state init value.
  593.         data->misc_states = 0x0C;
  594.  
  595.         /* if for some reason the hardware should support it, but it simply shows the wrong I2C id, its possible the device has been
  596.          * set into bootloader mode. See HTC Hero's microp driver for a way to fix this.
  597.          */
  598.         if (!supported) {
  599.                 printk(KERN_WARNING MODULE_NAME ": This hardware is not yet supported: %04x\n", data->version);
  600.                 r = -ENOTSUPP;
  601.                 goto fail;
  602.         }
  603.  
  604.         data->led_states = MICROP_KLT_DEFAULT_LED_STATES;
  605.  
  606.         data->leds[0].name = "klt::home";
  607.         data->leds[0].brightness = LED_OFF;
  608.         data->leds[0].brightness_set = micropklt_led_brightness_set;
  609.  
  610.         data->leds[1].name = "klt::back";
  611.         data->leds[1].brightness = LED_OFF;
  612.         data->leds[1].brightness_set = micropklt_led_brightness_set;
  613.  
  614.         data->leds[2].name = "klt::end";
  615.         data->leds[2].brightness = LED_OFF;
  616.         data->leds[2].brightness_set = micropklt_led_brightness_set;
  617.  
  618.         data->leds[3].name = "klt::send";
  619.         data->leds[3].brightness = LED_OFF;
  620.         data->leds[3].brightness_set = micropklt_led_brightness_set;
  621.  
  622.         data->leds[4].name = "klt::action";
  623.         data->leds[4].brightness = LED_OFF;
  624.         data->leds[4].brightness_set = micropklt_led_brightness_set;
  625.  
  626.         data->leds[5].name = "klt::lcd-bkl";
  627.         data->leds[5].brightness = 0x90;
  628.         data->leds[5].brightness_set = micropklt_led_brightness_set;
  629.  
  630.         data->leds[6].name = "klt::keypad-bkl";
  631.         data->leds[6].brightness = LED_OFF;
  632.         data->leds[6].brightness_set = micropklt_led_brightness_set;
  633.  
  634. #ifdef CONFIG_ANDROID_PMEM
  635.         data->leds[5].name = "lcd-backlight";
  636.         data->leds[6].name = "button-backlight";
  637. #endif
  638.  
  639.         for (i=0; i<ARRAY_SIZE(data->leds); i++) {
  640.                 r = led_classdev_register(&client->dev, &data->leds[i]);
  641.                 if (r < 0) {
  642.                         goto err_led_classdev_register_failed;
  643.                         break;
  644.                 }
  645.         }
  646.  
  647.         if(machine_is_htctopaz())
  648.                 color_led_address = 0x51;
  649.         else if (machine_is_htcrhodium())
  650.                 color_led_address = 0x50;
  651.         else if (machine_is_htckovsky())
  652.                 color_led_address = 0x20;
  653.         else
  654.                 color_led_address = 0x0;
  655.  
  656.         mutex_unlock(&data->lock);
  657.  
  658.         // Set default LED state
  659.         micropklt_set_led_states(MICROP_KLT_ALL_LEDS, MICROP_KLT_DEFAULT_LED_STATES);
  660.  
  661.         if(machine_is_htctopaz())       // Enable keypadled with device
  662.                 micropklt_set_led_states(0x1, 0x1);
  663.  
  664.         #ifdef CONFIG_HAS_EARLYSUSPEND
  665.         if (data->enable_early_suspend) {
  666.                 data->early_suspend.level =
  667.                                 EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
  668.                 data->early_suspend.suspend = micropklt_early_suspend;
  669.                 data->early_suspend.resume = micropklt_early_resume;
  670.                 register_early_suspend(&data->early_suspend);
  671.         }
  672.         #endif
  673.  
  674.         if (machine_is_htcrhodium())
  675.         {
  676.                 //init dual mic
  677.                 //init_mic(client);
  678.         }
  679.  
  680.         printk(KERN_INFO MODULE_NAME ": Initialized MicroP-LED chip revision v%04x\n", data->version);
  681.  
  682.         return 0;
  683.  
  684. err_led_classdev_register_failed:
  685.         printk(KERN_ERR MODULE_NAME ": led_classdev_register(%d) failed: %d\n", i, r);
  686.         for (i=i; i>=0; i--) {
  687.                 led_classdev_unregister(&data->leds[i]);
  688.         }
  689. fail:
  690.         mutex_unlock(&data->lock);
  691.         kfree(data);
  692.         micropklt_t = 0;
  693.         return r;
  694. }
  695.  
  696. static int micropklt_write(struct i2c_client *client, uint8_t *sendbuf, int len)
  697. {
  698.         int rc;
  699.         int retry;
  700.  
  701.         struct i2c_msg msg[] = {
  702.                 {
  703.                         .addr = client->addr,
  704.                         .flags = 0,
  705.                         .len = len,
  706.                         .buf = sendbuf,
  707.                 },
  708.         };
  709.  
  710.         for (retry = 0; retry <= I2C_WRITE_RETRY_TIMES; retry++) {
  711.                 rc = i2c_transfer(client->adapter, msg, 1);
  712.                 if (rc == 1)
  713.                         return 0;
  714.                 msleep(10);
  715.                 printk(KERN_WARNING "micropklt, i2c write retry\n");
  716.         }
  717.         printk(KERN_ERR "micropklt_write, i2c_write_block retry over %d\n",
  718.                         I2C_WRITE_RETRY_TIMES);
  719.         return rc;
  720. }
  721.  
  722. static int micropklt_read(struct i2c_client *client, uint8_t id, uint8_t *buf, int len)
  723. {
  724.         int retry;
  725.         int rc;
  726.         struct i2c_msg msgs[] = {
  727.                 {
  728.                         .addr = client->addr,
  729.                         .flags = 0,
  730.                         .len = 1,
  731.                         .buf = &id,
  732.                 },
  733.                 {
  734.                         .addr = client->addr,
  735.                         .flags = I2C_M_RD,
  736.                         .len = len,
  737.                         .buf = buf,
  738.                 }
  739.         };
  740.         for (retry= 0; retry <= I2C_READ_RETRY_TIMES; retry++) {
  741.                 rc = i2c_transfer(client->adapter, msgs, 2);
  742.                 if (rc == 2) {
  743.                         return 0;
  744.                 }
  745.                 msleep(10);
  746.                 printk(KERN_WARNING "micropklt, i2c read retry\n");
  747.         }
  748.         dev_err(&client->dev, "i2c_read_block retry over %d\n",
  749.                         I2C_READ_RETRY_TIMES);
  750.         return -EIO;
  751. }
  752.  
  753. static u16 sleep_state=0,old_state;
  754. #if CONFIG_PM
  755. static int micropklt_suspend(struct i2c_client *client, pm_message_t mesg)
  756. {
  757.         D("suspending device...");
  758.  
  759. //      char cmd[]={0x20,0x08};
  760. //      send_command(cmd);
  761.         if(sleep_state==-1) {
  762.         if(micropklt_t)
  763.                 old_state=micropklt_t->led_states;
  764.         else
  765.                 old_state=0;
  766.         }
  767.        
  768.         micropklt_set_led_states(0xffff, sleep_state);
  769.         //micropklt_set_led_states(0xffff, 0); old_state=0;
  770.         //Sleeping is GOOD !
  771.         //It's GREEN ! (on topa/rhod.)
  772.         if ( machine_is_htctopaz() || machine_is_htcrhodium() )
  773.                 micropklt_set_color_led_state(1);
  774.         return 0;
  775. }
  776.  
  777. static int micropklt_resume(struct i2c_client *client)
  778. {
  779.         D("resuming device...");
  780. //      char cmd[]={0x20,0x48};
  781. //      send_command(cmd);
  782.         micropklt_set_led_states(0xffff,old_state);
  783.         //Being awake is BAD !
  784.         //It's RED ! (on topa/rhod.) (ok it's amber.)
  785.  
  786.         if ( machine_is_htctopaz() || machine_is_htcrhodium() )
  787.                 micropklt_set_color_led_state(2);
  788.         return 0;
  789. }
  790. #else
  791.  #define micropklt_suspend NULL
  792.  #define micropklt_resume NULL
  793. #endif
  794.  
  795. static const struct i2c_device_id microp_klt_ids[] = {
  796.         { "microp-klt", 0 },
  797.         { }
  798. };
  799.  
  800. static struct i2c_driver micropklt_driver = {
  801.         .driver = {
  802.                 .name   = MODULE_NAME,
  803.                 .owner  = THIS_MODULE,
  804.         },
  805.         .id_table = microp_klt_ids,
  806.         .probe = micropklt_probe,
  807.         .remove = micropklt_remove,
  808.         .suspend = micropklt_suspend,
  809.         .resume = micropklt_resume,
  810. };
  811.  
  812. static int __init micropklt_init(void)
  813. {
  814.         printk(KERN_INFO "microp-klt: Registering MicroP-LED driver\n");
  815.         return i2c_add_driver(&micropklt_driver);
  816. }
  817.  
  818. static void __exit micropklt_exit(void)
  819. {
  820.         printk(KERN_INFO "microp-klt: Unregistered MicroP-LED driver\n");
  821.         i2c_del_driver(&micropklt_driver);
  822. }
  823.  
  824. MODULE_AUTHOR("Joe Hansche <madcoder@gmail.com>");
  825. MODULE_DESCRIPTION("MicroP-LED chip driver");
  826. MODULE_LICENSE("GPL");
  827. MODULE_VERSION("0.1");
  828.  
  829. module_init(micropklt_init);
  830. module_exit(micropklt_exit);
  831.  
  832. #if defined(CONFIG_DEBUG_FS)
  833. static int micropklt_dbg_leds_set(void *dat, u64 val)
  834. {
  835.         struct microp_klt *data;
  836.         struct i2c_client *client;
  837.         uint8_t buffer[4] = { 0, 0, 0, 0 };
  838.         int r;
  839.  
  840.         data = micropklt_t;
  841.         if (!data) return -EAGAIN;
  842.         client = data->client;
  843.  
  844.         mutex_lock(&data->lock);
  845.                 buffer[0] = MICROP_KLT_ID_LED_STATE;
  846.                 buffer[1] = 0xff & val;
  847.                 buffer[2] = 0xff & (val >> 8);
  848.  
  849.         r = micropklt_write(client, buffer, 3);
  850.        
  851.         mutex_unlock(&data->lock);
  852.         return r;
  853. }
  854.  
  855. static int micropklt_dbg_leds_get(void *data, u64 *val) {
  856.         return 0;
  857. }
  858.  
  859. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_leds_fops,
  860.                 micropklt_dbg_leds_get,
  861.                 micropklt_dbg_leds_set, "%llu\n");
  862.  
  863. static int micropklt_dbg_light_set(void *data, u64 val)
  864. {
  865.         return 0;
  866. }
  867.  
  868. static int micropklt_dbg_light_get(void *dat, u64 *val) {
  869.         struct microp_klt *data;
  870.         struct i2c_client *client;
  871.         int r;
  872.         u64 lcd_brgh;
  873.         unsigned long long d, d2;
  874.         uint8_t buffer[4] = { 0, 0, 0, 0 };
  875.         data = micropklt_t;
  876.         if (!data) return -EAGAIN;
  877.  
  878.         client = data->client;
  879.         mutex_lock(&data->lock);
  880.         if(!auto_bl && machine_is_htctopaz()) {
  881.                 buffer[0] = MICROP_I2C_WCMD_AUTO_BL_CTL;
  882.                 buffer[1] = 0x1;
  883.                 buffer[2] = 0x0;
  884.                 r = micropklt_write(client, buffer, 3);
  885.                 msleep(2);
  886.         }
  887.         // the typecast is a bit evil... could be done better.
  888.         r = micropklt_read(client, MICROP_KLT_ID_LIGHT_SENSOR, (uint8_t*)&d, 4);
  889.         *val=(d&0xff00);
  890.         if(machine_is_htctopaz()) {
  891.                 if(!auto_bl) {
  892.                         buffer[0] = MICROP_I2C_WCMD_AUTO_BL_CTL;
  893.                         buffer[1] = 0x0;
  894.                         buffer[2] = 0x0;
  895.                         r = micropklt_write(client, buffer, 3);
  896.                         msleep(2);
  897.                 }
  898.                 r = micropklt_read(client, MICROP_KLT_ID_GET_LCD_BRHTNS, (uint8_t*)&d2, 4);
  899.                 lcd_brgh = (d2&0xff00);
  900.         }
  901.         mutex_unlock(&data->lock);
  902.         return r;
  903. }
  904.  
  905. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_light_fops,
  906.                 micropklt_dbg_light_get,
  907.                 micropklt_dbg_light_set, "%llu\n");
  908.  
  909. static int micropklt_dbg_auto_bl_get(void *dat, u64 *val) {
  910.         *val=0;
  911.         return 0;
  912. }
  913.  
  914. static int micropklt_dbg_auto_bl_set(void *dat, u64 val)
  915. {
  916.         struct microp_klt *data;
  917.         uint8_t buffer[4] = { 0, 0, 0, 0 };
  918.         struct i2c_client *client;
  919.         int r;
  920.         auto_bl = val;
  921.  
  922.         data = micropklt_t;
  923.         if (!data) return -EAGAIN;
  924.         client = data->client;
  925.  
  926.         mutex_lock(&data->lock);
  927.                 buffer[0] = MICROP_I2C_WCMD_AUTO_BL_CTL;
  928.                 if(machine_is_htctopaz())
  929.                         buffer[1] = val;
  930.                   else
  931.                         buffer[1] = 0x2;
  932.                 buffer[2] = val;
  933.         r = micropklt_write(client, buffer, 3);
  934.         mutex_unlock(&data->lock);
  935.         return 0;
  936. }
  937.  
  938.  
  939. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_auto_bl_fops,
  940.                 micropklt_dbg_auto_bl_get,
  941.                 micropklt_dbg_auto_bl_set, "%llu\n");
  942.  
  943. static int micropklt_dbg_sleep_get(void *dat, u64 *val) {
  944.         *val=sleep_state;
  945.         return 0;
  946. }
  947.  
  948. static int micropklt_dbg_sleep_set(void *dat, u64 val)
  949. {
  950.         sleep_state=val;
  951.         return 0;
  952. }
  953.  
  954.  
  955. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_sleep_fops,
  956.                 micropklt_dbg_sleep_get,
  957.                 micropklt_dbg_sleep_set, "%llu\n");
  958.  
  959. static int micropklt_dbg_effects_get(void *dat, u64 *val) {
  960.         switch( (micropklt_t->led_states&0x1f00)>>8) {
  961.                 case 1:
  962.                         //Ring
  963.                         *val=1;
  964.                         break;
  965.                 case 2:
  966.                         //Blink
  967.                         *val=2;
  968.                         break;
  969.                 case 4:
  970.                         //Breathe
  971.                         *val=3;
  972.                         break;
  973.                 case 5:
  974.                         //Fade
  975.                         *val=4;
  976.                         break;
  977.                 case 8:
  978.                         //Rotate
  979.                         *val=5;
  980.                         break;
  981.                 case 0x10:
  982.                         //Vertical
  983.                         *val=6;
  984.                         break;
  985.                 default:
  986.                         *val=0;
  987.                         break;
  988.         }
  989.  
  990.         return 0;
  991. }
  992.  
  993. static int micropklt_dbg_effects_set(void *dat, u64 val)
  994. {
  995.         switch(val) {
  996.                 default:
  997.                 case 0:
  998.                         //Clear
  999.                         micropklt_set_led_states(0x1f00, 0);
  1000.                         break;
  1001.                 case 1:
  1002.                         //Ring
  1003.                         micropklt_set_led_states(0x1f00, MICROP_KLT_SYSLED_RING);
  1004.                         break;
  1005.                 case 2:
  1006.                         //Blink
  1007.                         micropklt_set_led_states(0x1f00, MICROP_KLT_SYSLED_BLINK);
  1008.                         break;
  1009.                 case 3:
  1010.                         //Breathe
  1011.                         micropklt_set_led_states(0x1f00, MICROP_KLT_SYSLED_BREATHE);
  1012.                         break;
  1013.                 case 4:
  1014.                         //Fade
  1015.                         micropklt_set_led_states(0x1f00, MICROP_KLT_SYSLED_FADE);
  1016.                         break;
  1017.                 case 5:
  1018.                         //Rotate
  1019.                         micropklt_set_led_states(0x1f00, MICROP_KLT_SYSLED_ROTATE);
  1020.                         break;
  1021.                 case 6:
  1022.                         //Vertical
  1023.                         micropklt_set_led_states(0x1f00, MICROP_KLT_SYSLED_VERTICAL);
  1024.                         break;
  1025.         }
  1026.         return 0;
  1027. }
  1028.  
  1029.  
  1030. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_effects_fops,
  1031.                 micropklt_dbg_effects_get,
  1032.                 micropklt_dbg_effects_set, "%llu\n");
  1033.  
  1034. static int micropklt_dbg_sl_eff_get(void *dat, u64 *val) {
  1035.         switch( (sleep_state&0x1f00)>>8) {
  1036.                 case 1:
  1037.                         //Ring
  1038.                         *val=1;
  1039.                         break;
  1040.                 case 2:
  1041.                         //Blink
  1042.                         *val=2;
  1043.                         break;
  1044.                 case 4:
  1045.                         //Breathe
  1046.                         *val=3;
  1047.                         break;
  1048.                 case 5:
  1049.                         //Fade
  1050.                         *val=4;
  1051.                         break;
  1052.                 case 8:
  1053.                         //Rotate
  1054.                         *val=5;
  1055.                         break;
  1056.                 case 0x10:
  1057.                         //Vertical
  1058.                         *val=6;
  1059.                         break;
  1060.                 default:
  1061.                         *val=0;
  1062.                         break;
  1063.         }
  1064.  
  1065.         return 0;
  1066. }
  1067.  
  1068. static int micropklt_dbg_sl_eff_set(void *dat, u64 val)
  1069. {
  1070.         switch(val) {
  1071.                 default:
  1072.                 case 0:
  1073.                         //Clear
  1074.                         sleep_state=0;
  1075.                         break;
  1076.                 case 1:
  1077.                         //Ring
  1078.                         sleep_state=MICROP_KLT_SYSLED_RING;
  1079.                         break;
  1080.                 case 2:
  1081.                         //Blink
  1082.                         sleep_state=MICROP_KLT_SYSLED_BLINK;
  1083.                         break;
  1084.                 case 3:
  1085.                         //Breathe
  1086.                         sleep_state=MICROP_KLT_SYSLED_BREATHE;
  1087.                         break;
  1088.                 case 4:
  1089.                         //Fade
  1090.                         sleep_state=MICROP_KLT_SYSLED_FADE;
  1091.                         break;
  1092.                 case 5:
  1093.                         //Rotate
  1094.                         sleep_state=MICROP_KLT_SYSLED_ROTATE;
  1095.                         break;
  1096.                 case 6:
  1097.                         //Vertical
  1098.                         sleep_state=MICROP_KLT_SYSLED_VERTICAL;
  1099.                         break;
  1100.         }
  1101.         return 0;
  1102. }
  1103.  
  1104.  
  1105. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_sl_eff_fops,
  1106.                 micropklt_dbg_sl_eff_get,
  1107.                 micropklt_dbg_sl_eff_set, "%llu\n");
  1108.  
  1109. static int micropklt_dbg_gpi_get(void *dat, u64 *val) {
  1110.  
  1111.         struct microp_klt *data;
  1112.         struct i2c_client *client;
  1113.         uint8_t *buff;
  1114.         int r;
  1115.  
  1116.         data = micropklt_t;
  1117.         if (!data) return -EAGAIN;
  1118.         client = data->client;
  1119.         buff = (uint8_t*)val;
  1120.  
  1121.         mutex_lock(&data->lock);
  1122.         r = micropklt_read(client, MICROP_I2C_RCMD_GPI_STATUS, buff, 2);
  1123.         mutex_unlock(&data->lock);
  1124.  
  1125.         return r;
  1126. }
  1127.  
  1128. static int micropklt_dbg_gpi_set(void *dat, u64 val)
  1129. {
  1130.         return -EPERM;
  1131. }
  1132.  
  1133. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_gpi_fops,
  1134.                 micropklt_dbg_gpi_get,
  1135.                 micropklt_dbg_gpi_set, "%llu\n");
  1136.  
  1137. static int micropklt_dbg_color_led_get(void *dat, u64 *val) {
  1138.         *val=0;
  1139.         return 0;
  1140. }
  1141.  
  1142. static int micropklt_dbg_color_led_set(void *dat, u64 val)
  1143. {
  1144.         struct microp_klt *data;
  1145.         struct i2c_client *client;
  1146.         uint8_t buffer[5] = { 0, 0, 0, 0, 0 };
  1147.         int r;
  1148.  
  1149.         if(color_led_address==0) return -ENODEV;
  1150.  
  1151.         data = micropklt_t;
  1152.         if (!data) return -EAGAIN;
  1153.         client = data->client;
  1154.  
  1155.         mutex_lock(&data->lock);
  1156.                 buffer[0] = color_led_address;
  1157.                 buffer[1] = val&0xff;
  1158.                 buffer[2] = (val>>8)&0xff;
  1159.                 buffer[3] = (val>>16)&0xff;
  1160.                 buffer[4] = (val>>32)&0xff;
  1161.         r = micropklt_write(client, buffer, 5);
  1162.         mutex_unlock(&data->lock);
  1163.         return 0;
  1164. }
  1165.  
  1166. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_color_led_fops,
  1167.                 micropklt_dbg_color_led_get,
  1168.                 micropklt_dbg_color_led_set, "%llu\n");
  1169.  
  1170. static int micropklt_dbg_brightness_get(void *dat, u64 *val) {
  1171.         return -EIO;
  1172. }
  1173.  
  1174. static int micropklt_dbg_brightness_set(void *dat, u64 val)
  1175. {
  1176.         struct microp_klt *data;
  1177.         struct i2c_client *client;
  1178.         uint8_t buffer[2] = { 0, 0, };
  1179.         int r;
  1180.  
  1181.         data = micropklt_t;
  1182.         if (!data) return -EAGAIN;
  1183.         client = data->client;
  1184.  
  1185.         mutex_lock(&data->lock);
  1186.                 buffer[0] = 0xcc;
  1187.                 buffer[1] = val;//time ?
  1188.         r = micropklt_write(client, buffer, 2);
  1189.         mutex_unlock(&data->lock);
  1190.         return 0;
  1191. }
  1192.  
  1193.  
  1194. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_brightness_fops,
  1195.                 micropklt_dbg_brightness_get,
  1196.                 micropklt_dbg_brightness_set, "%llu\n");
  1197.  
  1198. static int __init micropklt_dbg_init(void)
  1199. {
  1200.         struct dentry *dent;
  1201.  
  1202.         dent = debugfs_create_dir("micropklt_dbg", 0);
  1203.         if (IS_ERR(dent))
  1204.                 return PTR_ERR(dent);
  1205.  
  1206.         debugfs_create_file("leds", 0444, dent, NULL,
  1207.                         &micropklt_dbg_leds_fops);
  1208.         debugfs_create_file("light", 0444, dent, NULL,
  1209.                         &micropklt_dbg_light_fops);
  1210.         debugfs_create_file("auto_backlight", 0666, dent, NULL,
  1211.                         &micropklt_dbg_auto_bl_fops);
  1212.         debugfs_create_file("sleep_leds", 0666, dent, NULL,
  1213.                         &micropklt_dbg_sleep_fops);
  1214.         debugfs_create_file("sleep_effects", 0666, dent, NULL,
  1215.                         &micropklt_dbg_sl_eff_fops);
  1216.         debugfs_create_file("effects", 0666, dent, NULL,
  1217.                         &micropklt_dbg_effects_fops);
  1218.         debugfs_create_file("color_led", 0666, dent, NULL,
  1219.                         &micropklt_dbg_color_led_fops);
  1220.         debugfs_create_file("brightness", 0666, dent, NULL,
  1221.                         &micropklt_dbg_brightness_fops);
  1222.  
  1223.         debugfs_create_file("gpi", 0444, dent, NULL,
  1224.                         &micropklt_dbg_gpi_fops);
  1225.  
  1226.         return 0;
  1227. }
  1228.  
  1229. device_initcall(micropklt_dbg_init);
  1230. #endif /* CONFIG_DEBUG_FS */