128e64a68SDaniel Jeong /* 228e64a68SDaniel Jeong * Simple driver for Texas Instruments LM3630A Backlight driver chip 328e64a68SDaniel Jeong * Copyright (C) 2012 Texas Instruments 428e64a68SDaniel Jeong * 528e64a68SDaniel Jeong * This program is free software; you can redistribute it and/or modify 628e64a68SDaniel Jeong * it under the terms of the GNU General Public License version 2 as 728e64a68SDaniel Jeong * published by the Free Software Foundation. 828e64a68SDaniel Jeong * 928e64a68SDaniel Jeong */ 1028e64a68SDaniel Jeong #include <linux/module.h> 1128e64a68SDaniel Jeong #include <linux/slab.h> 1228e64a68SDaniel Jeong #include <linux/i2c.h> 1328e64a68SDaniel Jeong #include <linux/backlight.h> 1428e64a68SDaniel Jeong #include <linux/err.h> 1528e64a68SDaniel Jeong #include <linux/delay.h> 1628e64a68SDaniel Jeong #include <linux/uaccess.h> 1728e64a68SDaniel Jeong #include <linux/interrupt.h> 1828e64a68SDaniel Jeong #include <linux/regmap.h> 1928e64a68SDaniel Jeong #include <linux/pwm.h> 2028e64a68SDaniel Jeong #include <linux/platform_data/lm3630a_bl.h> 2128e64a68SDaniel Jeong 2228e64a68SDaniel Jeong #define REG_CTRL 0x00 2328e64a68SDaniel Jeong #define REG_BOOST 0x02 2428e64a68SDaniel Jeong #define REG_CONFIG 0x01 2528e64a68SDaniel Jeong #define REG_BRT_A 0x03 2628e64a68SDaniel Jeong #define REG_BRT_B 0x04 2728e64a68SDaniel Jeong #define REG_I_A 0x05 2828e64a68SDaniel Jeong #define REG_I_B 0x06 2928e64a68SDaniel Jeong #define REG_INT_STATUS 0x09 3028e64a68SDaniel Jeong #define REG_INT_EN 0x0A 3128e64a68SDaniel Jeong #define REG_FAULT 0x0B 3228e64a68SDaniel Jeong #define REG_PWM_OUTLOW 0x12 3328e64a68SDaniel Jeong #define REG_PWM_OUTHIGH 0x13 3428e64a68SDaniel Jeong #define REG_MAX 0x1F 3528e64a68SDaniel Jeong 3628e64a68SDaniel Jeong #define INT_DEBOUNCE_MSEC 10 3728e64a68SDaniel Jeong struct lm3630a_chip { 3828e64a68SDaniel Jeong struct device *dev; 3928e64a68SDaniel Jeong struct delayed_work work; 4028e64a68SDaniel Jeong 4128e64a68SDaniel Jeong int irq; 4228e64a68SDaniel Jeong struct workqueue_struct *irqthread; 4328e64a68SDaniel Jeong struct lm3630a_platform_data *pdata; 4428e64a68SDaniel Jeong struct backlight_device *bleda; 4528e64a68SDaniel Jeong struct backlight_device *bledb; 4628e64a68SDaniel Jeong struct regmap *regmap; 4728e64a68SDaniel Jeong struct pwm_device *pwmd; 4828e64a68SDaniel Jeong }; 4928e64a68SDaniel Jeong 5028e64a68SDaniel Jeong /* i2c access */ 5128e64a68SDaniel Jeong static int lm3630a_read(struct lm3630a_chip *pchip, unsigned int reg) 5228e64a68SDaniel Jeong { 5328e64a68SDaniel Jeong int rval; 5428e64a68SDaniel Jeong unsigned int reg_val; 5528e64a68SDaniel Jeong 5628e64a68SDaniel Jeong rval = regmap_read(pchip->regmap, reg, ®_val); 5728e64a68SDaniel Jeong if (rval < 0) 5828e64a68SDaniel Jeong return rval; 5928e64a68SDaniel Jeong return reg_val & 0xFF; 6028e64a68SDaniel Jeong } 6128e64a68SDaniel Jeong 6228e64a68SDaniel Jeong static int lm3630a_write(struct lm3630a_chip *pchip, 6328e64a68SDaniel Jeong unsigned int reg, unsigned int data) 6428e64a68SDaniel Jeong { 6528e64a68SDaniel Jeong return regmap_write(pchip->regmap, reg, data); 6628e64a68SDaniel Jeong } 6728e64a68SDaniel Jeong 6828e64a68SDaniel Jeong static int lm3630a_update(struct lm3630a_chip *pchip, 6928e64a68SDaniel Jeong unsigned int reg, unsigned int mask, 7028e64a68SDaniel Jeong unsigned int data) 7128e64a68SDaniel Jeong { 7228e64a68SDaniel Jeong return regmap_update_bits(pchip->regmap, reg, mask, data); 7328e64a68SDaniel Jeong } 7428e64a68SDaniel Jeong 7528e64a68SDaniel Jeong /* initialize chip */ 7628e64a68SDaniel Jeong static int lm3630a_chip_init(struct lm3630a_chip *pchip) 7728e64a68SDaniel Jeong { 7828e64a68SDaniel Jeong int rval; 7928e64a68SDaniel Jeong struct lm3630a_platform_data *pdata = pchip->pdata; 8028e64a68SDaniel Jeong 8128e64a68SDaniel Jeong usleep_range(1000, 2000); 8228e64a68SDaniel Jeong /* set Filter Strength Register */ 8328e64a68SDaniel Jeong rval = lm3630a_write(pchip, 0x50, 0x03); 8428e64a68SDaniel Jeong /* set Cofig. register */ 8528e64a68SDaniel Jeong rval |= lm3630a_update(pchip, REG_CONFIG, 0x07, pdata->pwm_ctrl); 8628e64a68SDaniel Jeong /* set boost control */ 8728e64a68SDaniel Jeong rval |= lm3630a_write(pchip, REG_BOOST, 0x38); 8828e64a68SDaniel Jeong /* set current A */ 8928e64a68SDaniel Jeong rval |= lm3630a_update(pchip, REG_I_A, 0x1F, 0x1F); 9028e64a68SDaniel Jeong /* set current B */ 9128e64a68SDaniel Jeong rval |= lm3630a_write(pchip, REG_I_B, 0x1F); 9228e64a68SDaniel Jeong /* set control */ 9328e64a68SDaniel Jeong rval |= 9428e64a68SDaniel Jeong lm3630a_write(pchip, REG_CTRL, pdata->leda_ctrl | pdata->ledb_ctrl); 9528e64a68SDaniel Jeong usleep_range(1000, 2000); 9628e64a68SDaniel Jeong /* set brightness A and B */ 9728e64a68SDaniel Jeong rval |= lm3630a_write(pchip, REG_BRT_A, pdata->leda_init_brt); 9828e64a68SDaniel Jeong rval |= lm3630a_write(pchip, REG_BRT_B, pdata->ledb_init_brt); 9928e64a68SDaniel Jeong 10028e64a68SDaniel Jeong if (rval < 0) 10128e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 10228e64a68SDaniel Jeong return rval; 10328e64a68SDaniel Jeong } 10428e64a68SDaniel Jeong 10528e64a68SDaniel Jeong /* interrupt handling */ 10628e64a68SDaniel Jeong static void lm3630a_delayed_func(struct work_struct *work) 10728e64a68SDaniel Jeong { 108*2a0c316bSDan Carpenter int rval; 10928e64a68SDaniel Jeong struct lm3630a_chip *pchip; 11028e64a68SDaniel Jeong 11128e64a68SDaniel Jeong pchip = container_of(work, struct lm3630a_chip, work.work); 11228e64a68SDaniel Jeong 11328e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_INT_STATUS); 11428e64a68SDaniel Jeong if (rval < 0) { 11528e64a68SDaniel Jeong dev_err(pchip->dev, 11628e64a68SDaniel Jeong "i2c failed to access REG_INT_STATUS Register\n"); 11728e64a68SDaniel Jeong return; 11828e64a68SDaniel Jeong } 11928e64a68SDaniel Jeong 12028e64a68SDaniel Jeong dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", rval); 12128e64a68SDaniel Jeong } 12228e64a68SDaniel Jeong 12328e64a68SDaniel Jeong static irqreturn_t lm3630a_isr_func(int irq, void *chip) 12428e64a68SDaniel Jeong { 12528e64a68SDaniel Jeong int rval; 12628e64a68SDaniel Jeong struct lm3630a_chip *pchip = chip; 12728e64a68SDaniel Jeong unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC); 12828e64a68SDaniel Jeong 12928e64a68SDaniel Jeong queue_delayed_work(pchip->irqthread, &pchip->work, delay); 13028e64a68SDaniel Jeong 13128e64a68SDaniel Jeong rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 13228e64a68SDaniel Jeong if (rval < 0) { 13328e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 13428e64a68SDaniel Jeong return IRQ_NONE; 13528e64a68SDaniel Jeong } 13628e64a68SDaniel Jeong return IRQ_HANDLED; 13728e64a68SDaniel Jeong } 13828e64a68SDaniel Jeong 13928e64a68SDaniel Jeong static int lm3630a_intr_config(struct lm3630a_chip *pchip) 14028e64a68SDaniel Jeong { 14128e64a68SDaniel Jeong int rval; 14228e64a68SDaniel Jeong 14328e64a68SDaniel Jeong rval = lm3630a_write(pchip, REG_INT_EN, 0x87); 14428e64a68SDaniel Jeong if (rval < 0) 14528e64a68SDaniel Jeong return rval; 14628e64a68SDaniel Jeong 14728e64a68SDaniel Jeong INIT_DELAYED_WORK(&pchip->work, lm3630a_delayed_func); 14828e64a68SDaniel Jeong pchip->irqthread = create_singlethread_workqueue("lm3630a-irqthd"); 14928e64a68SDaniel Jeong if (!pchip->irqthread) { 15028e64a68SDaniel Jeong dev_err(pchip->dev, "create irq thread fail\n"); 15128e64a68SDaniel Jeong return -ENOMEM; 15228e64a68SDaniel Jeong } 15328e64a68SDaniel Jeong if (request_threaded_irq 15428e64a68SDaniel Jeong (pchip->irq, NULL, lm3630a_isr_func, 15528e64a68SDaniel Jeong IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630a_irq", pchip)) { 15628e64a68SDaniel Jeong dev_err(pchip->dev, "request threaded irq fail\n"); 15728e64a68SDaniel Jeong return -ENOMEM; 15828e64a68SDaniel Jeong } 15928e64a68SDaniel Jeong return rval; 16028e64a68SDaniel Jeong } 16128e64a68SDaniel Jeong 16228e64a68SDaniel Jeong static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max) 16328e64a68SDaniel Jeong { 16428e64a68SDaniel Jeong unsigned int period = pwm_get_period(pchip->pwmd); 16528e64a68SDaniel Jeong unsigned int duty = br * period / br_max; 16628e64a68SDaniel Jeong 16728e64a68SDaniel Jeong pwm_config(pchip->pwmd, duty, period); 16828e64a68SDaniel Jeong if (duty) 16928e64a68SDaniel Jeong pwm_enable(pchip->pwmd); 17028e64a68SDaniel Jeong else 17128e64a68SDaniel Jeong pwm_disable(pchip->pwmd); 17228e64a68SDaniel Jeong } 17328e64a68SDaniel Jeong 17428e64a68SDaniel Jeong /* update and get brightness */ 17528e64a68SDaniel Jeong static int lm3630a_bank_a_update_status(struct backlight_device *bl) 17628e64a68SDaniel Jeong { 17728e64a68SDaniel Jeong int ret; 17828e64a68SDaniel Jeong struct lm3630a_chip *pchip = bl_get_data(bl); 17928e64a68SDaniel Jeong enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 18028e64a68SDaniel Jeong 18128e64a68SDaniel Jeong /* pwm control */ 18228e64a68SDaniel Jeong if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) { 18328e64a68SDaniel Jeong lm3630a_pwm_ctrl(pchip, bl->props.brightness, 18428e64a68SDaniel Jeong bl->props.max_brightness); 18528e64a68SDaniel Jeong return bl->props.brightness; 18628e64a68SDaniel Jeong } 18728e64a68SDaniel Jeong 18828e64a68SDaniel Jeong /* disable sleep */ 18928e64a68SDaniel Jeong ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 19028e64a68SDaniel Jeong if (ret < 0) 19128e64a68SDaniel Jeong goto out_i2c_err; 19228e64a68SDaniel Jeong usleep_range(1000, 2000); 19328e64a68SDaniel Jeong /* minimum brightness is 0x04 */ 19428e64a68SDaniel Jeong ret = lm3630a_write(pchip, REG_BRT_A, bl->props.brightness); 19528e64a68SDaniel Jeong if (bl->props.brightness < 0x4) 19628e64a68SDaniel Jeong ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0); 19728e64a68SDaniel Jeong else 19828e64a68SDaniel Jeong ret |= lm3630a_update(pchip, REG_CTRL, 19928e64a68SDaniel Jeong LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE); 20028e64a68SDaniel Jeong if (ret < 0) 20128e64a68SDaniel Jeong goto out_i2c_err; 20228e64a68SDaniel Jeong return bl->props.brightness; 20328e64a68SDaniel Jeong 20428e64a68SDaniel Jeong out_i2c_err: 20528e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access\n"); 20628e64a68SDaniel Jeong return bl->props.brightness; 20728e64a68SDaniel Jeong } 20828e64a68SDaniel Jeong 20928e64a68SDaniel Jeong static int lm3630a_bank_a_get_brightness(struct backlight_device *bl) 21028e64a68SDaniel Jeong { 21128e64a68SDaniel Jeong int brightness, rval; 21228e64a68SDaniel Jeong struct lm3630a_chip *pchip = bl_get_data(bl); 21328e64a68SDaniel Jeong enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 21428e64a68SDaniel Jeong 21528e64a68SDaniel Jeong if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) { 21628e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_PWM_OUTHIGH); 21728e64a68SDaniel Jeong if (rval < 0) 21828e64a68SDaniel Jeong goto out_i2c_err; 21928e64a68SDaniel Jeong brightness = (rval & 0x01) << 8; 22028e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_PWM_OUTLOW); 22128e64a68SDaniel Jeong if (rval < 0) 22228e64a68SDaniel Jeong goto out_i2c_err; 22328e64a68SDaniel Jeong brightness |= rval; 22428e64a68SDaniel Jeong goto out; 22528e64a68SDaniel Jeong } 22628e64a68SDaniel Jeong 22728e64a68SDaniel Jeong /* disable sleep */ 22828e64a68SDaniel Jeong rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 22928e64a68SDaniel Jeong if (rval < 0) 23028e64a68SDaniel Jeong goto out_i2c_err; 23128e64a68SDaniel Jeong usleep_range(1000, 2000); 23228e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_BRT_A); 23328e64a68SDaniel Jeong if (rval < 0) 23428e64a68SDaniel Jeong goto out_i2c_err; 23528e64a68SDaniel Jeong brightness = rval; 23628e64a68SDaniel Jeong 23728e64a68SDaniel Jeong out: 23828e64a68SDaniel Jeong bl->props.brightness = brightness; 23928e64a68SDaniel Jeong return bl->props.brightness; 24028e64a68SDaniel Jeong out_i2c_err: 24128e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 24228e64a68SDaniel Jeong return 0; 24328e64a68SDaniel Jeong } 24428e64a68SDaniel Jeong 24528e64a68SDaniel Jeong static const struct backlight_ops lm3630a_bank_a_ops = { 24628e64a68SDaniel Jeong .options = BL_CORE_SUSPENDRESUME, 24728e64a68SDaniel Jeong .update_status = lm3630a_bank_a_update_status, 24828e64a68SDaniel Jeong .get_brightness = lm3630a_bank_a_get_brightness, 24928e64a68SDaniel Jeong }; 25028e64a68SDaniel Jeong 25128e64a68SDaniel Jeong /* update and get brightness */ 25228e64a68SDaniel Jeong static int lm3630a_bank_b_update_status(struct backlight_device *bl) 25328e64a68SDaniel Jeong { 25428e64a68SDaniel Jeong int ret; 25528e64a68SDaniel Jeong struct lm3630a_chip *pchip = bl_get_data(bl); 25628e64a68SDaniel Jeong enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 25728e64a68SDaniel Jeong 25828e64a68SDaniel Jeong /* pwm control */ 25928e64a68SDaniel Jeong if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) { 26028e64a68SDaniel Jeong lm3630a_pwm_ctrl(pchip, bl->props.brightness, 26128e64a68SDaniel Jeong bl->props.max_brightness); 26228e64a68SDaniel Jeong return bl->props.brightness; 26328e64a68SDaniel Jeong } 26428e64a68SDaniel Jeong 26528e64a68SDaniel Jeong /* disable sleep */ 26628e64a68SDaniel Jeong ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 26728e64a68SDaniel Jeong if (ret < 0) 26828e64a68SDaniel Jeong goto out_i2c_err; 26928e64a68SDaniel Jeong usleep_range(1000, 2000); 27028e64a68SDaniel Jeong /* minimum brightness is 0x04 */ 27128e64a68SDaniel Jeong ret = lm3630a_write(pchip, REG_BRT_B, bl->props.brightness); 27228e64a68SDaniel Jeong if (bl->props.brightness < 0x4) 27328e64a68SDaniel Jeong ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0); 27428e64a68SDaniel Jeong else 27528e64a68SDaniel Jeong ret |= lm3630a_update(pchip, REG_CTRL, 27628e64a68SDaniel Jeong LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE); 27728e64a68SDaniel Jeong if (ret < 0) 27828e64a68SDaniel Jeong goto out_i2c_err; 27928e64a68SDaniel Jeong return bl->props.brightness; 28028e64a68SDaniel Jeong 28128e64a68SDaniel Jeong out_i2c_err: 28228e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access REG_CTRL\n"); 28328e64a68SDaniel Jeong return bl->props.brightness; 28428e64a68SDaniel Jeong } 28528e64a68SDaniel Jeong 28628e64a68SDaniel Jeong static int lm3630a_bank_b_get_brightness(struct backlight_device *bl) 28728e64a68SDaniel Jeong { 28828e64a68SDaniel Jeong int brightness, rval; 28928e64a68SDaniel Jeong struct lm3630a_chip *pchip = bl_get_data(bl); 29028e64a68SDaniel Jeong enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 29128e64a68SDaniel Jeong 29228e64a68SDaniel Jeong if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) { 29328e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_PWM_OUTHIGH); 29428e64a68SDaniel Jeong if (rval < 0) 29528e64a68SDaniel Jeong goto out_i2c_err; 29628e64a68SDaniel Jeong brightness = (rval & 0x01) << 8; 29728e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_PWM_OUTLOW); 29828e64a68SDaniel Jeong if (rval < 0) 29928e64a68SDaniel Jeong goto out_i2c_err; 30028e64a68SDaniel Jeong brightness |= rval; 30128e64a68SDaniel Jeong goto out; 30228e64a68SDaniel Jeong } 30328e64a68SDaniel Jeong 30428e64a68SDaniel Jeong /* disable sleep */ 30528e64a68SDaniel Jeong rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 30628e64a68SDaniel Jeong if (rval < 0) 30728e64a68SDaniel Jeong goto out_i2c_err; 30828e64a68SDaniel Jeong usleep_range(1000, 2000); 30928e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_BRT_B); 31028e64a68SDaniel Jeong if (rval < 0) 31128e64a68SDaniel Jeong goto out_i2c_err; 31228e64a68SDaniel Jeong brightness = rval; 31328e64a68SDaniel Jeong 31428e64a68SDaniel Jeong out: 31528e64a68SDaniel Jeong bl->props.brightness = brightness; 31628e64a68SDaniel Jeong return bl->props.brightness; 31728e64a68SDaniel Jeong out_i2c_err: 31828e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 31928e64a68SDaniel Jeong return 0; 32028e64a68SDaniel Jeong } 32128e64a68SDaniel Jeong 32228e64a68SDaniel Jeong static const struct backlight_ops lm3630a_bank_b_ops = { 32328e64a68SDaniel Jeong .options = BL_CORE_SUSPENDRESUME, 32428e64a68SDaniel Jeong .update_status = lm3630a_bank_b_update_status, 32528e64a68SDaniel Jeong .get_brightness = lm3630a_bank_b_get_brightness, 32628e64a68SDaniel Jeong }; 32728e64a68SDaniel Jeong 32828e64a68SDaniel Jeong static int lm3630a_backlight_register(struct lm3630a_chip *pchip) 32928e64a68SDaniel Jeong { 33028e64a68SDaniel Jeong struct backlight_properties props; 33128e64a68SDaniel Jeong struct lm3630a_platform_data *pdata = pchip->pdata; 33228e64a68SDaniel Jeong 33328e64a68SDaniel Jeong props.type = BACKLIGHT_RAW; 33428e64a68SDaniel Jeong if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) { 33528e64a68SDaniel Jeong props.brightness = pdata->leda_init_brt; 33628e64a68SDaniel Jeong props.max_brightness = pdata->leda_max_brt; 33728e64a68SDaniel Jeong pchip->bleda = 33828e64a68SDaniel Jeong devm_backlight_device_register(pchip->dev, "lm3630a_leda", 33928e64a68SDaniel Jeong pchip->dev, pchip, 34028e64a68SDaniel Jeong &lm3630a_bank_a_ops, &props); 34128e64a68SDaniel Jeong if (IS_ERR(pchip->bleda)) 34228e64a68SDaniel Jeong return PTR_ERR(pchip->bleda); 34328e64a68SDaniel Jeong } 34428e64a68SDaniel Jeong 34528e64a68SDaniel Jeong if ((pdata->ledb_ctrl != LM3630A_LEDB_DISABLE) && 34628e64a68SDaniel Jeong (pdata->ledb_ctrl != LM3630A_LEDB_ON_A)) { 34728e64a68SDaniel Jeong props.brightness = pdata->ledb_init_brt; 34828e64a68SDaniel Jeong props.max_brightness = pdata->ledb_max_brt; 34928e64a68SDaniel Jeong pchip->bledb = 35028e64a68SDaniel Jeong devm_backlight_device_register(pchip->dev, "lm3630a_ledb", 35128e64a68SDaniel Jeong pchip->dev, pchip, 35228e64a68SDaniel Jeong &lm3630a_bank_b_ops, &props); 35328e64a68SDaniel Jeong if (IS_ERR(pchip->bledb)) 35428e64a68SDaniel Jeong return PTR_ERR(pchip->bledb); 35528e64a68SDaniel Jeong } 35628e64a68SDaniel Jeong return 0; 35728e64a68SDaniel Jeong } 35828e64a68SDaniel Jeong 35928e64a68SDaniel Jeong static const struct regmap_config lm3630a_regmap = { 36028e64a68SDaniel Jeong .reg_bits = 8, 36128e64a68SDaniel Jeong .val_bits = 8, 36228e64a68SDaniel Jeong .max_register = REG_MAX, 36328e64a68SDaniel Jeong }; 36428e64a68SDaniel Jeong 36528e64a68SDaniel Jeong static int lm3630a_probe(struct i2c_client *client, 36628e64a68SDaniel Jeong const struct i2c_device_id *id) 36728e64a68SDaniel Jeong { 36828e64a68SDaniel Jeong struct lm3630a_platform_data *pdata = client->dev.platform_data; 36928e64a68SDaniel Jeong struct lm3630a_chip *pchip; 37028e64a68SDaniel Jeong int rval; 37128e64a68SDaniel Jeong 37228e64a68SDaniel Jeong if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 37328e64a68SDaniel Jeong dev_err(&client->dev, "fail : i2c functionality check\n"); 37428e64a68SDaniel Jeong return -EOPNOTSUPP; 37528e64a68SDaniel Jeong } 37628e64a68SDaniel Jeong 37728e64a68SDaniel Jeong pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630a_chip), 37828e64a68SDaniel Jeong GFP_KERNEL); 37928e64a68SDaniel Jeong if (!pchip) 38028e64a68SDaniel Jeong return -ENOMEM; 38128e64a68SDaniel Jeong pchip->dev = &client->dev; 38228e64a68SDaniel Jeong 38328e64a68SDaniel Jeong pchip->regmap = devm_regmap_init_i2c(client, &lm3630a_regmap); 38428e64a68SDaniel Jeong if (IS_ERR(pchip->regmap)) { 38528e64a68SDaniel Jeong rval = PTR_ERR(pchip->regmap); 38628e64a68SDaniel Jeong dev_err(&client->dev, "fail : allocate reg. map: %d\n", rval); 38728e64a68SDaniel Jeong return rval; 38828e64a68SDaniel Jeong } 38928e64a68SDaniel Jeong 39028e64a68SDaniel Jeong i2c_set_clientdata(client, pchip); 39128e64a68SDaniel Jeong if (pdata == NULL) { 39228e64a68SDaniel Jeong pchip->pdata = devm_kzalloc(pchip->dev, 39328e64a68SDaniel Jeong sizeof(struct 39428e64a68SDaniel Jeong lm3630a_platform_data), 39528e64a68SDaniel Jeong GFP_KERNEL); 39628e64a68SDaniel Jeong if (pchip->pdata == NULL) 39728e64a68SDaniel Jeong return -ENOMEM; 39828e64a68SDaniel Jeong /* default values */ 39928e64a68SDaniel Jeong pchip->pdata->leda_ctrl = LM3630A_LEDA_ENABLE; 40028e64a68SDaniel Jeong pchip->pdata->ledb_ctrl = LM3630A_LEDB_ENABLE; 40128e64a68SDaniel Jeong pchip->pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS; 40228e64a68SDaniel Jeong pchip->pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS; 40328e64a68SDaniel Jeong pchip->pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS; 40428e64a68SDaniel Jeong pchip->pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS; 40528e64a68SDaniel Jeong } else { 40628e64a68SDaniel Jeong pchip->pdata = pdata; 40728e64a68SDaniel Jeong } 40828e64a68SDaniel Jeong /* chip initialize */ 40928e64a68SDaniel Jeong rval = lm3630a_chip_init(pchip); 41028e64a68SDaniel Jeong if (rval < 0) { 41128e64a68SDaniel Jeong dev_err(&client->dev, "fail : init chip\n"); 41228e64a68SDaniel Jeong return rval; 41328e64a68SDaniel Jeong } 41428e64a68SDaniel Jeong /* backlight register */ 41528e64a68SDaniel Jeong rval = lm3630a_backlight_register(pchip); 41628e64a68SDaniel Jeong if (rval < 0) { 41728e64a68SDaniel Jeong dev_err(&client->dev, "fail : backlight register.\n"); 41828e64a68SDaniel Jeong return rval; 41928e64a68SDaniel Jeong } 42028e64a68SDaniel Jeong /* pwm */ 42128e64a68SDaniel Jeong if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) { 42228e64a68SDaniel Jeong pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm"); 42328e64a68SDaniel Jeong if (IS_ERR(pchip->pwmd)) { 42428e64a68SDaniel Jeong dev_err(&client->dev, "fail : get pwm device\n"); 42528e64a68SDaniel Jeong return PTR_ERR(pchip->pwmd); 42628e64a68SDaniel Jeong } 42728e64a68SDaniel Jeong } 42828e64a68SDaniel Jeong pchip->pwmd->period = pdata->pwm_period; 42928e64a68SDaniel Jeong 43028e64a68SDaniel Jeong /* interrupt enable : irq 0 is not allowed */ 43128e64a68SDaniel Jeong pchip->irq = client->irq; 43228e64a68SDaniel Jeong if (pchip->irq) { 43328e64a68SDaniel Jeong rval = lm3630a_intr_config(pchip); 43428e64a68SDaniel Jeong if (rval < 0) 43528e64a68SDaniel Jeong return rval; 43628e64a68SDaniel Jeong } 43728e64a68SDaniel Jeong dev_info(&client->dev, "LM3630A backlight register OK.\n"); 43828e64a68SDaniel Jeong return 0; 43928e64a68SDaniel Jeong } 44028e64a68SDaniel Jeong 44128e64a68SDaniel Jeong static int lm3630a_remove(struct i2c_client *client) 44228e64a68SDaniel Jeong { 44328e64a68SDaniel Jeong int rval; 44428e64a68SDaniel Jeong struct lm3630a_chip *pchip = i2c_get_clientdata(client); 44528e64a68SDaniel Jeong 44628e64a68SDaniel Jeong rval = lm3630a_write(pchip, REG_BRT_A, 0); 44728e64a68SDaniel Jeong if (rval < 0) 44828e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 44928e64a68SDaniel Jeong 45028e64a68SDaniel Jeong rval = lm3630a_write(pchip, REG_BRT_B, 0); 45128e64a68SDaniel Jeong if (rval < 0) 45228e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 45328e64a68SDaniel Jeong 45428e64a68SDaniel Jeong if (pchip->irq) { 45528e64a68SDaniel Jeong free_irq(pchip->irq, pchip); 45628e64a68SDaniel Jeong flush_workqueue(pchip->irqthread); 45728e64a68SDaniel Jeong destroy_workqueue(pchip->irqthread); 45828e64a68SDaniel Jeong } 45928e64a68SDaniel Jeong return 0; 46028e64a68SDaniel Jeong } 46128e64a68SDaniel Jeong 46228e64a68SDaniel Jeong static const struct i2c_device_id lm3630a_id[] = { 46328e64a68SDaniel Jeong {LM3630A_NAME, 0}, 46428e64a68SDaniel Jeong {} 46528e64a68SDaniel Jeong }; 46628e64a68SDaniel Jeong 46728e64a68SDaniel Jeong MODULE_DEVICE_TABLE(i2c, lm3630a_id); 46828e64a68SDaniel Jeong 46928e64a68SDaniel Jeong static struct i2c_driver lm3630a_i2c_driver = { 47028e64a68SDaniel Jeong .driver = { 47128e64a68SDaniel Jeong .name = LM3630A_NAME, 47228e64a68SDaniel Jeong }, 47328e64a68SDaniel Jeong .probe = lm3630a_probe, 47428e64a68SDaniel Jeong .remove = lm3630a_remove, 47528e64a68SDaniel Jeong .id_table = lm3630a_id, 47628e64a68SDaniel Jeong }; 47728e64a68SDaniel Jeong 47828e64a68SDaniel Jeong module_i2c_driver(lm3630a_i2c_driver); 47928e64a68SDaniel Jeong 48028e64a68SDaniel Jeong MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630A"); 48128e64a68SDaniel Jeong MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>"); 48228e64a68SDaniel Jeong MODULE_AUTHOR("LDD MLP <ldd-mlp@list.ti.com>"); 48328e64a68SDaniel Jeong MODULE_LICENSE("GPL v2"); 484