Guest
Public paste!

Untitled

By: a guest | Sep 8th, 2010 | Syntax: None | Size: 28.46 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 microp_klt_init_cam()
  417. {
  418.         struct microp_klt *data;
  419.         struct i2c_client *client;
  420.         uint8_t buffer[2] = { 0x14,0};
  421.  
  422.         data = micropklt_t;
  423.         if (!data) return;
  424.         client = data->client;
  425.  
  426.         printk(KERN_INFO MODULE_NAME ": Sending cam init\n");
  427.  
  428.         micropklt_write(client, buf, 2);
  429. }
  430.  
  431. void init_mic()
  432. {
  433.  
  434.         struct microp_klt *data;
  435.         struct i2c_client *client;
  436.         uint8_t buffer[5] = { 0, 0, 0, 0, 0 };
  437.  
  438.         data = micropklt_t;
  439.         if (!data) return;
  440.         client = data->client;
  441.  
  442.         printk(KERN_INFO MODULE_NAME ": Sending mic init\n");
  443.  
  444.         uint8_t buf[5];
  445.         buf[0] = 0x50;
  446.         buf[1] = 0;
  447.         buf[2] = 0;
  448.         buf[3] = 0;
  449.         buf[4] = 0;
  450.         micropklt_write(client, buf, 5);
  451.  
  452.         buf[1] = 0x2;
  453.         buf[3] = 0xff;
  454.         buf[4] = 0xff;
  455.         micropklt_write(client, buf, 5);
  456.  
  457.         buf[0] = 0x25;
  458.         buf[1] = 0x04;
  459.         micropklt_write(client, buf, 2);
  460.  
  461.         buf[1] = 0x14;
  462.         micropklt_write(client, buf, 2);
  463.  
  464.         buf[1] = 0x04;
  465.         micropklt_write(client, buf, 2);
  466. /*
  467.         buf[0] = 0x25;
  468.         buf[1] = 0x40;
  469.         micropklt_write(client, buf, 2);
  470.  
  471.         buf[1] = 0x44;
  472.         micropklt_write(client, buf, 2);*/
  473. }
  474.  
  475. EXPORT_SYMBOL(init_mic);
  476.  
  477.  
  478. void init_mic_post_adc()
  479. {
  480.  
  481.         struct microp_klt *data;
  482.         struct i2c_client *client;
  483.         uint8_t buffer[5] = { 0, 0, 0, 0, 0 };
  484.  
  485.         data = micropklt_t;
  486.         if (!data) return;
  487.         client = data->client;
  488.  
  489.         printk(KERN_INFO MODULE_NAME ": Sending mic init\n");
  490.  
  491.         uint8_t buf[5];
  492.  
  493.         buf[0] = 0x25;
  494.         buf[1] = 0x40;
  495. //      micropklt_write(client, buf, 2);
  496. }
  497.  
  498. EXPORT_SYMBOL(init_mic_post_adc);
  499.  
  500. static int micropklt_probe(struct i2c_client *client, const struct i2c_device_id *id)
  501. {
  502.         struct microp_klt *data;
  503.         int supported, r, i;
  504.         uint8_t buf[3] = { 0, 0, 0 };
  505.         int id_version;
  506.  
  507.         auto_bl = 0;
  508.  
  509.         printk(KERN_INFO MODULE_NAME ": Initializing MicroP-LED chip driver at "
  510.                "addr: 0x%02x\n", client->addr);
  511.  
  512.  
  513.         if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
  514.                 printk(KERN_ERR MODULE_NAME ": i2c bus not supported\n");
  515.                 return -EINVAL;
  516.         }
  517.  
  518.         data = kzalloc(sizeof *data, GFP_KERNEL);
  519.         if (data < 0) {
  520.                 printk(KERN_ERR MODULE_NAME ": Not enough memory\n");
  521.                 return -ENOMEM;
  522.         }
  523.  
  524.         // maybe seperate the read and write mutex.
  525.         mutex_init(&data->lock);
  526.         mutex_lock(&data->lock);
  527.  
  528.         data->client = client;
  529.         i2c_set_clientdata(client, data);
  530.         data->enable_early_suspend=1;
  531.         micropklt_t = data;
  532.  
  533.         // Read version
  534.         if (machine_is_htckovsky()) {
  535.                 id_version = MICROP_KLT_ID_VERSION_KOVS;
  536.         } else {
  537.                 id_version = MICROP_KLT_ID_VERSION;
  538.         }
  539.         if( micropklt_read(client, id_version, buf, 2) < 0 ) {
  540.                 printk( KERN_ERR MODULE_NAME" : unable to read microp firmware version\n" );
  541.                 r = -EIO;
  542.                 goto fail;
  543.         }
  544.  
  545.         /* Check version against what we think we should support
  546.          * Known supported versions:
  547.          *   0105, 0205, 0a05, 0b05, 0d02
  548.          *   8182, 8185
  549.          *   0c82, 0c85
  550.          *   060d
  551.          *   kovsky:
  552.          *   0787
  553.          */
  554.         supported = 0;
  555.         data->version = (buf[0] << 8) | buf[1];
  556.         switch (buf[0]) {
  557.         case 0x01:
  558.         case 0x02:
  559.         case 0x0a:
  560.         case 0x0b:
  561.                 switch (buf[1]) {
  562.                 case 0x0e: /* topa100 */
  563.                         bma150_probe(data);
  564.                 case 0x88: /* rhod210 */
  565.                 case 0x01:
  566.                 case 0x05:
  567.                 case 0x81: /* diam500 */
  568.                         supported = 1;
  569.                         break;
  570.                 }
  571.                 break;
  572.         case 0x0d:
  573.                 switch (buf[1]) {
  574.                 case 0x02:
  575.                         supported = 1;
  576.                         break;
  577.                 case 0x0a: /* raph300 */
  578.                         supported = 1;
  579.                         break;
  580.                 }
  581.                 break;
  582.         case 0x81:
  583.         case 0x0c:
  584.                 switch (buf[1]) {
  585.                 case 0x82:
  586.                 case 0x85:
  587.                         supported = 1;
  588.                         break;
  589.                 }
  590.                 break;
  591.         case 0x06:
  592.                 switch (buf[1]) {
  593.                 case 0x0d:
  594.                         supported = 1;
  595.                         break;
  596.                 }
  597.                 break;
  598.         case 0x07:
  599.                 switch (buf[1]) {
  600.                 case 0x87:
  601.                         supported = 1;
  602.                         break;
  603.                 }
  604.                 break;
  605.         }
  606.  
  607.         // microp misc state init value.
  608.         data->misc_states = 0x0C;
  609.  
  610.         /* if for some reason the hardware should support it, but it simply shows the wrong I2C id, its possible the device has been
  611.          * set into bootloader mode. See HTC Hero's microp driver for a way to fix this.
  612.          */
  613.         if (!supported) {
  614.                 printk(KERN_WARNING MODULE_NAME ": This hardware is not yet supported: %04x\n", data->version);
  615.                 r = -ENOTSUPP;
  616.                 goto fail;
  617.         }
  618.  
  619.         data->led_states = MICROP_KLT_DEFAULT_LED_STATES;
  620.  
  621.         data->leds[0].name = "klt::home";
  622.         data->leds[0].brightness = LED_OFF;
  623.         data->leds[0].brightness_set = micropklt_led_brightness_set;
  624.  
  625.         data->leds[1].name = "klt::back";
  626.         data->leds[1].brightness = LED_OFF;
  627.         data->leds[1].brightness_set = micropklt_led_brightness_set;
  628.  
  629.         data->leds[2].name = "klt::end";
  630.         data->leds[2].brightness = LED_OFF;
  631.         data->leds[2].brightness_set = micropklt_led_brightness_set;
  632.  
  633.         data->leds[3].name = "klt::send";
  634.         data->leds[3].brightness = LED_OFF;
  635.         data->leds[3].brightness_set = micropklt_led_brightness_set;
  636.  
  637.         data->leds[4].name = "klt::action";
  638.         data->leds[4].brightness = LED_OFF;
  639.         data->leds[4].brightness_set = micropklt_led_brightness_set;
  640.  
  641.         data->leds[5].name = "klt::lcd-bkl";
  642.         data->leds[5].brightness = 0x90;
  643.         data->leds[5].brightness_set = micropklt_led_brightness_set;
  644.  
  645.         data->leds[6].name = "klt::keypad-bkl";
  646.         data->leds[6].brightness = LED_OFF;
  647.         data->leds[6].brightness_set = micropklt_led_brightness_set;
  648.  
  649. #ifdef CONFIG_ANDROID_PMEM
  650.         data->leds[5].name = "lcd-backlight";
  651.         data->leds[6].name = "button-backlight";
  652. #endif
  653.  
  654.         for (i=0; i<ARRAY_SIZE(data->leds); i++) {
  655.                 r = led_classdev_register(&client->dev, &data->leds[i]);
  656.                 if (r < 0) {
  657.                         goto err_led_classdev_register_failed;
  658.                         break;
  659.                 }
  660.         }
  661.  
  662.         if(machine_is_htctopaz())
  663.                 color_led_address = 0x51;
  664.         else if (machine_is_htcrhodium())
  665.                 color_led_address = 0x50;
  666.         else if (machine_is_htckovsky())
  667.                 color_led_address = 0x20;
  668.         else
  669.                 color_led_address = 0x0;
  670.  
  671.         mutex_unlock(&data->lock);
  672.  
  673.         // Set default LED state
  674.         micropklt_set_led_states(MICROP_KLT_ALL_LEDS, MICROP_KLT_DEFAULT_LED_STATES);
  675.  
  676.         if(machine_is_htctopaz())       // Enable keypadled with device
  677.                 micropklt_set_led_states(0x1, 0x1);
  678.  
  679.         #ifdef CONFIG_HAS_EARLYSUSPEND
  680.         if (data->enable_early_suspend) {
  681.                 data->early_suspend.level =
  682.                                 EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
  683.                 data->early_suspend.suspend = micropklt_early_suspend;
  684.                 data->early_suspend.resume = micropklt_early_resume;
  685.                 register_early_suspend(&data->early_suspend);
  686.         }
  687.         #endif
  688.  
  689.         if (machine_is_htcrhodium())
  690.         {
  691.                 //init dual mic
  692.                 //init_mic(client);
  693.         }
  694.  
  695.         printk(KERN_INFO MODULE_NAME ": Initialized MicroP-LED chip revision v%04x\n", data->version);
  696.  
  697.         return 0;
  698.  
  699. err_led_classdev_register_failed:
  700.         printk(KERN_ERR MODULE_NAME ": led_classdev_register(%d) failed: %d\n", i, r);
  701.         for (i=i; i>=0; i--) {
  702.                 led_classdev_unregister(&data->leds[i]);
  703.         }
  704. fail:
  705.         mutex_unlock(&data->lock);
  706.         kfree(data);
  707.         micropklt_t = 0;
  708.         return r;
  709. }
  710.  
  711. static int micropklt_write(struct i2c_client *client, uint8_t *sendbuf, int len)
  712. {
  713.         int rc;
  714.         int retry;
  715.  
  716.         struct i2c_msg msg[] = {
  717.                 {
  718.                         .addr = client->addr,
  719.                         .flags = 0,
  720.                         .len = len,
  721.                         .buf = sendbuf,
  722.                 },
  723.         };
  724.  
  725.         for (retry = 0; retry <= I2C_WRITE_RETRY_TIMES; retry++) {
  726.                 rc = i2c_transfer(client->adapter, msg, 1);
  727.                 if (rc == 1)
  728.                         return 0;
  729.                 msleep(10);
  730.                 printk(KERN_WARNING "micropklt, i2c write retry\n");
  731.         }
  732.         printk(KERN_ERR "micropklt_write, i2c_write_block retry over %d\n",
  733.                         I2C_WRITE_RETRY_TIMES);
  734.         return rc;
  735. }
  736.  
  737. static int micropklt_read(struct i2c_client *client, uint8_t id, uint8_t *buf, int len)
  738. {
  739.         int retry;
  740.         int rc;
  741.         struct i2c_msg msgs[] = {
  742.                 {
  743.                         .addr = client->addr,
  744.                         .flags = 0,
  745.                         .len = 1,
  746.                         .buf = &id,
  747.                 },
  748.                 {
  749.                         .addr = client->addr,
  750.                         .flags = I2C_M_RD,
  751.                         .len = len,
  752.                         .buf = buf,
  753.                 }
  754.         };
  755.         for (retry= 0; retry <= I2C_READ_RETRY_TIMES; retry++) {
  756.                 rc = i2c_transfer(client->adapter, msgs, 2);
  757.                 if (rc == 2) {
  758.                         return 0;
  759.                 }
  760.                 msleep(10);
  761.                 printk(KERN_WARNING "micropklt, i2c read retry\n");
  762.         }
  763.         dev_err(&client->dev, "i2c_read_block retry over %d\n",
  764.                         I2C_READ_RETRY_TIMES);
  765.         return -EIO;
  766. }
  767.  
  768. static u16 sleep_state=0,old_state;
  769. #if CONFIG_PM
  770. static int micropklt_suspend(struct i2c_client *client, pm_message_t mesg)
  771. {
  772.         D("suspending device...");
  773.  
  774. //      char cmd[]={0x20,0x08};
  775. //      send_command(cmd);
  776.         if(sleep_state==-1) {
  777.         if(micropklt_t)
  778.                 old_state=micropklt_t->led_states;
  779.         else
  780.                 old_state=0;
  781.         }
  782.        
  783.         micropklt_set_led_states(0xffff, sleep_state);
  784.         //micropklt_set_led_states(0xffff, 0); old_state=0;
  785.         //Sleeping is GOOD !
  786.         //It's GREEN ! (on topa/rhod.)
  787.         if ( machine_is_htctopaz() || machine_is_htcrhodium() )
  788.                 micropklt_set_color_led_state(1);
  789.         return 0;
  790. }
  791.  
  792. static int micropklt_resume(struct i2c_client *client)
  793. {
  794.         D("resuming device...");
  795. //      char cmd[]={0x20,0x48};
  796. //      send_command(cmd);
  797.         micropklt_set_led_states(0xffff,old_state);
  798.         //Being awake is BAD !
  799.         //It's RED ! (on topa/rhod.) (ok it's amber.)
  800.  
  801.         if ( machine_is_htctopaz() || machine_is_htcrhodium() )
  802.                 micropklt_set_color_led_state(2);
  803.         return 0;
  804. }
  805. #else
  806.  #define micropklt_suspend NULL
  807.  #define micropklt_resume NULL
  808. #endif
  809.  
  810. static const struct i2c_device_id microp_klt_ids[] = {
  811.         { "microp-klt", 0 },
  812.         { }
  813. };
  814.  
  815. static struct i2c_driver micropklt_driver = {
  816.         .driver = {
  817.                 .name   = MODULE_NAME,
  818.                 .owner  = THIS_MODULE,
  819.         },
  820.         .id_table = microp_klt_ids,
  821.         .probe = micropklt_probe,
  822.         .remove = micropklt_remove,
  823.         .suspend = micropklt_suspend,
  824.         .resume = micropklt_resume,
  825. };
  826.  
  827. static int __init micropklt_init(void)
  828. {
  829.         printk(KERN_INFO "microp-klt: Registering MicroP-LED driver\n");
  830.         return i2c_add_driver(&micropklt_driver);
  831. }
  832.  
  833. static void __exit micropklt_exit(void)
  834. {
  835.         printk(KERN_INFO "microp-klt: Unregistered MicroP-LED driver\n");
  836.         i2c_del_driver(&micropklt_driver);
  837. }
  838.  
  839. MODULE_AUTHOR("Joe Hansche <madcoder@gmail.com>");
  840. MODULE_DESCRIPTION("MicroP-LED chip driver");
  841. MODULE_LICENSE("GPL");
  842. MODULE_VERSION("0.1");
  843.  
  844. module_init(micropklt_init);
  845. module_exit(micropklt_exit);
  846.  
  847. #if defined(CONFIG_DEBUG_FS)
  848. static int micropklt_dbg_leds_set(void *dat, u64 val)
  849. {
  850.         struct microp_klt *data;
  851.         struct i2c_client *client;
  852.         uint8_t buffer[4] = { 0, 0, 0, 0 };
  853.         int r;
  854.  
  855.         data = micropklt_t;
  856.         if (!data) return -EAGAIN;
  857.         client = data->client;
  858.  
  859.         mutex_lock(&data->lock);
  860.                 buffer[0] = MICROP_KLT_ID_LED_STATE;
  861.                 buffer[1] = 0xff & val;
  862.                 buffer[2] = 0xff & (val >> 8);
  863.  
  864.         r = micropklt_write(client, buffer, 3);
  865.        
  866.         mutex_unlock(&data->lock);
  867.         return r;
  868. }
  869.  
  870. static int micropklt_dbg_leds_get(void *data, u64 *val) {
  871.         return 0;
  872. }
  873.  
  874. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_leds_fops,
  875.                 micropklt_dbg_leds_get,
  876.                 micropklt_dbg_leds_set, "%llu\n");
  877.  
  878. static int micropklt_dbg_light_set(void *data, u64 val)
  879. {
  880.         return 0;
  881. }
  882.  
  883. static int micropklt_dbg_light_get(void *dat, u64 *val) {
  884.         struct microp_klt *data;
  885.         struct i2c_client *client;
  886.         int r;
  887.         u64 lcd_brgh;
  888.         unsigned long long d, d2;
  889.         uint8_t buffer[4] = { 0, 0, 0, 0 };
  890.         data = micropklt_t;
  891.         if (!data) return -EAGAIN;
  892.  
  893.         client = data->client;
  894.         mutex_lock(&data->lock);
  895.         if(!auto_bl && machine_is_htctopaz()) {
  896.                 buffer[0] = MICROP_I2C_WCMD_AUTO_BL_CTL;
  897.                 buffer[1] = 0x1;
  898.                 buffer[2] = 0x0;
  899.                 r = micropklt_write(client, buffer, 3);
  900.                 msleep(2);
  901.         }
  902.         // the typecast is a bit evil... could be done better.
  903.         r = micropklt_read(client, MICROP_KLT_ID_LIGHT_SENSOR, (uint8_t*)&d, 4);
  904.         *val=(d&0xff00);
  905.         if(machine_is_htctopaz()) {
  906.                 if(!auto_bl) {
  907.                         buffer[0] = MICROP_I2C_WCMD_AUTO_BL_CTL;
  908.                         buffer[1] = 0x0;
  909.                         buffer[2] = 0x0;
  910.                         r = micropklt_write(client, buffer, 3);
  911.                         msleep(2);
  912.                 }
  913.                 r = micropklt_read(client, MICROP_KLT_ID_GET_LCD_BRHTNS, (uint8_t*)&d2, 4);
  914.                 lcd_brgh = (d2&0xff00);
  915.         }
  916.         mutex_unlock(&data->lock);
  917.         return r;
  918. }
  919.  
  920. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_light_fops,
  921.                 micropklt_dbg_light_get,
  922.                 micropklt_dbg_light_set, "%llu\n");
  923.  
  924. static int micropklt_dbg_auto_bl_get(void *dat, u64 *val) {
  925.         *val=0;
  926.         return 0;
  927. }
  928.  
  929. static int micropklt_dbg_auto_bl_set(void *dat, u64 val)
  930. {
  931.         struct microp_klt *data;
  932.         uint8_t buffer[4] = { 0, 0, 0, 0 };
  933.         struct i2c_client *client;
  934.         int r;
  935.         auto_bl = val;
  936.  
  937.         data = micropklt_t;
  938.         if (!data) return -EAGAIN;
  939.         client = data->client;
  940.  
  941.         mutex_lock(&data->lock);
  942.                 buffer[0] = MICROP_I2C_WCMD_AUTO_BL_CTL;
  943.                 if(machine_is_htctopaz())
  944.                         buffer[1] = val;
  945.                   else
  946.                         buffer[1] = 0x2;
  947.                 buffer[2] = val;
  948.         r = micropklt_write(client, buffer, 3);
  949.         mutex_unlock(&data->lock);
  950.         return 0;
  951. }
  952.  
  953.  
  954. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_auto_bl_fops,
  955.                 micropklt_dbg_auto_bl_get,
  956.                 micropklt_dbg_auto_bl_set, "%llu\n");
  957.  
  958. static int micropklt_dbg_sleep_get(void *dat, u64 *val) {
  959.         *val=sleep_state;
  960.         return 0;
  961. }
  962.  
  963. static int micropklt_dbg_sleep_set(void *dat, u64 val)
  964. {
  965.         sleep_state=val;
  966.         return 0;
  967. }
  968.  
  969.  
  970. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_sleep_fops,
  971.                 micropklt_dbg_sleep_get,
  972.                 micropklt_dbg_sleep_set, "%llu\n");
  973.  
  974. static int micropklt_dbg_effects_get(void *dat, u64 *val) {
  975.         switch( (micropklt_t->led_states&0x1f00)>>8) {
  976.                 case 1:
  977.                         //Ring
  978.                         *val=1;
  979.                         break;
  980.                 case 2:
  981.                         //Blink
  982.                         *val=2;
  983.                         break;
  984.                 case 4:
  985.                         //Breathe
  986.                         *val=3;
  987.                         break;
  988.                 case 5:
  989.                         //Fade
  990.                         *val=4;
  991.                         break;
  992.                 case 8:
  993.                         //Rotate
  994.                         *val=5;
  995.                         break;
  996.                 case 0x10:
  997.                         //Vertical
  998.                         *val=6;
  999.                         break;
  1000.                 default:
  1001.                         *val=0;
  1002.                         break;
  1003.         }
  1004.  
  1005.         return 0;
  1006. }
  1007.  
  1008. static int micropklt_dbg_effects_set(void *dat, u64 val)
  1009. {
  1010.         switch(val) {
  1011.                 default:
  1012.                 case 0:
  1013.                         //Clear
  1014.                         micropklt_set_led_states(0x1f00, 0);
  1015.                         break;
  1016.                 case 1:
  1017.                         //Ring
  1018.                         micropklt_set_led_states(0x1f00, MICROP_KLT_SYSLED_RING);
  1019.                         break;
  1020.                 case 2:
  1021.                         //Blink
  1022.                         micropklt_set_led_states(0x1f00, MICROP_KLT_SYSLED_BLINK);
  1023.                         break;
  1024.                 case 3:
  1025.                         //Breathe
  1026.                         micropklt_set_led_states(0x1f00, MICROP_KLT_SYSLED_BREATHE);
  1027.                         break;
  1028.                 case 4:
  1029.                         //Fade
  1030.                         micropklt_set_led_states(0x1f00, MICROP_KLT_SYSLED_FADE);
  1031.                         break;
  1032.                 case 5:
  1033.                         //Rotate
  1034.                         micropklt_set_led_states(0x1f00, MICROP_KLT_SYSLED_ROTATE);
  1035.                         break;
  1036.                 case 6:
  1037.                         //Vertical
  1038.                         micropklt_set_led_states(0x1f00, MICROP_KLT_SYSLED_VERTICAL);
  1039.                         break;
  1040.         }
  1041.         return 0;
  1042. }
  1043.  
  1044.  
  1045. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_effects_fops,
  1046.                 micropklt_dbg_effects_get,
  1047.                 micropklt_dbg_effects_set, "%llu\n");
  1048.  
  1049. static int micropklt_dbg_sl_eff_get(void *dat, u64 *val) {
  1050.         switch( (sleep_state&0x1f00)>>8) {
  1051.                 case 1:
  1052.                         //Ring
  1053.                         *val=1;
  1054.                         break;
  1055.                 case 2:
  1056.                         //Blink
  1057.                         *val=2;
  1058.                         break;
  1059.                 case 4:
  1060.                         //Breathe
  1061.                         *val=3;
  1062.                         break;
  1063.                 case 5:
  1064.                         //Fade
  1065.                         *val=4;
  1066.                         break;
  1067.                 case 8:
  1068.                         //Rotate
  1069.                         *val=5;
  1070.                         break;
  1071.                 case 0x10:
  1072.                         //Vertical
  1073.                         *val=6;
  1074.                         break;
  1075.                 default:
  1076.                         *val=0;
  1077.                         break;
  1078.         }
  1079.  
  1080.         return 0;
  1081. }
  1082.  
  1083. static int micropklt_dbg_sl_eff_set(void *dat, u64 val)
  1084. {
  1085.         switch(val) {
  1086.                 default:
  1087.                 case 0:
  1088.                         //Clear
  1089.                         sleep_state=0;
  1090.                         break;
  1091.                 case 1:
  1092.                         //Ring
  1093.                         sleep_state=MICROP_KLT_SYSLED_RING;
  1094.                         break;
  1095.                 case 2:
  1096.                         //Blink
  1097.                         sleep_state=MICROP_KLT_SYSLED_BLINK;
  1098.                         break;
  1099.                 case 3:
  1100.                         //Breathe
  1101.                         sleep_state=MICROP_KLT_SYSLED_BREATHE;
  1102.                         break;
  1103.                 case 4:
  1104.                         //Fade
  1105.                         sleep_state=MICROP_KLT_SYSLED_FADE;
  1106.                         break;
  1107.                 case 5:
  1108.                         //Rotate
  1109.                         sleep_state=MICROP_KLT_SYSLED_ROTATE;
  1110.                         break;
  1111.                 case 6:
  1112.                         //Vertical
  1113.                         sleep_state=MICROP_KLT_SYSLED_VERTICAL;
  1114.                         break;
  1115.         }
  1116.         return 0;
  1117. }
  1118.  
  1119.  
  1120. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_sl_eff_fops,
  1121.                 micropklt_dbg_sl_eff_get,
  1122.                 micropklt_dbg_sl_eff_set, "%llu\n");
  1123.  
  1124. static int micropklt_dbg_gpi_get(void *dat, u64 *val) {
  1125.  
  1126.         struct microp_klt *data;
  1127.         struct i2c_client *client;
  1128.         uint8_t *buff;
  1129.         int r;
  1130.  
  1131.         data = micropklt_t;
  1132.         if (!data) return -EAGAIN;
  1133.         client = data->client;
  1134.         buff = (uint8_t*)val;
  1135.  
  1136.         mutex_lock(&data->lock);
  1137.         r = micropklt_read(client, MICROP_I2C_RCMD_GPI_STATUS, buff, 2);
  1138.         mutex_unlock(&data->lock);
  1139.  
  1140.         return r;
  1141. }
  1142.  
  1143. static int micropklt_dbg_gpi_set(void *dat, u64 val)
  1144. {
  1145.         return -EPERM;
  1146. }
  1147.  
  1148. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_gpi_fops,
  1149.                 micropklt_dbg_gpi_get,
  1150.                 micropklt_dbg_gpi_set, "%llu\n");
  1151.  
  1152. static int micropklt_dbg_color_led_get(void *dat, u64 *val) {
  1153.         *val=0;
  1154.         return 0;
  1155. }
  1156.  
  1157. static int micropklt_dbg_color_led_set(void *dat, u64 val)
  1158. {
  1159.         struct microp_klt *data;
  1160.         struct i2c_client *client;
  1161.         uint8_t buffer[5] = { 0, 0, 0, 0, 0 };
  1162.         int r;
  1163.  
  1164.         if(color_led_address==0) return -ENODEV;
  1165.  
  1166.         data = micropklt_t;
  1167.         if (!data) return -EAGAIN;
  1168.         client = data->client;
  1169.  
  1170.         mutex_lock(&data->lock);
  1171.                 buffer[0] = color_led_address;
  1172.                 buffer[1] = val&0xff;
  1173.                 buffer[2] = (val>>8)&0xff;
  1174.                 buffer[3] = (val>>16)&0xff;
  1175.                 buffer[4] = (val>>32)&0xff;
  1176.         r = micropklt_write(client, buffer, 5);
  1177.         mutex_unlock(&data->lock);
  1178.         return 0;
  1179. }
  1180.  
  1181. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_color_led_fops,
  1182.                 micropklt_dbg_color_led_get,
  1183.                 micropklt_dbg_color_led_set, "%llu\n");
  1184.  
  1185. static int micropklt_dbg_brightness_get(void *dat, u64 *val) {
  1186.         return -EIO;
  1187. }
  1188.  
  1189. static int micropklt_dbg_brightness_set(void *dat, u64 val)
  1190. {
  1191.         struct microp_klt *data;
  1192.         struct i2c_client *client;
  1193.         uint8_t buffer[2] = { 0, 0, };
  1194.         int r;
  1195.  
  1196.         data = micropklt_t;
  1197.         if (!data) return -EAGAIN;
  1198.         client = data->client;
  1199.  
  1200.         mutex_lock(&data->lock);
  1201.                 buffer[0] = 0xcc;
  1202.                 buffer[1] = val;//time ?
  1203.         r = micropklt_write(client, buffer, 2);
  1204.         mutex_unlock(&data->lock);
  1205.         return 0;
  1206. }
  1207.  
  1208.  
  1209. DEFINE_SIMPLE_ATTRIBUTE(micropklt_dbg_brightness_fops,
  1210.                 micropklt_dbg_brightness_get,
  1211.                 micropklt_dbg_brightness_set, "%llu\n");
  1212.  
  1213. static int __init micropklt_dbg_init(void)
  1214. {
  1215.         struct dentry *dent;
  1216.  
  1217.         dent = debugfs_create_dir("micropklt_dbg", 0);
  1218.         if (IS_ERR(dent))
  1219.                 return PTR_ERR(dent);
  1220.  
  1221.         debugfs_create_file("leds", 0444, dent, NULL,
  1222.                         &micropklt_dbg_leds_fops);
  1223.         debugfs_create_file("light", 0444, dent, NULL,
  1224.                         &micropklt_dbg_light_fops);
  1225.         debugfs_create_file("auto_backlight", 0666, dent, NULL,
  1226.                         &micropklt_dbg_auto_bl_fops);
  1227.         debugfs_create_file("sleep_leds", 0666, dent, NULL,
  1228.                         &micropklt_dbg_sleep_fops);
  1229.         debugfs_create_file("sleep_effects", 0666, dent, NULL,
  1230.                         &micropklt_dbg_sl_eff_fops);
  1231.         debugfs_create_file("effects", 0666, dent, NULL,
  1232.                         &micropklt_dbg_effects_fops);
  1233.         debugfs_create_file("color_led", 0666, dent, NULL,
  1234.                         &micropklt_dbg_color_led_fops);
  1235.         debugfs_create_file("brightness", 0666, dent, NULL,
  1236.                         &micropklt_dbg_brightness_fops);
  1237.  
  1238.         debugfs_create_file("gpi", 0444, dent, NULL,
  1239.                         &micropklt_dbg_gpi_fops);
  1240.  
  1241.         return 0;
  1242. }
  1243.  
  1244. device_initcall(micropklt_dbg_init);
  1245. #endif /* CONFIG_DEBUG_FS */