123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262 |
- /* board-mahimahi-microp.c
- * Copyright (C) 2009 Google.
- * Copyright (C) 2009 HTC Corporation.
- *
- * The Microp on mahimahi is an i2c device that supports
- * the following functions
- * - LEDs (Green, Amber, Jogball backlight)
- * - Lightsensor
- * - Headset remotekeys
- * - G-sensor
- * - Interrupts
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/kernel.h>
- #include <linux/platform_device.h>
- #include <linux/slab.h>
- #include <linux/init.h>
- #include <linux/leds.h>
- #include <linux/workqueue.h>
- #include <linux/i2c.h>
- #include <linux/delay.h>
- #include <linux/gpio.h>
- #include <linux/miscdevice.h>
- #include <linux/input.h>
- #include <asm/uaccess.h>
- #include <linux/wakelock.h>
- #include <asm/mach-types.h>
- #include <mach/htc_pwrsink.h>
- #include <linux/earlysuspend.h>
- #include <linux/bma150.h>
- #include <linux/lightsensor.h>
- #include <asm/mach/mmc.h>
- #include <mach/htc_35mm_jack.h>
- #include <asm/setup.h>
- #include <linux/debugfs.h>
- #include <linux/seq_file.h>
- #include <linux/mutex.h>
- #include <linux/jiffies.h>
- #include "board-mahimahi.h"
- #define MICROP_I2C_NAME "mahimahi-microp"
- #define MICROP_LSENSOR_ADC_CHAN 6
- #define MICROP_REMOTE_KEY_ADC_CHAN 7
- #define MICROP_I2C_WCMD_MISC 0x20
- #define MICROP_I2C_WCMD_SPI_EN 0x21
- #define MICROP_I2C_WCMD_AUTO_BL_CTL 0x23
- #define MICROP_I2C_RCMD_SPI_BL_STATUS 0x24
- #define MICROP_I2C_WCMD_BUTTONS_LED_CTRL 0x25
- #define MICROP_I2C_RCMD_VERSION 0x30
- #define MICROP_I2C_WCMD_ADC_TABLE 0x42
- #define MICROP_I2C_WCMD_LED_MODE 0x53
- #define MICROP_I2C_RCMD_GREEN_LED_REMAIN_TIME 0x54
- #define MICROP_I2C_RCMD_AMBER_RED_LED_REMAIN_TIME 0x55
- #define MICROP_I2C_RCMD_BLUE_LED_REMAIN_TIME 0x57
- #define MICROP_I2C_WCMD_JOGBALL_LED_MODE 0x5A
- #define MICROP_I2C_RCMD_JOGBALL_LED_REMAIN_TIME 0x5B
- #define MICROP_I2C_WCMD_JOGBALL_LED_PWM_SET 0x5C
- #define MICROP_I2C_WCMD_JOGBALL_LED_PERIOD_SET 0x5D
- #define MICROP_I2C_WCMD_READ_ADC_VALUE_REQ 0x60
- #define MICROP_I2C_RCMD_ADC_VALUE 0x62
- #define MICROP_I2C_WCMD_REMOTEKEY_TABLE 0x63
- #define MICROP_I2C_WCMD_LCM_REGISTER 0x70
- #define MICROP_I2C_WCMD_GSENSOR_REG 0x73
- #define MICROP_I2C_WCMD_GSENSOR_REG_DATA_REQ 0x74
- #define MICROP_I2C_RCMD_GSENSOR_REG_DATA 0x75
- #define MICROP_I2C_WCMD_GSENSOR_DATA_REQ 0x76
- #define MICROP_I2C_RCMD_GSENSOR_X_DATA 0x77
- #define MICROP_I2C_RCMD_GSENSOR_Y_DATA 0x78
- #define MICROP_I2C_RCMD_GSENSOR_Z_DATA 0x79
- #define MICROP_I2C_RCMD_GSENSOR_DATA 0x7A
- #define MICROP_I2C_WCMD_OJ_REG 0x7B
- #define MICROP_I2C_WCMD_OJ_REG_DATA_REQ 0x7C
- #define MICROP_I2C_RCMD_OJ_REG_DATA 0x7D
- #define MICROP_I2C_WCMD_OJ_POS_DATA_REQ 0x7E
- #define MICROP_I2C_RCMD_OJ_POS_DATA 0x7F
- #define MICROP_I2C_WCMD_GPI_INT_CTL_EN 0x80
- #define MICROP_I2C_WCMD_GPI_INT_CTL_DIS 0x81
- #define MICROP_I2C_RCMD_GPI_INT_STATUS 0x82
- #define MICROP_I2C_RCMD_GPI_STATUS 0x83
- #define MICROP_I2C_WCMD_GPI_INT_STATUS_CLR 0x84
- #define MICROP_I2C_RCMD_GPI_INT_SETTING 0x85
- #define MICROP_I2C_RCMD_REMOTE_KEYCODE 0x87
- #define MICROP_I2C_WCMD_REMOTE_KEY_DEBN_TIME 0x88
- #define MICROP_I2C_WCMD_REMOTE_PLUG_DEBN_TIME 0x89
- #define MICROP_I2C_WCMD_SIMCARD_DEBN_TIME 0x8A
- #define MICROP_I2C_WCMD_GPO_LED_STATUS_EN 0x90
- #define MICROP_I2C_WCMD_GPO_LED_STATUS_DIS 0x91
- #define IRQ_GSENSOR (1<<10)
- #define IRQ_LSENSOR (1<<9)
- #define IRQ_REMOTEKEY (1<<7)
- #define IRQ_HEADSETIN (1<<2)
- #define IRQ_SDCARD (1<<0)
- #define READ_GPI_STATE_HPIN (1<<2)
- #define READ_GPI_STATE_SDCARD (1<<0)
- #define ALS_CALIBRATE_MODE 147
- /* Check pattern, to check if ALS has been calibrated */
- #define ALS_CALIBRATED 0x6DA5
- /* delay for deferred light sensor read */
- #define LS_READ_DELAY (HZ/2)
- /*#define DEBUG_BMA150 */
- #ifdef DEBUG_BMA150
- /* Debug logging of accelleration data */
- #define GSENSOR_LOG_MAX 2048 /* needs to be power of 2 */
- #define GSENSOR_LOG_MASK (GSENSOR_LOG_MAX - 1)
- struct gsensor_log {
- ktime_t timestamp;
- short x;
- short y;
- short z;
- };
- static DEFINE_MUTEX(gsensor_log_lock);
- static struct gsensor_log gsensor_log[GSENSOR_LOG_MAX];
- static unsigned gsensor_log_head;
- static unsigned gsensor_log_tail;
- void gsensor_log_status(ktime_t time, short x, short y, short z)
- {
- unsigned n;
- mutex_lock(&gsensor_log_lock);
- n = gsensor_log_head;
- gsensor_log[n].timestamp = time;
- gsensor_log[n].x = x;
- gsensor_log[n].y = y;
- gsensor_log[n].z = z;
- n = (n + 1) & GSENSOR_LOG_MASK;
- if (n == gsensor_log_tail)
- gsensor_log_tail = (gsensor_log_tail + 1) & GSENSOR_LOG_MASK;
- gsensor_log_head = n;
- mutex_unlock(&gsensor_log_lock);
- }
- static int gsensor_log_print(struct seq_file *sf, void *private)
- {
- unsigned n;
- mutex_lock(&gsensor_log_lock);
- seq_printf(sf, "timestamp X Y Z\n");
- for (n = gsensor_log_tail;
- n != gsensor_log_head;
- n = (n + 1) & GSENSOR_LOG_MASK) {
- seq_printf(sf, "%10d.%010d %6d %6d %6d\n",
- gsensor_log[n].timestamp.tv.sec,
- gsensor_log[n].timestamp.tv.nsec,
- gsensor_log[n].x, gsensor_log[n].y,
- gsensor_log[n].z);
- }
- mutex_unlock(&gsensor_log_lock);
- return 0;
- }
- static int gsensor_log_open(struct inode *inode, struct file *file)
- {
- return single_open(file, gsensor_log_print, NULL);
- }
- static struct file_operations gsensor_log_fops = {
- .open = gsensor_log_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- };
- #endif /* def DEBUG_BMA150 */
- static int microp_headset_has_mic(void);
- static int microp_enable_headset_plug_event(void);
- static int microp_enable_key_event(void);
- static int microp_disable_key_event(void);
- static struct h35mm_platform_data mahimahi_h35mm_data = {
- .plug_event_enable = microp_enable_headset_plug_event,
- .headset_has_mic = microp_headset_has_mic,
- .key_event_enable = microp_enable_key_event,
- .key_event_disable = microp_disable_key_event,
- };
- static struct platform_device mahimahi_h35mm = {
- .name = "htc_headset",
- .id = -1,
- .dev = {
- .platform_data = &mahimahi_h35mm_data,
- },
- };
- enum led_type {
- GREEN_LED,
- AMBER_LED,
- RED_LED,
- BLUE_LED,
- JOGBALL_LED,
- BUTTONS_LED,
- NUM_LEDS,
- };
- static uint16_t lsensor_adc_table[10] = {
- 0x000, 0x001, 0x00F, 0x01E, 0x03C, 0x121, 0x190, 0x2BA, 0x26E, 0x3FF
- };
- static uint16_t remote_key_adc_table[6] = {
- 0, 33, 43, 110, 129, 220
- };
- static uint32_t golden_adc = 0xC0;
- static uint32_t als_kadc;
- static struct wake_lock microp_i2c_wakelock;
- static struct i2c_client *private_microp_client;
- struct microp_int_pin {
- uint16_t int_gsensor;
- uint16_t int_lsensor;
- uint16_t int_reset;
- uint16_t int_simcard;
- uint16_t int_hpin;
- uint16_t int_remotekey;
- };
- struct microp_led_data {
- int type;
- struct led_classdev ldev;
- struct mutex led_data_mutex;
- struct work_struct brightness_work;
- spinlock_t brightness_lock;
- enum led_brightness brightness;
- uint8_t mode;
- uint8_t blink;
- };
- struct microp_i2c_work {
- struct work_struct work;
- struct i2c_client *client;
- int (*intr_debounce)(uint8_t *pin_status);
- void (*intr_function)(uint8_t *pin_status);
- };
- struct microp_i2c_client_data {
- struct microp_led_data leds[NUM_LEDS];
- uint16_t version;
- struct microp_i2c_work work;
- struct delayed_work hpin_debounce_work;
- struct delayed_work ls_read_work;
- struct early_suspend early_suspend;
- uint8_t enable_early_suspend;
- uint8_t enable_reset_button;
- int microp_is_suspend;
- int auto_backlight_enabled;
- uint8_t light_sensor_enabled;
- uint8_t force_light_sensor_read;
- uint8_t button_led_value;
- int headset_is_in;
- int is_hpin_pin_stable;
- struct input_dev *ls_input_dev;
- uint32_t als_kadc;
- uint32_t als_gadc;
- uint8_t als_calibrating;
- };
- static char *hex2string(uint8_t *data, int len)
- {
- static char buf[101];
- int i;
- i = (sizeof(buf) - 1) / 4;
- if (len > i)
- len = i;
- for (i = 0; i < len; i++)
- sprintf(buf + i * 4, "[%02X]", data[i]);
- return buf;
- }
- #define I2C_READ_RETRY_TIMES 10
- #define I2C_WRITE_RETRY_TIMES 10
- static int i2c_read_block(struct i2c_client *client, uint8_t addr,
- uint8_t *data, int length)
- {
- int retry;
- int ret;
- struct i2c_msg msgs[] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = 1,
- .buf = &addr,
- },
- {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = length,
- .buf = data,
- }
- };
- mdelay(1);
- for (retry = 0; retry <= I2C_READ_RETRY_TIMES; retry++) {
- ret = i2c_transfer(client->adapter, msgs, 2);
- if (ret == 2) {
- dev_dbg(&client->dev, "R [%02X] = %s\n", addr,
- hex2string(data, length));
- return 0;
- }
- msleep(10);
- }
- dev_err(&client->dev, "i2c_read_block retry over %d\n",
- I2C_READ_RETRY_TIMES);
- return -EIO;
- }
- #define MICROP_I2C_WRITE_BLOCK_SIZE 21
- static int i2c_write_block(struct i2c_client *client, uint8_t addr,
- uint8_t *data, int length)
- {
- int retry;
- uint8_t buf[MICROP_I2C_WRITE_BLOCK_SIZE];
- int ret;
- struct i2c_msg msg[] = {
- {
- .addr = client->addr,
- .flags = 0,
- .len = length + 1,
- .buf = buf,
- }
- };
- dev_dbg(&client->dev, "W [%02X] = %s\n", addr,
- hex2string(data, length));
- if (length + 1 > MICROP_I2C_WRITE_BLOCK_SIZE) {
- dev_err(&client->dev, "i2c_write_block length too long\n");
- return -E2BIG;
- }
- buf[0] = addr;
- memcpy((void *)&buf[1], (void *)data, length);
- mdelay(1);
- for (retry = 0; retry <= I2C_WRITE_RETRY_TIMES; retry++) {
- ret = i2c_transfer(client->adapter, msg, 1);
- if (ret == 1)
- return 0;
- msleep(10);
- }
- dev_err(&client->dev, "i2c_write_block retry over %d\n",
- I2C_WRITE_RETRY_TIMES);
- return -EIO;
- }
- static int microp_read_adc(uint8_t channel, uint16_t *value)
- {
- struct i2c_client *client;
- int ret;
- uint8_t cmd[2], data[2];
- client = private_microp_client;
- cmd[0] = 0;
- cmd[1] = channel;
- ret = i2c_write_block(client, MICROP_I2C_WCMD_READ_ADC_VALUE_REQ,
- cmd, 2);
- if (ret < 0) {
- dev_err(&client->dev, "%s: request adc fail\n", __func__);
- return -EIO;
- }
- ret = i2c_read_block(client, MICROP_I2C_RCMD_ADC_VALUE, data, 2);
- if (ret < 0) {
- dev_err(&client->dev, "%s: read adc fail\n", __func__);
- return -EIO;
- }
- *value = data[0] << 8 | data[1];
- return 0;
- }
- static int microp_read_gpi_status(struct i2c_client *client, uint16_t *status)
- {
- uint8_t data[2];
- int ret;
- ret = i2c_read_block(client, MICROP_I2C_RCMD_GPI_STATUS, data, 2);
- if (ret < 0) {
- dev_err(&client->dev, "%s: read failed\n", __func__);
- return -EIO;
- }
- *status = (data[0] << 8) | data[1];
- return 0;
- }
- static int microp_interrupt_enable(struct i2c_client *client,
- uint16_t interrupt_mask)
- {
- uint8_t data[2];
- int ret = -1;
- data[0] = interrupt_mask >> 8;
- data[1] = interrupt_mask & 0xFF;
- ret = i2c_write_block(client, MICROP_I2C_WCMD_GPI_INT_CTL_EN, data, 2);
- if (ret < 0)
- dev_err(&client->dev, "%s: enable 0x%x interrupt failed\n",
- __func__, interrupt_mask);
- return ret;
- }
- static int microp_interrupt_disable(struct i2c_client *client,
- uint16_t interrupt_mask)
- {
- uint8_t data[2];
- int ret = -1;
- data[0] = interrupt_mask >> 8;
- data[1] = interrupt_mask & 0xFF;
- ret = i2c_write_block(client, MICROP_I2C_WCMD_GPI_INT_CTL_DIS, data, 2);
- if (ret < 0)
- dev_err(&client->dev, "%s: disable 0x%x interrupt failed\n",
- __func__, interrupt_mask);
- return ret;
- }
- /*
- * SD slot card-detect support
- */
- static unsigned int sdslot_cd = 0;
- static void (*sdslot_status_cb)(int card_present, void *dev_id);
- static void *sdslot_mmc_dev;
- int mahimahi_microp_sdslot_status_register(
- void (*cb)(int card_present, void *dev_id),
- void *dev_id)
- {
- if (sdslot_status_cb)
- return -EBUSY;
- sdslot_status_cb = cb;
- sdslot_mmc_dev = dev_id;
- return 0;
- }
- unsigned int mahimahi_microp_sdslot_status(struct device *dev)
- {
- return sdslot_cd;
- }
- static void mahimahi_microp_sdslot_update_status(int status)
- {
- sdslot_cd = !(status & READ_GPI_STATE_SDCARD);
- if (sdslot_status_cb)
- sdslot_status_cb(sdslot_cd, sdslot_mmc_dev);
- }
- /*
- *Headset Support
- */
- static void hpin_debounce_do_work(struct work_struct *work)
- {
- uint16_t gpi_status = 0;
- struct microp_i2c_client_data *cdata;
- int insert = 0;
- struct i2c_client *client;
- client = private_microp_client;
- cdata = i2c_get_clientdata(client);
- microp_read_gpi_status(client, &gpi_status);
- insert = (gpi_status & READ_GPI_STATE_HPIN) ? 0 : 1;
- if (insert != cdata->headset_is_in) {
- cdata->headset_is_in = insert;
- pr_debug("headset %s\n", insert ? "inserted" : "removed");
- htc_35mm_jack_plug_event(cdata->headset_is_in,
- &cdata->is_hpin_pin_stable);
- }
- }
- static int microp_enable_headset_plug_event(void)
- {
- int ret;
- struct i2c_client *client;
- struct microp_i2c_client_data *cdata;
- uint16_t stat;
- client = private_microp_client;
- cdata = i2c_get_clientdata(client);
- /* enable microp interrupt to detect changes */
- ret = microp_interrupt_enable(client, IRQ_HEADSETIN);
- if (ret < 0) {
- dev_err(&client->dev, "%s: failed to enable irqs\n",
- __func__);
- return 0;
- }
- /* see if headset state has changed */
- microp_read_gpi_status(client, &stat);
- stat = !(stat & READ_GPI_STATE_HPIN);
- if(cdata->headset_is_in != stat) {
- cdata->headset_is_in = stat;
- pr_debug("Headset state changed\n");
- htc_35mm_jack_plug_event(stat, &cdata->is_hpin_pin_stable);
- }
- return 1;
- }
- static int microp_headset_detect_mic(void)
- {
- uint16_t data;
- microp_read_adc(MICROP_REMOTE_KEY_ADC_CHAN, &data);
- if (data >= 200)
- return 1;
- else
- return 0;
- }
- static int microp_headset_has_mic(void)
- {
- int mic1 = -1;
- int mic2 = -1;
- int count = 0;
- mic2 = microp_headset_detect_mic();
- /* debounce the detection wait until 2 consecutive read are equal */
- while ((mic1 != mic2) && (count < 10)) {
- mic1 = mic2;
- msleep(600);
- mic2 = microp_headset_detect_mic();
- count++;
- }
- pr_info("%s: microphone (%d) %s\n", __func__, count,
- mic1 ? "present" : "not present");
- return mic1;
- }
- static int microp_enable_key_event(void)
- {
- int ret;
- struct i2c_client *client;
- client = private_microp_client;
- if (!is_cdma_version(system_rev))
- gpio_set_value(MAHIMAHI_GPIO_35MM_KEY_INT_SHUTDOWN, 1);
- /* turn on key interrupt */
- /* enable microp interrupt to detect changes */
- ret = microp_interrupt_enable(client, IRQ_REMOTEKEY);
- if (ret < 0) {
- dev_err(&client->dev, "%s: failed to enable irqs\n",
- __func__);
- return ret;
- }
- return 0;
- }
- static int microp_disable_key_event(void)
- {
- int ret;
- struct i2c_client *client;
- client = private_microp_client;
- /* shutdown key interrupt */
- if (!is_cdma_version(system_rev))
- gpio_set_value(MAHIMAHI_GPIO_35MM_KEY_INT_SHUTDOWN, 0);
- /* disable microp interrupt to detect changes */
- ret = microp_interrupt_disable(client, IRQ_REMOTEKEY);
- if (ret < 0) {
- dev_err(&client->dev, "%s: failed to disable irqs\n",
- __func__);
- return ret;
- }
- return 0;
- }
- static int get_remote_keycode(int *keycode)
- {
- struct i2c_client *client = private_microp_client;
- int ret;
- uint8_t data[2];
- ret = i2c_read_block(client, MICROP_I2C_RCMD_REMOTE_KEYCODE, data, 2);
- if (ret < 0) {
- dev_err(&client->dev, "%s: read remote keycode fail\n",
- __func__);
- return -EIO;
- }
- pr_debug("%s: key = 0x%x\n", __func__, data[1]);
- if (!data[1]) {
- *keycode = 0;
- return 1; /* no keycode */
- } else {
- *keycode = data[1];
- }
- return 0;
- }
- static ssize_t microp_i2c_remotekey_adc_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct i2c_client *client;
- uint16_t value;
- int i, button = 0;
- int ret;
- client = to_i2c_client(dev);
- microp_read_adc(MICROP_REMOTE_KEY_ADC_CHAN, &value);
- for (i = 0; i < 3; i++) {
- if ((value >= remote_key_adc_table[2 * i]) &&
- (value <= remote_key_adc_table[2 * i + 1])) {
- button = i + 1;
- }
- }
- ret = sprintf(buf, "Remote Key[0x%03X] => button %d\n",
- value, button);
- return ret;
- }
- static DEVICE_ATTR(key_adc, 0644, microp_i2c_remotekey_adc_show, NULL);
- /*
- * LED support
- */
- static int microp_i2c_write_led_mode(struct i2c_client *client,
- struct led_classdev *led_cdev,
- uint8_t mode, uint16_t off_timer)
- {
- struct microp_i2c_client_data *cdata;
- struct microp_led_data *ldata;
- uint8_t data[7];
- int ret;
- cdata = i2c_get_clientdata(client);
- ldata = container_of(led_cdev, struct microp_led_data, ldev);
- if (ldata->type == GREEN_LED) {
- data[0] = 0x01;
- data[1] = mode;
- data[2] = off_timer >> 8;
- data[3] = off_timer & 0xFF;
- data[4] = 0x00;
- data[5] = 0x00;
- data[6] = 0x00;
- } else if (ldata->type == AMBER_LED) {
- data[0] = 0x02;
- data[1] = 0x00;
- data[2] = 0x00;
- data[3] = 0x00;
- data[4] = mode;
- data[5] = off_timer >> 8;
- data[6] = off_timer & 0xFF;
- } else if (ldata->type == RED_LED) {
- data[0] = 0x02;
- data[1] = 0x00;
- data[2] = 0x00;
- data[3] = 0x00;
- data[4] = mode? 5: 0;
- data[5] = off_timer >> 8;
- data[6] = off_timer & 0xFF;
- } else if (ldata->type == BLUE_LED) {
- data[0] = 0x04;
- data[1] = mode;
- data[2] = off_timer >> 8;
- data[3] = off_timer & 0xFF;
- data[4] = 0x00;
- data[5] = 0x00;
- data[6] = 0x00;
- }
- ret = i2c_write_block(client, MICROP_I2C_WCMD_LED_MODE, data, 7);
- if (ret == 0) {
- mutex_lock(&ldata->led_data_mutex);
- if (mode > 1)
- ldata->blink = mode;
- else
- ldata->mode = mode;
- mutex_unlock(&ldata->led_data_mutex);
- }
- return ret;
- }
- static ssize_t microp_i2c_led_blink_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct led_classdev *led_cdev;
- struct microp_led_data *ldata;
- int ret;
- led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
- ldata = container_of(led_cdev, struct microp_led_data, ldev);
- mutex_lock(&ldata->led_data_mutex);
- ret = sprintf(buf, "%d\n", ldata->blink ? ldata->blink - 1 : 0);
- mutex_unlock(&ldata->led_data_mutex);
- return ret;
- }
- static ssize_t microp_i2c_led_blink_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct led_classdev *led_cdev;
- struct microp_led_data *ldata;
- struct i2c_client *client;
- int val, ret;
- uint8_t mode;
- val = -1;
- sscanf(buf, "%u", &val);
- led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
- ldata = container_of(led_cdev, struct microp_led_data, ldev);
- client = to_i2c_client(dev->parent);
- mutex_lock(&ldata->led_data_mutex);
- switch (val) {
- case 0: /* stop flashing */
- mode = ldata->mode;
- ldata->blink = 0;
- break;
- case 1:
- case 2:
- case 3:
- mode = val + 1;
- break;
- default:
- mutex_unlock(&ldata->led_data_mutex);
- return -EINVAL;
- }
- mutex_unlock(&ldata->led_data_mutex);
- ret = microp_i2c_write_led_mode(client, led_cdev, mode, 0xffff);
- if (ret)
- dev_err(&client->dev, "%s set blink failed\n", led_cdev->name);
- return count;
- }
- static DEVICE_ATTR(blink, 0644, microp_i2c_led_blink_show,
- microp_i2c_led_blink_store);
- static ssize_t microp_i2c_led_off_timer_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct microp_i2c_client_data *cdata;
- struct led_classdev *led_cdev;
- struct microp_led_data *ldata;
- struct i2c_client *client;
- uint8_t data[2];
- int ret, offtime;
- led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
- ldata = container_of(led_cdev, struct microp_led_data, ldev);
- client = to_i2c_client(dev->parent);
- cdata = i2c_get_clientdata(client);
- dev_dbg(&client->dev, "Getting %s remaining time\n", led_cdev->name);
- if (ldata->type == GREEN_LED) {
- ret = i2c_read_block(client,
- MICROP_I2C_RCMD_GREEN_LED_REMAIN_TIME, data, 2);
- } else if (ldata->type == AMBER_LED) {
- ret = i2c_read_block(client,
- MICROP_I2C_RCMD_AMBER_RED_LED_REMAIN_TIME,
- data, 2);
- } else if (ldata->type == RED_LED) {
- ret = i2c_read_block(client,
- MICROP_I2C_RCMD_AMBER_RED_LED_REMAIN_TIME,
- data, 2);
- } else if (ldata->type == BLUE_LED) {
- ret = i2c_read_block(client,
- MICROP_I2C_RCMD_BLUE_LED_REMAIN_TIME, data, 2);
- } else {
- dev_err(&client->dev, "Unknown led %s\n", ldata->ldev.name);
- return -EINVAL;
- }
- if (ret) {
- dev_err(&client->dev,
- "%s get off_timer failed\n", led_cdev->name);
- }
- offtime = (int)((data[1] | data[0] << 8) * 2);
- ret = sprintf(buf, "Time remains %d:%d\n", offtime / 60, offtime % 60);
- return ret;
- }
- static ssize_t microp_i2c_led_off_timer_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct led_classdev *led_cdev;
- struct microp_led_data *ldata;
- struct i2c_client *client;
- int min, sec, ret;
- uint16_t off_timer;
- min = -1;
- sec = -1;
- sscanf(buf, "%d %d", &min, &sec);
- if (min < 0 || min > 255)
- return -EINVAL;
- if (sec < 0 || sec > 255)
- return -EINVAL;
- led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
- ldata = container_of(led_cdev, struct microp_led_data, ldev);
- client = to_i2c_client(dev->parent);
- dev_dbg(&client->dev, "Setting %s off_timer to %d min %d sec\n",
- led_cdev->name, min, sec);
- if (!min && !sec)
- off_timer = 0xFFFF;
- else
- off_timer = (min * 60 + sec) / 2;
- ret = microp_i2c_write_led_mode(client, led_cdev,
- ldata->mode, off_timer);
- if (ret) {
- dev_err(&client->dev,
- "%s set off_timer %d min %d sec failed\n",
- led_cdev->name, min, sec);
- }
- return count;
- }
- static DEVICE_ATTR(off_timer, 0644, microp_i2c_led_off_timer_show,
- microp_i2c_led_off_timer_store);
- static ssize_t microp_i2c_jogball_color_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct led_classdev *led_cdev;
- struct microp_led_data *ldata;
- struct i2c_client *client;
- int rpwm, gpwm, bpwm, ret;
- uint8_t data[4];
- rpwm = -1;
- gpwm = -1;
- bpwm = -1;
- sscanf(buf, "%d %d %d", &rpwm, &gpwm, &bpwm);
- if (rpwm < 0 || rpwm > 255)
- return -EINVAL;
- if (gpwm < 0 || gpwm > 255)
- return -EINVAL;
- if (bpwm < 0 || bpwm > 255)
- return -EINVAL;
- led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
- ldata = container_of(led_cdev, struct microp_led_data, ldev);
- client = to_i2c_client(dev->parent);
- dev_dbg(&client->dev, "Setting %s color to R=%d, G=%d, B=%d\n",
- led_cdev->name, rpwm, gpwm, bpwm);
- data[0] = rpwm;
- data[1] = gpwm;
- data[2] = bpwm;
- data[3] = 0x00;
- ret = i2c_write_block(client, MICROP_I2C_WCMD_JOGBALL_LED_PWM_SET,
- data, 4);
- if (ret) {
- dev_err(&client->dev,
- "%s set color R=%d G=%d B=%d failed\n",
- led_cdev->name, rpwm, gpwm, bpwm);
- }
- return count;
- }
- static DEVICE_ATTR(color, 0644, NULL, microp_i2c_jogball_color_store);
- static ssize_t microp_i2c_jogball_period_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct led_classdev *led_cdev;
- struct microp_led_data *ldata;
- struct i2c_client *client;
- int period = -1;
- int ret;
- uint8_t data[4];
- sscanf(buf, "%d", &period);
- if (period < 2 || period > 12)
- return -EINVAL;
- led_cdev = (struct led_classdev *)dev_get_drvdata(dev);
- ldata = container_of(led_cdev, struct microp_led_data, ldev);
- client = to_i2c_client(dev->parent);
- dev_info(&client->dev, "Setting Jogball flash period to %d\n", period);
- data[0] = 0x00;
- data[1] = period;
- ret = i2c_write_block(client, MICROP_I2C_WCMD_JOGBALL_LED_PERIOD_SET,
- data, 2);
- if (ret) {
- dev_err(&client->dev, "%s set period=%d failed\n",
- led_cdev->name, period);
- }
- return count;
- }
- static DEVICE_ATTR(period, 0644, NULL, microp_i2c_jogball_period_store);
- static void microp_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
- {
- unsigned long flags;
- struct i2c_client *client = to_i2c_client(led_cdev->dev->parent);
- struct microp_led_data *ldata =
- container_of(led_cdev, struct microp_led_data, ldev);
- dev_dbg(&client->dev, "Setting %s brightness current %d new %d\n",
- led_cdev->name, led_cdev->brightness, brightness);
- if (brightness > 255)
- brightness = 255;
- led_cdev->brightness = brightness;
- spin_lock_irqsave(&ldata->brightness_lock, flags);
- ldata->brightness = brightness;
- spin_unlock_irqrestore(&ldata->brightness_lock, flags);
- schedule_work(&ldata->brightness_work);
- }
- static void microp_led_brightness_set_work(struct work_struct *work)
- {
- unsigned long flags;
- struct microp_led_data *ldata =
- container_of(work, struct microp_led_data, brightness_work);
- struct led_classdev *led_cdev = &ldata->ldev;
- struct i2c_client *client = to_i2c_client(led_cdev->dev->parent);
- enum led_brightness brightness;
- int ret;
- uint8_t mode;
- spin_lock_irqsave(&ldata->brightness_lock, flags);
- brightness = ldata->brightness;
- spin_unlock_irqrestore(&ldata->brightness_lock, flags);
- if (brightness)
- mode = 1;
- else
- mode = 0;
- ret = microp_i2c_write_led_mode(client, led_cdev, mode, 0xffff);
- if (ret) {
- dev_err(&client->dev,
- "led_brightness_set failed to set mode\n");
- }
- }
- struct device_attribute *green_amber_attrs[] = {
- &dev_attr_blink,
- &dev_attr_off_timer,
- };
- struct device_attribute *jogball_attrs[] = {
- &dev_attr_color,
- &dev_attr_period,
- };
- static void microp_led_buttons_brightness_set_work(struct work_struct *work)
- {
- unsigned long flags;
- struct microp_led_data *ldata =
- container_of(work, struct microp_led_data, brightness_work);
- struct led_classdev *led_cdev = &ldata->ldev;
- struct i2c_client *client = to_i2c_client(led_cdev->dev->parent);
- struct microp_i2c_client_data *cdata = i2c_get_clientdata(client);
- uint8_t data[4] = {0, 0, 0};
- int ret = 0;
- enum led_brightness brightness;
- uint8_t value;
- spin_lock_irqsave(&ldata->brightness_lock, flags);
- brightness = ldata->brightness;
- spin_unlock_irqrestore(&ldata->brightness_lock, flags);
- value = brightness >= 255 ? 0x20 : 0;
- /* avoid a flicker that can occur when writing the same value */
- if (cdata->button_led_value == value)
- return;
- cdata->button_led_value = value;
- /* in 40ms */
- data[0] = 0x05;
- /* duty cycle 0-255 */
- data[1] = value;
- /* bit2 == change brightness */
- data[3] = 0x04;
- ret = i2c_write_block(client, MICROP_I2C_WCMD_BUTTONS_LED_CTRL,
- data, 4);
- if (ret < 0)
- dev_err(&client->dev, "%s failed on set buttons\n", __func__);
- }
- static void microp_led_jogball_brightness_set_work(struct work_struct *work)
- {
- unsigned long flags;
- struct microp_led_data *ldata =
- container_of(work, struct microp_led_data, brightness_work);
- struct led_classdev *led_cdev = &ldata->ldev;
- struct i2c_client *client = to_i2c_client(led_cdev->dev->parent);
- uint8_t data[3] = {0, 0, 0};
- int ret = 0;
- enum led_brightness brightness;
- spin_lock_irqsave(&ldata->brightness_lock, flags);
- brightness = ldata->brightness;
- spin_unlock_irqrestore(&ldata->brightness_lock, flags);
- switch (brightness) {
- case 0:
- data[0] = 0;
- break;
- case 3:
- data[0] = 1;
- data[1] = data[2] = 0xFF;
- break;
- case 7:
- data[0] = 2;
- data[1] = 0;
- data[2] = 60;
- break;
- default:
- dev_warn(&client->dev, "%s: unknown value: %d\n",
- __func__, brightness);
- break;
- }
- ret = i2c_write_block(client, MICROP_I2C_WCMD_JOGBALL_LED_MODE,
- data, 3);
- if (ret < 0)
- dev_err(&client->dev, "%s failed on set jogball mode:0x%2.2X\n",
- __func__, data[0]);
- }
- /*
- * Light Sensor Support
- */
- static int microp_i2c_auto_backlight_mode(struct i2c_client *client,
- uint8_t enabled)
- {
- uint8_t data[2];
- int ret = 0;
- data[0] = 0;
- if (enabled)
- data[1] = 1;
- else
- data[1] = 0;
- ret = i2c_write_block(client, MICROP_I2C_WCMD_AUTO_BL_CTL, data, 2);
- if (ret != 0)
- pr_err("%s: set auto light sensor fail\n", __func__);
- return ret;
- }
- static int lightsensor_enable(void)
- {
- struct i2c_client *client;
- struct microp_i2c_client_data *cdata;
- int ret;
- client = private_microp_client;
- cdata = i2c_get_clientdata(client);
- if (cdata->microp_is_suspend) {
- pr_err("%s: abort, uP is going to suspend after #\n",
- __func__);
- return -EIO;
- }
- disable_irq(client->irq);
- ret = microp_i2c_auto_backlight_mode(client, 1);
- if (ret < 0) {
- pr_err("%s: set auto light sensor fail\n", __func__);
- enable_irq(client->irq);
- return ret;
- }
- cdata->auto_backlight_enabled = 1;
- /* TEMPORARY HACK: schedule a deferred light sensor read
- * to work around sensor manager race condition
- */
- schedule_delayed_work(&cdata->ls_read_work, LS_READ_DELAY);
- schedule_work(&cdata->work.work);
- return 0;
- }
- static int lightsensor_disable(void)
- {
- /* update trigger data when done */
- struct i2c_client *client;
- struct microp_i2c_client_data *cdata;
- int ret;
- client = private_microp_client;
- cdata = i2c_get_clientdata(client);
- if (cdata->microp_is_suspend) {
- pr_err("%s: abort, uP is going to suspend after #\n",
- __func__);
- return -EIO;
- }
- cancel_delayed_work(&cdata->ls_read_work);
- ret = microp_i2c_auto_backlight_mode(client, 0);
- if (ret < 0)
- pr_err("%s: disable auto light sensor fail\n",
- __func__);
- else
- cdata->auto_backlight_enabled = 0;
- return 0;
- }
- static int microp_lightsensor_read(uint16_t *adc_value,
- uint8_t *adc_level)
- {
- struct i2c_client *client;
- struct microp_i2c_client_data *cdata;
- uint8_t i;
- int ret;
- client = private_microp_client;
- cdata = i2c_get_clientdata(client);
- ret = microp_read_adc(MICROP_LSENSOR_ADC_CHAN, adc_value);
- if (ret != 0)
- return -1;
- if (*adc_value > 0x3FF) {
- pr_warning("%s: get wrong value: 0x%X\n",
- __func__, *adc_value);
- return -1;
- } else {
- if (!cdata->als_calibrating) {
- *adc_value = *adc_value
- * cdata->als_gadc / cdata->als_kadc;
- if (*adc_value > 0x3FF)
- *adc_value = 0x3FF;
- }
- *adc_level = ARRAY_SIZE(lsensor_adc_table) - 1;
- for (i = 0; i < ARRAY_SIZE(lsensor_adc_table); i++) {
- if (*adc_value <= lsensor_adc_table[i]) {
- *adc_level = i;
- break;
- }
- }
- pr_debug("%s: ADC value: 0x%X, level: %d #\n",
- __func__, *adc_value, *adc_level);
- }
- return 0;
- }
- static ssize_t microp_i2c_lightsensor_adc_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- uint8_t adc_level = 0;
- uint16_t adc_value = 0;
- int ret;
- ret = microp_lightsensor_read(&adc_value, &adc_level);
- ret = sprintf(buf, "ADC[0x%03X] => level %d\n", adc_value, adc_level);
- return ret;
- }
- static DEVICE_ATTR(ls_adc, 0644, microp_i2c_lightsensor_adc_show, NULL);
- static ssize_t microp_i2c_ls_auto_show(struct device *dev,
- struct device_attribute *attr, char *buf)
- {
- struct i2c_client *client;
- uint8_t data[2] = {0, 0};
- int ret;
- client = to_i2c_client(dev);
- i2c_read_block(client, MICROP_I2C_RCMD_SPI_BL_STATUS, data, 2);
- ret = sprintf(buf, "Light sensor Auto = %d, SPI enable = %d\n",
- data[0], data[1]);
- return ret;
- }
- static ssize_t microp_i2c_ls_auto_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
- {
- struct i2c_client *client;
- struct microp_i2c_client_data *cdata;
- uint8_t enable = 0;
- int ls_auto;
- ls_auto = -1;
- sscanf(buf, "%d", &ls_auto);
- if (ls_auto != 0 && ls_auto != 1 && ls_auto != ALS_CALIBRATE_MODE)
- return -EINVAL;
- client = to_i2c_client(dev);
- cdata = i2c_get_clientdata(client);
- if (ls_auto) {
- enable = 1;
- cdata->als_calibrating = (ls_auto == ALS_CALIBRATE_MODE) ? 1 : 0;
- cdata->auto_backlight_enabled = 1;
- } else {
- enable = 0;
- cdata->als_calibrating = 0;
- cdata->auto_backlight_enabled = 0;
- }
- microp_i2c_auto_backlight_mode(client, enable);
- return count;
- }
- static DEVICE_ATTR(ls_auto, 0644, microp_i2c_ls_auto_show,
- microp_i2c_ls_auto_store);
- DEFINE_MUTEX(api_lock);
- static int lightsensor_opened;
- static int lightsensor_open(struct inode *inode, struct file *file)
- {
- int rc = 0;
- pr_debug("%s\n", __func__);
- mutex_lock(&api_lock);
- if (lightsensor_opened) {
- pr_err("%s: already opened\n", __func__);
- rc = -EBUSY;
- }
- lightsensor_opened = 1;
- mutex_unlock(&api_lock);
- return rc;
- }
- static int lightsensor_release(struct inode *inode, struct file *file)
- {
- pr_debug("%s\n", __func__);
- mutex_lock(&api_lock);
- lightsensor_opened = 0;
- mutex_unlock(&api_lock);
- return 0;
- }
- static long lightsensor_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
- {
- int rc, val;
- struct i2c_client *client;
- struct microp_i2c_client_data *cdata;
- mutex_lock(&api_lock);
- client = private_microp_client;
- cdata = i2c_get_clientdata(client);
- pr_debug("%s cmd %d\n", __func__, _IOC_NR(cmd));
- switch (cmd) {
- case LIGHTSENSOR_IOCTL_ENABLE:
- if (get_user(val, (unsigned long __user *)arg)) {
- rc = -EFAULT;
- break;
- }
- rc = val ? lightsensor_enable() : lightsensor_disable();
- break;
- case LIGHTSENSOR_IOCTL_GET_ENABLED:
- val = cdata->auto_backlight_enabled;
- pr_debug("%s enabled %d\n", __func__, val);
- rc = put_user(val, (unsigned long __user *)arg);
- break;
- default:
- pr_err("%s: invalid cmd %d\n", __func__, _IOC_NR(cmd));
- rc = -EINVAL;
- }
- mutex_unlock(&api_lock);
- return rc;
- }
- static struct file_operations lightsensor_fops = {
- .owner = THIS_MODULE,
- .open = lightsensor_open,
- .release = lightsensor_release,
- .unlocked_ioctl = lightsensor_ioctl
- };
- struct miscdevice lightsensor_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "lightsensor",
- .fops = &lightsensor_fops
- };
- /*
- * G-sensor
- */
- static int microp_spi_enable(uint8_t on)
- {
- struct i2c_client *client;
- int ret;
- client = private_microp_client;
- ret = i2c_write_block(client, MICROP_I2C_WCMD_SPI_EN, &on, 1);
- if (ret < 0) {
- dev_err(&client->dev,"%s: i2c_write_block fail\n", __func__);
- return ret;
- }
- msleep(10);
- return ret;
- }
- static int gsensor_read_reg(uint8_t reg, uint8_t *data)
- {
- struct i2c_client *client;
- int ret;
- uint8_t tmp[2];
- client = private_microp_client;
- ret = i2c_write_block(client, MICROP_I2C_WCMD_GSENSOR_REG_DATA_REQ,
- ®, 1);
- if (ret < 0) {
- dev_err(&client->dev,"%s: i2c_write_block fail\n", __func__);
- return ret;
- }
- msleep(10);
- ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_REG_DATA, tmp, 2);
- if (ret < 0) {
- dev_err(&client->dev,"%s: i2c_read_block fail\n", __func__);
- return ret;
- }
- *data = tmp[1];
- return ret;
- }
- static int gsensor_write_reg(uint8_t reg, uint8_t data)
- {
- struct i2c_client *client;
- int ret;
- uint8_t tmp[2];
- client = private_microp_client;
- tmp[0] = reg;
- tmp[1] = data;
- ret = i2c_write_block(client, MICROP_I2C_WCMD_GSENSOR_REG, tmp, 2);
- if (ret < 0) {
- dev_err(&client->dev,"%s: i2c_write_block fail\n", __func__);
- return ret;
- }
- return ret;
- }
- static int gsensor_read_acceleration(short *buf)
- {
- struct i2c_client *client;
- int ret;
- uint8_t tmp[6];
- struct microp_i2c_client_data *cdata;
- client = private_microp_client;
- cdata = i2c_get_clientdata(client);
- tmp[0] = 1;
- ret = i2c_write_block(client, MICROP_I2C_WCMD_GSENSOR_DATA_REQ,
- tmp, 1);
- if (ret < 0) {
- dev_err(&client->dev,"%s: i2c_write_block fail\n", __func__);
- return ret;
- }
- msleep(10);
- if (cdata->version <= 0x615) {
- /*
- * Note the data is a 10bit signed value from the chip.
- */
- ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_X_DATA,
- tmp, 2);
- if (ret < 0) {
- dev_err(&client->dev, "%s: i2c_read_block fail\n",
- __func__);
- return ret;
- }
- buf[0] = (short)(tmp[0] << 8 | tmp[1]);
- buf[0] >>= 6;
- ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_Y_DATA,
- tmp, 2);
- if (ret < 0) {
- dev_err(&client->dev, "%s: i2c_read_block fail\n",
- __func__);
- return ret;
- }
- buf[1] = (short)(tmp[0] << 8 | tmp[1]);
- buf[1] >>= 6;
- ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_Z_DATA,
- tmp, 2);
- if (ret < 0) {
- dev_err(&client->dev, "%s: i2c_read_block fail\n",
- __func__);
- return ret;
- }
- buf[2] = (short)(tmp[0] << 8 | tmp[1]);
- buf[2] >>= 6;
- } else {
- ret = i2c_read_block(client, MICROP_I2C_RCMD_GSENSOR_DATA,
- tmp, 6);
- if (ret < 0) {
- dev_err(&client->dev, "%s: i2c_read_block fail\n",
- __func__);
- return ret;
- }
- buf[0] = (short)(tmp[0] << 8 | tmp[1]);
- buf[0] >>= 6;
- buf[1] = (short)(tmp[2] << 8 | tmp[3]);
- buf[1] >>= 6;
- buf[2] = (short)(tmp[4] << 8 | tmp[5]);
- buf[2] >>= 6;
- }
- #ifdef DEBUG_BMA150
- /* Log this to debugfs */
- gsensor_log_status(ktime_get(), buf[0], buf[1], buf[2]);
- #endif
- return 1;
- }
- static int gsensor_init_hw(void)
- {
- uint8_t reg;
- int ret;
- pr_debug("%s\n", __func__);
- microp_spi_enable(1);
- ret = gsensor_read_reg(RANGE_BWIDTH_REG, ®);
- if (ret < 0 )
- return -EIO;
- reg &= 0xe0;
- ret = gsensor_write_reg(RANGE_BWIDTH_REG, reg);
- if (ret < 0 )
- return -EIO;
- ret = gsensor_read_reg(SMB150_CONF2_REG, ®);
- if (ret < 0 )
- return -EIO;
- reg |= (1 << 3);
- ret = gsensor_write_reg(SMB150_CONF2_REG, reg);
- return ret;
- }
- static int bma150_set_mode(char mode)
- {
- uint8_t reg;
- int ret;
- pr_debug("%s mode = %d\n", __func__, mode);
- if (mode == BMA_MODE_NORMAL)
- microp_spi_enable(1);
- ret = gsensor_read_reg(SMB150_CTRL_REG, ®);
- if (ret < 0 )
- return -EIO;
- reg = (reg & 0xfe) | mode;
- ret = gsensor_write_reg(SMB150_CTRL_REG, reg);
- if (mode == BMA_MODE_SLEEP)
- microp_spi_enable(0);
- return ret;
- }
- static int gsensor_read(uint8_t *data)
- {
- int ret;
- uint8_t reg = data[0];
- ret = gsensor_read_reg(reg, &data[1]);
- pr_debug("%s reg = %x data = %x\n", __func__, reg, data[1]);
- return ret;
- }
- static int gsensor_write(uint8_t *data)
- {
- int ret;
- uint8_t reg = data[0];
- pr_debug("%s reg = %x data = %x\n", __func__, reg, data[1]);
- ret = gsensor_write_reg(reg, data[1]);
- return ret;
- }
- static int bma150_open(struct inode *inode, struct file *file)
- {
- pr_debug("%s\n", __func__);
- return nonseekable_open(inode, file);
- }
- static int bma150_release(struct inode *inode, struct file *file)
- {
- return 0;
- }
- static int bma150_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
- {
- void __user *argp = (void __user *)arg;
- char rwbuf[8];
- int ret = -1;
- short buf[8], temp;
- switch (cmd) {
- case BMA_IOCTL_READ:
- case BMA_IOCTL_WRITE:
- case BMA_IOCTL_SET_MODE:
- if (copy_from_user(&rwbuf, argp, sizeof(rwbuf)))
- return -EFAULT;
- break;
- case BMA_IOCTL_READ_ACCELERATION:
- if (copy_from_user(&buf, argp, sizeof(buf)))
- return -EFAULT;
- break;
- default:
- break;
- }
- switch (cmd) {
- case BMA_IOCTL_INIT:
- ret = gsensor_init_hw();
- if (ret < 0)
- return ret;
- break;
- case BMA_IOCTL_READ:
- if (rwbuf[0] < 1)
- return -EINVAL;
- ret = gsensor_read(rwbuf);
- if (ret < 0)
- return ret;
- break;
- case BMA_IOCTL_WRITE:
- if (rwbuf[0] < 2)
- return -EINVAL;
- ret = gsensor_write(rwbuf);
- if (ret < 0)
- return ret;
- break;
- case BMA_IOCTL_READ_ACCELERATION:
- ret = gsensor_read_acceleration(&buf[0]);
- if (ret < 0)
- return ret;
- break;
- case BMA_IOCTL_SET_MODE:
- bma150_set_mode(rwbuf[0]);
- break;
- case BMA_IOCTL_GET_INT:
- temp = 0;
- break;
- default:
- return -ENOTTY;
- }
- switch (cmd) {
- case BMA_IOCTL_READ:
- if (copy_to_user(argp, &rwbuf, sizeof(rwbuf)))
- return -EFAULT;
- break;
- case BMA_IOCTL_READ_ACCELERATION:
- if (copy_to_user(argp, &buf, sizeof(buf)))
- return -EFAULT;
- break;
- case BMA_IOCTL_GET_INT:
- if (copy_to_user(argp, &temp, sizeof(temp)))
- return -EFAULT;
- break;
- default:
- break;
- }
- return 0;
- }
- static struct file_operations bma_fops = {
- .owner = THIS_MODULE,
- .open = bma150_open,
- .release = bma150_release,
- .ioctl = bma150_ioctl,
- };
- static struct miscdevice spi_bma_device = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = BMA150_G_SENSOR_NAME,
- .fops = &bma_fops,
- };
- /*
- * Interrupt
- */
- static irqreturn_t microp_i2c_intr_irq_handler(int irq, void *dev_id)
- {
- struct i2c_client *client;
- struct microp_i2c_client_data *cdata;
- client = to_i2c_client(dev_id);
- cdata = i2c_get_clientdata(client);
- dev_dbg(&client->dev, "intr_irq_handler\n");
- disable_irq_nosync(client->irq);
- schedule_work(&cdata->work.work);
- return IRQ_HANDLED;
- }
- static void microp_i2c_intr_work_func(struct work_struct *work)
- {
- struct microp_i2c_work *up_work;
- struct i2c_client *client;
- struct microp_i2c_client_data *cdata;
- uint8_t data[3], adc_level;
- uint16_t intr_status = 0, adc_value, gpi_status = 0;
- int keycode = 0, ret = 0;
- up_work = container_of(work, struct microp_i2c_work, work);
- client = up_work->client;
- cdata = i2c_get_clientdata(client);
- ret = i2c_read_block(client, MICROP_I2C_RCMD_GPI_INT_STATUS, data, 2);
- if (ret < 0) {
- dev_err(&client->dev, "%s: read interrupt status fail\n",
- __func__);
- }
- intr_status = data[0]<<8 | data[1];
- ret = i2c_write_block(client, MICROP_I2C_WCMD_GPI_INT_STATUS_CLR,
- data, 2);
- if (ret < 0) {
- dev_err(&client->dev, "%s: clear interrupt status fail\n",
- __func__);
- }
- pr_debug("intr_status=0x%02x\n", intr_status);
- if ((intr_status & IRQ_LSENSOR) || cdata->force_light_sensor_read) {
- ret = microp_lightsensor_read(&adc_value, &adc_level);
- if (cdata->force_light_sensor_read) {
- /* report an invalid value first to ensure we trigger an event
- * when adc_level is zero.
- */
- input_report_abs(cdata->ls_input_dev, ABS_MISC, -1);
- input_sync(cdata->ls_input_dev);
- cdata->force_light_sensor_read = 0;
- }
- input_report_abs(cdata->ls_input_dev, ABS_MISC, (int)adc_level);
- input_sync(cdata->ls_input_dev);
- }
- if (intr_status & IRQ_SDCARD) {
- microp_read_gpi_status(client, &gpi_status);
- mahimahi_microp_sdslot_update_status(gpi_status);
- }
- if (intr_status & IRQ_HEADSETIN) {
- cdata->is_hpin_pin_stable = 0;
- wake_lock_timeout(µp_i2c_wakelock, 3*HZ);
- if (!cdata->headset_is_in)
- schedule_delayed_work(&cdata->hpin_debounce_work,
- msecs_to_jiffies(500));
- else
- schedule_delayed_work(&cdata->hpin_debounce_work,
- msecs_to_jiffies(300));
- }
- if (intr_status & IRQ_REMOTEKEY) {
- if ((get_remote_keycode(&keycode) == 0) &&
- (cdata->is_hpin_pin_stable)) {
- htc_35mm_key_event(keycode, &cdata->is_hpin_pin_stable);
- }
- }
- enable_irq(client->irq);
- }
- static void ls_read_do_work(struct work_struct *work)
- {
- struct i2c_client *client = private_microp_client;
- struct microp_i2c_client_data *cdata = i2c_get_clientdata(client);
- /* force a light sensor reading */
- disable_irq(client->irq);
- cdata->force_light_sensor_read = 1;
- schedule_work(&cdata->work.work);
- }
- static int microp_function_initialize(struct i2c_client *client)
- {
- struct microp_i2c_client_data *cdata;
- uint8_t data[20];
- uint16_t stat, interrupts = 0;
- int i;
- int ret;
- struct led_classdev *led_cdev;
- cdata = i2c_get_clientdata(client);
- /* Light Sensor */
- if (als_kadc >> 16 == ALS_CALIBRATED)
- cdata->als_kadc = als_kadc & 0xFFFF;
- else {
- cdata->als_kadc = 0;
- pr_info("%s: no ALS calibrated\n", __func__);
- }
- if (cdata->als_kadc && golden_adc) {
- cdata->als_kadc =
- (cdata->als_kadc > 0 && cdata->als_kadc < 0x400)
- ? cdata->als_kadc : golden_adc;
- cdata->als_gadc =
- (golden_adc > 0)
- ? golden_adc : cdata->als_kadc;
- } else {
- cdata->als_kadc = 1;
- cdata->als_gadc = 1;
- }
- pr_info("%s: als_kadc=0x%x, als_gadc=0x%x\n",
- __func__, cdata->als_kadc, cdata->als_gadc);
- for (i = 0; i < 10; i++) {
- data[i] = (uint8_t)(lsensor_adc_table[i]
- * cdata->als_kadc / cdata->als_gadc >> 8);
- data[i + 10] = (uint8_t)(lsensor_adc_table[i]
- * cdata->als_kadc / cdata->als_gadc);
- }
- ret = i2c_write_block(client, MICROP_I2C_WCMD_ADC_TABLE, data, 20);
- if (ret)
- goto exit;
- ret = gpio_request(MAHIMAHI_GPIO_LS_EN_N, "microp_i2c");
- if (ret < 0) {
- dev_err(&client->dev, "failed on request gpio ls_on\n");
- goto exit;
- }
- ret = gpio_direction_output(MAHIMAHI_GPIO_LS_EN_N, 0);
- if (ret < 0) {
- dev_err(&client->dev, "failed on gpio_direction_output"
- "ls_on\n");
- goto err_gpio_ls;
- }
- cdata->light_sensor_enabled = 1;
- /* Headset */
- for (i = 0; i < 6; i++) {
- data[i] = (uint8_t)(remote_key_adc_table[i] >> 8);
- data[i + 6] = (uint8_t)(remote_key_adc_table[i]);
- }
- ret = i2c_write_block(client,
- MICROP_I2C_WCMD_REMOTEKEY_TABLE, data, 12);
- if (ret)
- goto exit;
- INIT_DELAYED_WORK(
- &cdata->hpin_debounce_work, hpin_debounce_do_work);
- INIT_DELAYED_WORK(
- &cdata->ls_read_work, ls_read_do_work);
- /* SD Card */
- interrupts |= IRQ_SDCARD;
- /* set LED initial state */
- for (i = 0; i < BLUE_LED; i++) {
- led_cdev = &cdata->leds[i].ldev;
- microp_i2c_write_led_mode(client, led_cdev, 0, 0xffff);
- }
- /* enable the interrupts */
- ret = microp_interrupt_enable(client, interrupts);
- if (ret < 0) {
- dev_err(&client->dev, "%s: failed to enable gpi irqs\n",
- __func__);
- goto err_irq_en;
- }
- microp_read_gpi_status(client, &stat);
- mahimahi_microp_sdslot_update_status(stat);
- return 0;
- err_irq_en:
- err_gpio_ls:
- gpio_free(MAHIMAHI_GPIO_LS_EN_N);
- exit:
- return ret;
- }
- #ifdef CONFIG_HAS_EARLYSUSPEND
- void microp_early_suspend(struct early_suspend *h)
- {
- struct microp_i2c_client_data *cdata;
- struct i2c_client *client = private_microp_client;
- int ret;
- if (!client) {
- pr_err("%s: dataset: client is empty\n", __func__);
- return;
- }
- cdata = i2c_get_clientdata(client);
- cdata->microp_is_suspend = 1;
- disable_irq(client->irq);
- ret = cancel_work_sync(&cdata->work.work);
- if (ret != 0) {
- enable_irq(client->irq);
- }
- if (cdata->auto_backlight_enabled)
- microp_i2c_auto_backlight_mode(client, 0);
- if (cdata->light_sensor_enabled == 1) {
- gpio_set_value(MAHIMAHI_GPIO_LS_EN_N, 1);
- cdata->light_sensor_enabled = 0;
- }
- }
- void microp_early_resume(struct early_suspend *h)
- {
- struct i2c_client *client = private_microp_client;
- struct microp_i2c_client_data *cdata;
- if (!client) {
- pr_err("%s: dataset: client is empty\n", __func__);
- return;
- }
- cdata = i2c_get_clientdata(client);
- gpio_set_value(MAHIMAHI_GPIO_LS_EN_N, 0);
- cdata->light_sensor_enabled = 1;
- if (cdata->auto_backlight_enabled)
- microp_i2c_auto_backlight_mode(client, 1);
- cdata->microp_is_suspend = 0;
- enable_irq(client->irq);
- }
- #endif
- static int microp_i2c_suspend(struct i2c_client *client,
- pm_message_t mesg)
- {
- return 0;
- }
- static int microp_i2c_resume(struct i2c_client *client)
- {
- return 0;
- }
- static struct {
- const char *name;
- void (*led_set_work)(struct work_struct *);
- struct device_attribute **attrs;
- int attr_cnt;
- } microp_leds[] = {
- [GREEN_LED] = {
- .name = "green",
- .led_set_work = microp_led_brightness_set_work,
- .attrs = green_amber_attrs,
- .attr_cnt = ARRAY_SIZE(green_amber_attrs)
- },
- [AMBER_LED] = {
- .name = "amber",
- .led_set_work = microp_led_brightness_set_work,
- .attrs = green_amber_attrs,
- .attr_cnt = ARRAY_SIZE(green_amber_attrs)
- },
- [RED_LED] = {
- .name = "red",
- .led_set_work = microp_led_brightness_set_work,
- .attrs = green_amber_attrs,
- .attr_cnt = ARRAY_SIZE(green_amber_attrs)
- },
- [BLUE_LED] = {
- .name = "blue",
- .led_set_work = microp_led_brightness_set_work,
- .attrs = green_amber_attrs,
- .attr_cnt = ARRAY_SIZE(green_amber_attrs)
- },
- [JOGBALL_LED] = {
- .name = "jogball-backlight",
- .led_set_work = microp_led_jogball_brightness_set_work,
- .attrs = jogball_attrs,
- .attr_cnt = ARRAY_SIZE(jogball_attrs)
- },
- [BUTTONS_LED] = {
- .name = "button-backlight",
- .led_set_work = microp_led_buttons_brightness_set_work
- },
- };
- static int microp_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
- {
- struct microp_i2c_client_data *cdata;
- uint8_t data[6];
- int ret;
- int i;
- int j;
- private_microp_client = client;
- ret = i2c_read_block(client, MICROP_I2C_RCMD_VERSION, data, 2);
- if (ret || !(data[0] && data[1])) {
- ret = -ENODEV;
- dev_err(&client->dev, "failed on get microp version\n");
- goto err_exit;
- }
- dev_info(&client->dev, "microp version [%02X][%02X]\n",
- data[0], data[1]);
- ret = gpio_request(MAHIMAHI_GPIO_UP_RESET_N, "microp_i2c_wm");
- if (ret < 0) {
- dev_err(&client->dev, "failed on request gpio reset\n");
- goto err_exit;
- }
- ret = gpio_direction_output(MAHIMAHI_GPIO_UP_RESET_N, 1);
- if (ret < 0) {
- dev_err(&client->dev,
- "failed on gpio_direction_output reset\n");
- goto err_gpio_reset;
- }
- cdata = kzalloc(sizeof(struct microp_i2c_client_data), GFP_KERNEL);
- if (!cdata) {
- ret = -ENOMEM;
- dev_err(&client->dev, "failed on allocat cdata\n");
- goto err_cdata;
- }
- i2c_set_clientdata(client, cdata);
- cdata->version = data[0] << 8 | data[1];
- cdata->microp_is_suspend = 0;
- cdata->auto_backlight_enabled = 0;
- cdata->light_sensor_enabled = 0;
- wake_lock_init(µp_i2c_wakelock, WAKE_LOCK_SUSPEND,
- "microp_i2c_present");
- /* Light Sensor */
- ret = device_create_file(&client->dev, &dev_attr_ls_adc);
- ret = device_create_file(&client->dev, &dev_attr_ls_auto);
- cdata->ls_input_dev = input_allocate_device();
- if (!cdata->ls_input_dev) {
- pr_err("%s: could not allocate input device\n", __func__);
- ret = -ENOMEM;
- goto err_request_input_dev;
- }
- cdata->ls_input_dev->name = "lightsensor-level";
- set_bit(EV_ABS, cdata->ls_input_dev->evbit);
- input_set_abs_params(cdata->ls_input_dev, ABS_MISC, 0, 9, 0, 0);
- ret = input_register_device(cdata->ls_input_dev);
- if (ret < 0) {
- dev_err(&client->dev, "%s: can not register input device\n",
- __func__);
- goto err_register_input_dev;
- }
- ret = misc_register(&lightsensor_misc);
- if (ret < 0) {
- dev_err(&client->dev, "%s: can not register misc device\n",
- __func__);
- goto err_register_misc_register;
- }
- /* LEDs */
- ret = 0;
- for (i = 0; i < ARRAY_SIZE(microp_leds) && !ret; ++i) {
- struct microp_led_data *ldata = &cdata->leds[i];
- ldata->type = i;
- ldata->ldev.name = microp_leds[i].name;
- ldata->ldev.brightness_set = microp_brightness_set;
- mutex_init(&ldata->led_data_mutex);
- INIT_WORK(&ldata->brightness_work, microp_leds[i].led_set_work);
- spin_lock_init(&ldata->brightness_lock);
- ret = led_classdev_register(&client->dev, &ldata->ldev);
- if (ret) {
- ldata->ldev.name = NULL;
- break;
- }
- for (j = 0; j < microp_leds[i].attr_cnt && !ret; ++j)
- ret = device_create_file(ldata->ldev.dev,
- microp_leds[i].attrs[j]);
- }
- if (ret) {
- dev_err(&client->dev, "failed to add leds\n");
- goto err_add_leds;
- }
- /* Headset */
- cdata->headset_is_in = 0;
- cdata->is_hpin_pin_stable = 1;
- platform_device_register(&mahimahi_h35mm);
- ret = device_create_file(&client->dev, &dev_attr_key_adc);
- /* G-sensor */
- ret = misc_register(&spi_bma_device);
- if (ret < 0) {
- pr_err("%s: init bma150 misc_register fail\n",
- __func__);
- goto err_register_bma150;
- }
- #ifdef DEBUG_BMA150
- debugfs_create_file("gsensor_log", 0444, NULL, NULL, &gsensor_log_fops);
- #endif
- /* Setup IRQ handler */
- INIT_WORK(&cdata->work.work, microp_i2c_intr_work_func);
- cdata->work.client = client;
- ret = request_irq(client->irq,
- microp_i2c_intr_irq_handler,
- IRQF_TRIGGER_LOW,
- "microp_interrupt",
- &client->dev);
- if (ret) {
- dev_err(&client->dev, "request_irq failed\n");
- goto err_intr;
- }
- ret = set_irq_wake(client->irq, 1);
- if (ret) {
- dev_err(&client->dev, "set_irq_wake failed\n");
- goto err_intr;
- }
- #ifdef CONFIG_HAS_EARLYSUSPEND
- if (cdata->enable_early_suspend) {
- cdata->early_suspend.level =
- EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
- cdata->early_suspend.suspend = microp_early_suspend;
- cdata->early_suspend.resume = microp_early_resume;
- register_early_suspend(&cdata->early_suspend);
- }
- #endif
- ret = microp_function_initialize(client);
- if (ret) {
- dev_err(&client->dev, "failed on microp function initialize\n");
- goto err_fun_init;
- }
- return 0;
- err_fun_init:
- err_intr:
- misc_deregister(&spi_bma_device);
- err_register_bma150:
- platform_device_unregister(&mahimahi_h35mm);
- device_remove_file(&client->dev, &dev_attr_key_adc);
- err_add_leds:
- for (i = 0; i < ARRAY_SIZE(microp_leds); ++i) {
- if (!cdata->leds[i].ldev.name)
- continue;
- led_classdev_unregister(&cdata->leds[i].ldev);
- for (j = 0; j < microp_leds[i].attr_cnt; ++j)
- device_remove_file(cdata->leds[i].ldev.dev,
- microp_leds[i].attrs[j]);
- }
- misc_deregister(&lightsensor_misc);
- err_register_misc_register:
- input_unregister_device(cdata->ls_input_dev);
- err_register_input_dev:
- input_free_device(cdata->ls_input_dev);
- err_request_input_dev:
- wake_lock_destroy(µp_i2c_wakelock);
- device_remove_file(&client->dev, &dev_attr_ls_adc);
- device_remove_file(&client->dev, &dev_attr_ls_auto);
- kfree(cdata);
- i2c_set_clientdata(client, NULL);
- err_cdata:
- err_gpio_reset:
- gpio_free(MAHIMAHI_GPIO_UP_RESET_N);
- err_exit:
- return ret;
- }
- static int __devexit microp_i2c_remove(struct i2c_client *client)
- {
- struct microp_i2c_client_data *cdata;
- int i;
- int j;
- cdata = i2c_get_clientdata(client);
- for (i = 0; i < ARRAY_SIZE(microp_leds); ++i) {
- struct microp_led_data *ldata = &cdata->leds[i];
- cancel_work_sync(&ldata->brightness_work);
- }
- #ifdef CONFIG_HAS_EARLYSUSPEND
- if (cdata->enable_early_suspend) {
- unregister_early_suspend(&cdata->early_suspend);
- }
- #endif
- for (i = 0; i < ARRAY_SIZE(microp_leds); ++i) {
- if (!cdata->leds[i].ldev.name)
- continue;
- led_classdev_unregister(&cdata->leds[i].ldev);
- for (j = 0; j < microp_leds[i].attr_cnt; ++j)
- device_remove_file(cdata->leds[i].ldev.dev,
- microp_leds[i].attrs[j]);
- }
- free_irq(client->irq, &client->dev);
- gpio_free(MAHIMAHI_GPIO_UP_RESET_N);
- misc_deregister(&lightsensor_misc);
- input_unregister_device(cdata->ls_input_dev);
- input_free_device(cdata->ls_input_dev);
- device_remove_file(&client->dev, &dev_attr_ls_adc);
- device_remove_file(&client->dev, &dev_attr_key_adc);
- device_remove_file(&client->dev, &dev_attr_ls_auto);
- platform_device_unregister(&mahimahi_h35mm);
- /* G-sensor */
- misc_deregister(&spi_bma_device);
- kfree(cdata);
- return 0;
- }
- #define ATAG_ALS 0x5441001b
- static int __init parse_tag_als_kadc(const struct tag *tags)
- {
- int found = 0;
- struct tag *t = (struct tag *)tags;
- for (; t->hdr.size; t = tag_next(t)) {
- if (t->hdr.tag == ATAG_ALS) {
- found = 1;
- break;
- }
- }
- if (found)
- als_kadc = t->u.revision.rev;
- pr_debug("%s: als_kadc = 0x%x\n", __func__, als_kadc);
- return 0;
- }
- __tagtable(ATAG_ALS, parse_tag_als_kadc);
- static const struct i2c_device_id microp_i2c_id[] = {
- { MICROP_I2C_NAME, 0 },
- { }
- };
- static struct i2c_driver microp_i2c_driver = {
- .driver = {
- .name = MICROP_I2C_NAME,
- },
- .id_table = microp_i2c_id,
- .probe = microp_i2c_probe,
- .suspend = microp_i2c_suspend,
- .resume = microp_i2c_resume,
- .remove = __devexit_p(microp_i2c_remove),
- };
- static int __init microp_i2c_init(void)
- {
- return i2c_add_driver(µp_i2c_driver);
- }
- static void __exit microp_i2c_exit(void)
- {
- i2c_del_driver(µp_i2c_driver);
- }
- module_init(microp_i2c_init);
- module_exit(microp_i2c_exit);
- MODULE_AUTHOR("Eric Olsen <eolsen@android.com>");
- MODULE_DESCRIPTION("MicroP I2C driver");
- MODULE_LICENSE("GPL");
|