1*28e64a68SDaniel Jeong /* 2*28e64a68SDaniel Jeong * Simple driver for Texas Instruments LM3630A Backlight driver chip 3*28e64a68SDaniel Jeong * Copyright (C) 2012 Texas Instruments 4*28e64a68SDaniel Jeong * 5*28e64a68SDaniel Jeong * This program is free software; you can redistribute it and/or modify 6*28e64a68SDaniel Jeong * it under the terms of the GNU General Public License version 2 as 7*28e64a68SDaniel Jeong * published by the Free Software Foundation. 8*28e64a68SDaniel Jeong * 9*28e64a68SDaniel Jeong */ 10*28e64a68SDaniel Jeong #include <linux/module.h> 11*28e64a68SDaniel Jeong #include <linux/slab.h> 12*28e64a68SDaniel Jeong #include <linux/i2c.h> 13*28e64a68SDaniel Jeong #include <linux/backlight.h> 14*28e64a68SDaniel Jeong #include <linux/err.h> 15*28e64a68SDaniel Jeong #include <linux/delay.h> 16*28e64a68SDaniel Jeong #include <linux/uaccess.h> 17*28e64a68SDaniel Jeong #include <linux/interrupt.h> 18*28e64a68SDaniel Jeong #include <linux/regmap.h> 19*28e64a68SDaniel Jeong #include <linux/pwm.h> 20*28e64a68SDaniel Jeong #include <linux/platform_data/lm3630a_bl.h> 21*28e64a68SDaniel Jeong 22*28e64a68SDaniel Jeong #define REG_CTRL 0x00 23*28e64a68SDaniel Jeong #define REG_BOOST 0x02 24*28e64a68SDaniel Jeong #define REG_CONFIG 0x01 25*28e64a68SDaniel Jeong #define REG_BRT_A 0x03 26*28e64a68SDaniel Jeong #define REG_BRT_B 0x04 27*28e64a68SDaniel Jeong #define REG_I_A 0x05 28*28e64a68SDaniel Jeong #define REG_I_B 0x06 29*28e64a68SDaniel Jeong #define REG_INT_STATUS 0x09 30*28e64a68SDaniel Jeong #define REG_INT_EN 0x0A 31*28e64a68SDaniel Jeong #define REG_FAULT 0x0B 32*28e64a68SDaniel Jeong #define REG_PWM_OUTLOW 0x12 33*28e64a68SDaniel Jeong #define REG_PWM_OUTHIGH 0x13 34*28e64a68SDaniel Jeong #define REG_MAX 0x1F 35*28e64a68SDaniel Jeong 36*28e64a68SDaniel Jeong #define INT_DEBOUNCE_MSEC 10 37*28e64a68SDaniel Jeong struct lm3630a_chip { 38*28e64a68SDaniel Jeong struct device *dev; 39*28e64a68SDaniel Jeong struct delayed_work work; 40*28e64a68SDaniel Jeong 41*28e64a68SDaniel Jeong int irq; 42*28e64a68SDaniel Jeong struct workqueue_struct *irqthread; 43*28e64a68SDaniel Jeong struct lm3630a_platform_data *pdata; 44*28e64a68SDaniel Jeong struct backlight_device *bleda; 45*28e64a68SDaniel Jeong struct backlight_device *bledb; 46*28e64a68SDaniel Jeong struct regmap *regmap; 47*28e64a68SDaniel Jeong struct pwm_device *pwmd; 48*28e64a68SDaniel Jeong }; 49*28e64a68SDaniel Jeong 50*28e64a68SDaniel Jeong /* i2c access */ 51*28e64a68SDaniel Jeong static int lm3630a_read(struct lm3630a_chip *pchip, unsigned int reg) 52*28e64a68SDaniel Jeong { 53*28e64a68SDaniel Jeong int rval; 54*28e64a68SDaniel Jeong unsigned int reg_val; 55*28e64a68SDaniel Jeong 56*28e64a68SDaniel Jeong rval = regmap_read(pchip->regmap, reg, ®_val); 57*28e64a68SDaniel Jeong if (rval < 0) 58*28e64a68SDaniel Jeong return rval; 59*28e64a68SDaniel Jeong return reg_val & 0xFF; 60*28e64a68SDaniel Jeong } 61*28e64a68SDaniel Jeong 62*28e64a68SDaniel Jeong static int lm3630a_write(struct lm3630a_chip *pchip, 63*28e64a68SDaniel Jeong unsigned int reg, unsigned int data) 64*28e64a68SDaniel Jeong { 65*28e64a68SDaniel Jeong return regmap_write(pchip->regmap, reg, data); 66*28e64a68SDaniel Jeong } 67*28e64a68SDaniel Jeong 68*28e64a68SDaniel Jeong static int lm3630a_update(struct lm3630a_chip *pchip, 69*28e64a68SDaniel Jeong unsigned int reg, unsigned int mask, 70*28e64a68SDaniel Jeong unsigned int data) 71*28e64a68SDaniel Jeong { 72*28e64a68SDaniel Jeong return regmap_update_bits(pchip->regmap, reg, mask, data); 73*28e64a68SDaniel Jeong } 74*28e64a68SDaniel Jeong 75*28e64a68SDaniel Jeong /* initialize chip */ 76*28e64a68SDaniel Jeong static int lm3630a_chip_init(struct lm3630a_chip *pchip) 77*28e64a68SDaniel Jeong { 78*28e64a68SDaniel Jeong int rval; 79*28e64a68SDaniel Jeong struct lm3630a_platform_data *pdata = pchip->pdata; 80*28e64a68SDaniel Jeong 81*28e64a68SDaniel Jeong usleep_range(1000, 2000); 82*28e64a68SDaniel Jeong /* set Filter Strength Register */ 83*28e64a68SDaniel Jeong rval = lm3630a_write(pchip, 0x50, 0x03); 84*28e64a68SDaniel Jeong /* set Cofig. register */ 85*28e64a68SDaniel Jeong rval |= lm3630a_update(pchip, REG_CONFIG, 0x07, pdata->pwm_ctrl); 86*28e64a68SDaniel Jeong /* set boost control */ 87*28e64a68SDaniel Jeong rval |= lm3630a_write(pchip, REG_BOOST, 0x38); 88*28e64a68SDaniel Jeong /* set current A */ 89*28e64a68SDaniel Jeong rval |= lm3630a_update(pchip, REG_I_A, 0x1F, 0x1F); 90*28e64a68SDaniel Jeong /* set current B */ 91*28e64a68SDaniel Jeong rval |= lm3630a_write(pchip, REG_I_B, 0x1F); 92*28e64a68SDaniel Jeong /* set control */ 93*28e64a68SDaniel Jeong rval |= 94*28e64a68SDaniel Jeong lm3630a_write(pchip, REG_CTRL, pdata->leda_ctrl | pdata->ledb_ctrl); 95*28e64a68SDaniel Jeong usleep_range(1000, 2000); 96*28e64a68SDaniel Jeong /* set brightness A and B */ 97*28e64a68SDaniel Jeong rval |= lm3630a_write(pchip, REG_BRT_A, pdata->leda_init_brt); 98*28e64a68SDaniel Jeong rval |= lm3630a_write(pchip, REG_BRT_B, pdata->ledb_init_brt); 99*28e64a68SDaniel Jeong 100*28e64a68SDaniel Jeong if (rval < 0) 101*28e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 102*28e64a68SDaniel Jeong return rval; 103*28e64a68SDaniel Jeong } 104*28e64a68SDaniel Jeong 105*28e64a68SDaniel Jeong /* interrupt handling */ 106*28e64a68SDaniel Jeong static void lm3630a_delayed_func(struct work_struct *work) 107*28e64a68SDaniel Jeong { 108*28e64a68SDaniel Jeong unsigned int rval; 109*28e64a68SDaniel Jeong struct lm3630a_chip *pchip; 110*28e64a68SDaniel Jeong 111*28e64a68SDaniel Jeong pchip = container_of(work, struct lm3630a_chip, work.work); 112*28e64a68SDaniel Jeong 113*28e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_INT_STATUS); 114*28e64a68SDaniel Jeong if (rval < 0) { 115*28e64a68SDaniel Jeong dev_err(pchip->dev, 116*28e64a68SDaniel Jeong "i2c failed to access REG_INT_STATUS Register\n"); 117*28e64a68SDaniel Jeong return; 118*28e64a68SDaniel Jeong } 119*28e64a68SDaniel Jeong 120*28e64a68SDaniel Jeong dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", rval); 121*28e64a68SDaniel Jeong } 122*28e64a68SDaniel Jeong 123*28e64a68SDaniel Jeong static irqreturn_t lm3630a_isr_func(int irq, void *chip) 124*28e64a68SDaniel Jeong { 125*28e64a68SDaniel Jeong int rval; 126*28e64a68SDaniel Jeong struct lm3630a_chip *pchip = chip; 127*28e64a68SDaniel Jeong unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC); 128*28e64a68SDaniel Jeong 129*28e64a68SDaniel Jeong queue_delayed_work(pchip->irqthread, &pchip->work, delay); 130*28e64a68SDaniel Jeong 131*28e64a68SDaniel Jeong rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 132*28e64a68SDaniel Jeong if (rval < 0) { 133*28e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 134*28e64a68SDaniel Jeong return IRQ_NONE; 135*28e64a68SDaniel Jeong } 136*28e64a68SDaniel Jeong return IRQ_HANDLED; 137*28e64a68SDaniel Jeong } 138*28e64a68SDaniel Jeong 139*28e64a68SDaniel Jeong static int lm3630a_intr_config(struct lm3630a_chip *pchip) 140*28e64a68SDaniel Jeong { 141*28e64a68SDaniel Jeong int rval; 142*28e64a68SDaniel Jeong 143*28e64a68SDaniel Jeong rval = lm3630a_write(pchip, REG_INT_EN, 0x87); 144*28e64a68SDaniel Jeong if (rval < 0) 145*28e64a68SDaniel Jeong return rval; 146*28e64a68SDaniel Jeong 147*28e64a68SDaniel Jeong INIT_DELAYED_WORK(&pchip->work, lm3630a_delayed_func); 148*28e64a68SDaniel Jeong pchip->irqthread = create_singlethread_workqueue("lm3630a-irqthd"); 149*28e64a68SDaniel Jeong if (!pchip->irqthread) { 150*28e64a68SDaniel Jeong dev_err(pchip->dev, "create irq thread fail\n"); 151*28e64a68SDaniel Jeong return -ENOMEM; 152*28e64a68SDaniel Jeong } 153*28e64a68SDaniel Jeong if (request_threaded_irq 154*28e64a68SDaniel Jeong (pchip->irq, NULL, lm3630a_isr_func, 155*28e64a68SDaniel Jeong IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630a_irq", pchip)) { 156*28e64a68SDaniel Jeong dev_err(pchip->dev, "request threaded irq fail\n"); 157*28e64a68SDaniel Jeong return -ENOMEM; 158*28e64a68SDaniel Jeong } 159*28e64a68SDaniel Jeong return rval; 160*28e64a68SDaniel Jeong } 161*28e64a68SDaniel Jeong 162*28e64a68SDaniel Jeong static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max) 163*28e64a68SDaniel Jeong { 164*28e64a68SDaniel Jeong unsigned int period = pwm_get_period(pchip->pwmd); 165*28e64a68SDaniel Jeong unsigned int duty = br * period / br_max; 166*28e64a68SDaniel Jeong 167*28e64a68SDaniel Jeong pwm_config(pchip->pwmd, duty, period); 168*28e64a68SDaniel Jeong if (duty) 169*28e64a68SDaniel Jeong pwm_enable(pchip->pwmd); 170*28e64a68SDaniel Jeong else 171*28e64a68SDaniel Jeong pwm_disable(pchip->pwmd); 172*28e64a68SDaniel Jeong } 173*28e64a68SDaniel Jeong 174*28e64a68SDaniel Jeong /* update and get brightness */ 175*28e64a68SDaniel Jeong static int lm3630a_bank_a_update_status(struct backlight_device *bl) 176*28e64a68SDaniel Jeong { 177*28e64a68SDaniel Jeong int ret; 178*28e64a68SDaniel Jeong struct lm3630a_chip *pchip = bl_get_data(bl); 179*28e64a68SDaniel Jeong enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 180*28e64a68SDaniel Jeong 181*28e64a68SDaniel Jeong /* pwm control */ 182*28e64a68SDaniel Jeong if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) { 183*28e64a68SDaniel Jeong lm3630a_pwm_ctrl(pchip, bl->props.brightness, 184*28e64a68SDaniel Jeong bl->props.max_brightness); 185*28e64a68SDaniel Jeong return bl->props.brightness; 186*28e64a68SDaniel Jeong } 187*28e64a68SDaniel Jeong 188*28e64a68SDaniel Jeong /* disable sleep */ 189*28e64a68SDaniel Jeong ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 190*28e64a68SDaniel Jeong if (ret < 0) 191*28e64a68SDaniel Jeong goto out_i2c_err; 192*28e64a68SDaniel Jeong usleep_range(1000, 2000); 193*28e64a68SDaniel Jeong /* minimum brightness is 0x04 */ 194*28e64a68SDaniel Jeong ret = lm3630a_write(pchip, REG_BRT_A, bl->props.brightness); 195*28e64a68SDaniel Jeong if (bl->props.brightness < 0x4) 196*28e64a68SDaniel Jeong ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0); 197*28e64a68SDaniel Jeong else 198*28e64a68SDaniel Jeong ret |= lm3630a_update(pchip, REG_CTRL, 199*28e64a68SDaniel Jeong LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE); 200*28e64a68SDaniel Jeong if (ret < 0) 201*28e64a68SDaniel Jeong goto out_i2c_err; 202*28e64a68SDaniel Jeong return bl->props.brightness; 203*28e64a68SDaniel Jeong 204*28e64a68SDaniel Jeong out_i2c_err: 205*28e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access\n"); 206*28e64a68SDaniel Jeong return bl->props.brightness; 207*28e64a68SDaniel Jeong } 208*28e64a68SDaniel Jeong 209*28e64a68SDaniel Jeong static int lm3630a_bank_a_get_brightness(struct backlight_device *bl) 210*28e64a68SDaniel Jeong { 211*28e64a68SDaniel Jeong int brightness, rval; 212*28e64a68SDaniel Jeong struct lm3630a_chip *pchip = bl_get_data(bl); 213*28e64a68SDaniel Jeong enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 214*28e64a68SDaniel Jeong 215*28e64a68SDaniel Jeong if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) { 216*28e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_PWM_OUTHIGH); 217*28e64a68SDaniel Jeong if (rval < 0) 218*28e64a68SDaniel Jeong goto out_i2c_err; 219*28e64a68SDaniel Jeong brightness = (rval & 0x01) << 8; 220*28e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_PWM_OUTLOW); 221*28e64a68SDaniel Jeong if (rval < 0) 222*28e64a68SDaniel Jeong goto out_i2c_err; 223*28e64a68SDaniel Jeong brightness |= rval; 224*28e64a68SDaniel Jeong goto out; 225*28e64a68SDaniel Jeong } 226*28e64a68SDaniel Jeong 227*28e64a68SDaniel Jeong /* disable sleep */ 228*28e64a68SDaniel Jeong rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 229*28e64a68SDaniel Jeong if (rval < 0) 230*28e64a68SDaniel Jeong goto out_i2c_err; 231*28e64a68SDaniel Jeong usleep_range(1000, 2000); 232*28e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_BRT_A); 233*28e64a68SDaniel Jeong if (rval < 0) 234*28e64a68SDaniel Jeong goto out_i2c_err; 235*28e64a68SDaniel Jeong brightness = rval; 236*28e64a68SDaniel Jeong 237*28e64a68SDaniel Jeong out: 238*28e64a68SDaniel Jeong bl->props.brightness = brightness; 239*28e64a68SDaniel Jeong return bl->props.brightness; 240*28e64a68SDaniel Jeong out_i2c_err: 241*28e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 242*28e64a68SDaniel Jeong return 0; 243*28e64a68SDaniel Jeong } 244*28e64a68SDaniel Jeong 245*28e64a68SDaniel Jeong static const struct backlight_ops lm3630a_bank_a_ops = { 246*28e64a68SDaniel Jeong .options = BL_CORE_SUSPENDRESUME, 247*28e64a68SDaniel Jeong .update_status = lm3630a_bank_a_update_status, 248*28e64a68SDaniel Jeong .get_brightness = lm3630a_bank_a_get_brightness, 249*28e64a68SDaniel Jeong }; 250*28e64a68SDaniel Jeong 251*28e64a68SDaniel Jeong /* update and get brightness */ 252*28e64a68SDaniel Jeong static int lm3630a_bank_b_update_status(struct backlight_device *bl) 253*28e64a68SDaniel Jeong { 254*28e64a68SDaniel Jeong int ret; 255*28e64a68SDaniel Jeong struct lm3630a_chip *pchip = bl_get_data(bl); 256*28e64a68SDaniel Jeong enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 257*28e64a68SDaniel Jeong 258*28e64a68SDaniel Jeong /* pwm control */ 259*28e64a68SDaniel Jeong if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) { 260*28e64a68SDaniel Jeong lm3630a_pwm_ctrl(pchip, bl->props.brightness, 261*28e64a68SDaniel Jeong bl->props.max_brightness); 262*28e64a68SDaniel Jeong return bl->props.brightness; 263*28e64a68SDaniel Jeong } 264*28e64a68SDaniel Jeong 265*28e64a68SDaniel Jeong /* disable sleep */ 266*28e64a68SDaniel Jeong ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 267*28e64a68SDaniel Jeong if (ret < 0) 268*28e64a68SDaniel Jeong goto out_i2c_err; 269*28e64a68SDaniel Jeong usleep_range(1000, 2000); 270*28e64a68SDaniel Jeong /* minimum brightness is 0x04 */ 271*28e64a68SDaniel Jeong ret = lm3630a_write(pchip, REG_BRT_B, bl->props.brightness); 272*28e64a68SDaniel Jeong if (bl->props.brightness < 0x4) 273*28e64a68SDaniel Jeong ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0); 274*28e64a68SDaniel Jeong else 275*28e64a68SDaniel Jeong ret |= lm3630a_update(pchip, REG_CTRL, 276*28e64a68SDaniel Jeong LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE); 277*28e64a68SDaniel Jeong if (ret < 0) 278*28e64a68SDaniel Jeong goto out_i2c_err; 279*28e64a68SDaniel Jeong return bl->props.brightness; 280*28e64a68SDaniel Jeong 281*28e64a68SDaniel Jeong out_i2c_err: 282*28e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access REG_CTRL\n"); 283*28e64a68SDaniel Jeong return bl->props.brightness; 284*28e64a68SDaniel Jeong } 285*28e64a68SDaniel Jeong 286*28e64a68SDaniel Jeong static int lm3630a_bank_b_get_brightness(struct backlight_device *bl) 287*28e64a68SDaniel Jeong { 288*28e64a68SDaniel Jeong int brightness, rval; 289*28e64a68SDaniel Jeong struct lm3630a_chip *pchip = bl_get_data(bl); 290*28e64a68SDaniel Jeong enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; 291*28e64a68SDaniel Jeong 292*28e64a68SDaniel Jeong if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) { 293*28e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_PWM_OUTHIGH); 294*28e64a68SDaniel Jeong if (rval < 0) 295*28e64a68SDaniel Jeong goto out_i2c_err; 296*28e64a68SDaniel Jeong brightness = (rval & 0x01) << 8; 297*28e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_PWM_OUTLOW); 298*28e64a68SDaniel Jeong if (rval < 0) 299*28e64a68SDaniel Jeong goto out_i2c_err; 300*28e64a68SDaniel Jeong brightness |= rval; 301*28e64a68SDaniel Jeong goto out; 302*28e64a68SDaniel Jeong } 303*28e64a68SDaniel Jeong 304*28e64a68SDaniel Jeong /* disable sleep */ 305*28e64a68SDaniel Jeong rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); 306*28e64a68SDaniel Jeong if (rval < 0) 307*28e64a68SDaniel Jeong goto out_i2c_err; 308*28e64a68SDaniel Jeong usleep_range(1000, 2000); 309*28e64a68SDaniel Jeong rval = lm3630a_read(pchip, REG_BRT_B); 310*28e64a68SDaniel Jeong if (rval < 0) 311*28e64a68SDaniel Jeong goto out_i2c_err; 312*28e64a68SDaniel Jeong brightness = rval; 313*28e64a68SDaniel Jeong 314*28e64a68SDaniel Jeong out: 315*28e64a68SDaniel Jeong bl->props.brightness = brightness; 316*28e64a68SDaniel Jeong return bl->props.brightness; 317*28e64a68SDaniel Jeong out_i2c_err: 318*28e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 319*28e64a68SDaniel Jeong return 0; 320*28e64a68SDaniel Jeong } 321*28e64a68SDaniel Jeong 322*28e64a68SDaniel Jeong static const struct backlight_ops lm3630a_bank_b_ops = { 323*28e64a68SDaniel Jeong .options = BL_CORE_SUSPENDRESUME, 324*28e64a68SDaniel Jeong .update_status = lm3630a_bank_b_update_status, 325*28e64a68SDaniel Jeong .get_brightness = lm3630a_bank_b_get_brightness, 326*28e64a68SDaniel Jeong }; 327*28e64a68SDaniel Jeong 328*28e64a68SDaniel Jeong static int lm3630a_backlight_register(struct lm3630a_chip *pchip) 329*28e64a68SDaniel Jeong { 330*28e64a68SDaniel Jeong struct backlight_properties props; 331*28e64a68SDaniel Jeong struct lm3630a_platform_data *pdata = pchip->pdata; 332*28e64a68SDaniel Jeong 333*28e64a68SDaniel Jeong props.type = BACKLIGHT_RAW; 334*28e64a68SDaniel Jeong if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) { 335*28e64a68SDaniel Jeong props.brightness = pdata->leda_init_brt; 336*28e64a68SDaniel Jeong props.max_brightness = pdata->leda_max_brt; 337*28e64a68SDaniel Jeong pchip->bleda = 338*28e64a68SDaniel Jeong devm_backlight_device_register(pchip->dev, "lm3630a_leda", 339*28e64a68SDaniel Jeong pchip->dev, pchip, 340*28e64a68SDaniel Jeong &lm3630a_bank_a_ops, &props); 341*28e64a68SDaniel Jeong if (IS_ERR(pchip->bleda)) 342*28e64a68SDaniel Jeong return PTR_ERR(pchip->bleda); 343*28e64a68SDaniel Jeong } 344*28e64a68SDaniel Jeong 345*28e64a68SDaniel Jeong if ((pdata->ledb_ctrl != LM3630A_LEDB_DISABLE) && 346*28e64a68SDaniel Jeong (pdata->ledb_ctrl != LM3630A_LEDB_ON_A)) { 347*28e64a68SDaniel Jeong props.brightness = pdata->ledb_init_brt; 348*28e64a68SDaniel Jeong props.max_brightness = pdata->ledb_max_brt; 349*28e64a68SDaniel Jeong pchip->bledb = 350*28e64a68SDaniel Jeong devm_backlight_device_register(pchip->dev, "lm3630a_ledb", 351*28e64a68SDaniel Jeong pchip->dev, pchip, 352*28e64a68SDaniel Jeong &lm3630a_bank_b_ops, &props); 353*28e64a68SDaniel Jeong if (IS_ERR(pchip->bledb)) 354*28e64a68SDaniel Jeong return PTR_ERR(pchip->bledb); 355*28e64a68SDaniel Jeong } 356*28e64a68SDaniel Jeong return 0; 357*28e64a68SDaniel Jeong } 358*28e64a68SDaniel Jeong 359*28e64a68SDaniel Jeong static const struct regmap_config lm3630a_regmap = { 360*28e64a68SDaniel Jeong .reg_bits = 8, 361*28e64a68SDaniel Jeong .val_bits = 8, 362*28e64a68SDaniel Jeong .max_register = REG_MAX, 363*28e64a68SDaniel Jeong }; 364*28e64a68SDaniel Jeong 365*28e64a68SDaniel Jeong static int lm3630a_probe(struct i2c_client *client, 366*28e64a68SDaniel Jeong const struct i2c_device_id *id) 367*28e64a68SDaniel Jeong { 368*28e64a68SDaniel Jeong struct lm3630a_platform_data *pdata = client->dev.platform_data; 369*28e64a68SDaniel Jeong struct lm3630a_chip *pchip; 370*28e64a68SDaniel Jeong int rval; 371*28e64a68SDaniel Jeong 372*28e64a68SDaniel Jeong if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 373*28e64a68SDaniel Jeong dev_err(&client->dev, "fail : i2c functionality check\n"); 374*28e64a68SDaniel Jeong return -EOPNOTSUPP; 375*28e64a68SDaniel Jeong } 376*28e64a68SDaniel Jeong 377*28e64a68SDaniel Jeong pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630a_chip), 378*28e64a68SDaniel Jeong GFP_KERNEL); 379*28e64a68SDaniel Jeong if (!pchip) 380*28e64a68SDaniel Jeong return -ENOMEM; 381*28e64a68SDaniel Jeong pchip->dev = &client->dev; 382*28e64a68SDaniel Jeong 383*28e64a68SDaniel Jeong pchip->regmap = devm_regmap_init_i2c(client, &lm3630a_regmap); 384*28e64a68SDaniel Jeong if (IS_ERR(pchip->regmap)) { 385*28e64a68SDaniel Jeong rval = PTR_ERR(pchip->regmap); 386*28e64a68SDaniel Jeong dev_err(&client->dev, "fail : allocate reg. map: %d\n", rval); 387*28e64a68SDaniel Jeong return rval; 388*28e64a68SDaniel Jeong } 389*28e64a68SDaniel Jeong 390*28e64a68SDaniel Jeong i2c_set_clientdata(client, pchip); 391*28e64a68SDaniel Jeong if (pdata == NULL) { 392*28e64a68SDaniel Jeong pchip->pdata = devm_kzalloc(pchip->dev, 393*28e64a68SDaniel Jeong sizeof(struct 394*28e64a68SDaniel Jeong lm3630a_platform_data), 395*28e64a68SDaniel Jeong GFP_KERNEL); 396*28e64a68SDaniel Jeong if (pchip->pdata == NULL) 397*28e64a68SDaniel Jeong return -ENOMEM; 398*28e64a68SDaniel Jeong /* default values */ 399*28e64a68SDaniel Jeong pchip->pdata->leda_ctrl = LM3630A_LEDA_ENABLE; 400*28e64a68SDaniel Jeong pchip->pdata->ledb_ctrl = LM3630A_LEDB_ENABLE; 401*28e64a68SDaniel Jeong pchip->pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS; 402*28e64a68SDaniel Jeong pchip->pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS; 403*28e64a68SDaniel Jeong pchip->pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS; 404*28e64a68SDaniel Jeong pchip->pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS; 405*28e64a68SDaniel Jeong } else { 406*28e64a68SDaniel Jeong pchip->pdata = pdata; 407*28e64a68SDaniel Jeong } 408*28e64a68SDaniel Jeong /* chip initialize */ 409*28e64a68SDaniel Jeong rval = lm3630a_chip_init(pchip); 410*28e64a68SDaniel Jeong if (rval < 0) { 411*28e64a68SDaniel Jeong dev_err(&client->dev, "fail : init chip\n"); 412*28e64a68SDaniel Jeong return rval; 413*28e64a68SDaniel Jeong } 414*28e64a68SDaniel Jeong /* backlight register */ 415*28e64a68SDaniel Jeong rval = lm3630a_backlight_register(pchip); 416*28e64a68SDaniel Jeong if (rval < 0) { 417*28e64a68SDaniel Jeong dev_err(&client->dev, "fail : backlight register.\n"); 418*28e64a68SDaniel Jeong return rval; 419*28e64a68SDaniel Jeong } 420*28e64a68SDaniel Jeong /* pwm */ 421*28e64a68SDaniel Jeong if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) { 422*28e64a68SDaniel Jeong pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm"); 423*28e64a68SDaniel Jeong if (IS_ERR(pchip->pwmd)) { 424*28e64a68SDaniel Jeong dev_err(&client->dev, "fail : get pwm device\n"); 425*28e64a68SDaniel Jeong return PTR_ERR(pchip->pwmd); 426*28e64a68SDaniel Jeong } 427*28e64a68SDaniel Jeong } 428*28e64a68SDaniel Jeong pchip->pwmd->period = pdata->pwm_period; 429*28e64a68SDaniel Jeong 430*28e64a68SDaniel Jeong /* interrupt enable : irq 0 is not allowed */ 431*28e64a68SDaniel Jeong pchip->irq = client->irq; 432*28e64a68SDaniel Jeong if (pchip->irq) { 433*28e64a68SDaniel Jeong rval = lm3630a_intr_config(pchip); 434*28e64a68SDaniel Jeong if (rval < 0) 435*28e64a68SDaniel Jeong return rval; 436*28e64a68SDaniel Jeong } 437*28e64a68SDaniel Jeong dev_info(&client->dev, "LM3630A backlight register OK.\n"); 438*28e64a68SDaniel Jeong return 0; 439*28e64a68SDaniel Jeong } 440*28e64a68SDaniel Jeong 441*28e64a68SDaniel Jeong static int lm3630a_remove(struct i2c_client *client) 442*28e64a68SDaniel Jeong { 443*28e64a68SDaniel Jeong int rval; 444*28e64a68SDaniel Jeong struct lm3630a_chip *pchip = i2c_get_clientdata(client); 445*28e64a68SDaniel Jeong 446*28e64a68SDaniel Jeong rval = lm3630a_write(pchip, REG_BRT_A, 0); 447*28e64a68SDaniel Jeong if (rval < 0) 448*28e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 449*28e64a68SDaniel Jeong 450*28e64a68SDaniel Jeong rval = lm3630a_write(pchip, REG_BRT_B, 0); 451*28e64a68SDaniel Jeong if (rval < 0) 452*28e64a68SDaniel Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 453*28e64a68SDaniel Jeong 454*28e64a68SDaniel Jeong if (pchip->irq) { 455*28e64a68SDaniel Jeong free_irq(pchip->irq, pchip); 456*28e64a68SDaniel Jeong flush_workqueue(pchip->irqthread); 457*28e64a68SDaniel Jeong destroy_workqueue(pchip->irqthread); 458*28e64a68SDaniel Jeong } 459*28e64a68SDaniel Jeong return 0; 460*28e64a68SDaniel Jeong } 461*28e64a68SDaniel Jeong 462*28e64a68SDaniel Jeong static const struct i2c_device_id lm3630a_id[] = { 463*28e64a68SDaniel Jeong {LM3630A_NAME, 0}, 464*28e64a68SDaniel Jeong {} 465*28e64a68SDaniel Jeong }; 466*28e64a68SDaniel Jeong 467*28e64a68SDaniel Jeong MODULE_DEVICE_TABLE(i2c, lm3630a_id); 468*28e64a68SDaniel Jeong 469*28e64a68SDaniel Jeong static struct i2c_driver lm3630a_i2c_driver = { 470*28e64a68SDaniel Jeong .driver = { 471*28e64a68SDaniel Jeong .name = LM3630A_NAME, 472*28e64a68SDaniel Jeong }, 473*28e64a68SDaniel Jeong .probe = lm3630a_probe, 474*28e64a68SDaniel Jeong .remove = lm3630a_remove, 475*28e64a68SDaniel Jeong .id_table = lm3630a_id, 476*28e64a68SDaniel Jeong }; 477*28e64a68SDaniel Jeong 478*28e64a68SDaniel Jeong module_i2c_driver(lm3630a_i2c_driver); 479*28e64a68SDaniel Jeong 480*28e64a68SDaniel Jeong MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630A"); 481*28e64a68SDaniel Jeong MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>"); 482*28e64a68SDaniel Jeong MODULE_AUTHOR("LDD MLP <ldd-mlp@list.ti.com>"); 483*28e64a68SDaniel Jeong MODULE_LICENSE("GPL v2"); 484