10f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong/* 20f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong* Simple driver for Texas Instruments LM3639 Backlight + Flash LED driver chip 30f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong* Copyright (C) 2012 Texas Instruments 40f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong* 50f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong* This program is free software; you can redistribute it and/or modify 60f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong* it under the terms of the GNU General Public License version 2 as 70f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong* published by the Free Software Foundation. 80f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong* 90f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong*/ 100f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#include <linux/module.h> 110f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#include <linux/slab.h> 120f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#include <linux/i2c.h> 130f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#include <linux/leds.h> 140f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#include <linux/backlight.h> 150f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#include <linux/err.h> 160f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#include <linux/delay.h> 170f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#include <linux/uaccess.h> 180f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#include <linux/interrupt.h> 190f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#include <linux/regmap.h> 200f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#include <linux/platform_data/lm3639_bl.h> 210f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 220f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#define REG_DEV_ID 0x00 230f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#define REG_CHECKSUM 0x01 240f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#define REG_BL_CONF_1 0x02 250f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#define REG_BL_CONF_2 0x03 260f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#define REG_BL_CONF_3 0x04 270f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#define REG_BL_CONF_4 0x05 280f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#define REG_FL_CONF_1 0x06 290f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#define REG_FL_CONF_2 0x07 300f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#define REG_FL_CONF_3 0x08 310f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#define REG_IO_CTRL 0x09 320f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#define REG_ENABLE 0x0A 330f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#define REG_FLAG 0x0B 340f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong#define REG_MAX REG_FLAG 350f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 360f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongstruct lm3639_chip_data { 370f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct device *dev; 380f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct lm3639_platform_data *pdata; 390f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 400f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct backlight_device *bled; 410f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct led_classdev cdev_flash; 420f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct led_classdev cdev_torch; 430f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct regmap *regmap; 440f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 450f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong unsigned int bled_mode; 460f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong unsigned int bled_map; 470f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong unsigned int last_flag; 480f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong}; 490f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 500f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong/* initialize chip */ 511b9e450de105c1429a15f4e2566695f4f425672aBill Pembertonstatic int lm3639_chip_init(struct lm3639_chip_data *pchip) 520f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong{ 530f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong int ret; 540f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong unsigned int reg_val; 550f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct lm3639_platform_data *pdata = pchip->pdata; 560f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 570f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong /* input pins config. */ 580f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = 590f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x08, 600f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pdata->pin_pwm); 610f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 620f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 630f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 640f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong reg_val = (pdata->pin_pwm & 0x40) | pdata->pin_strobe | pdata->pin_tx; 650f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_update_bits(pchip->regmap, REG_IO_CTRL, 0x7C, reg_val); 660f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 670f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 680f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 690f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong /* init brightness */ 700f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_write(pchip->regmap, REG_BL_CONF_4, pdata->init_brt_led); 710f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 720f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 730f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 740f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_write(pchip->regmap, REG_BL_CONF_3, pdata->init_brt_led); 750f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 760f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 770f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 780f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong /* output pins config. */ 790ab7b20fa011f25f900b04e8f6f6e8221864eefdJingoo Han if (!pdata->init_brt_led) { 800ab7b20fa011f25f900b04e8f6f6e8221864eefdJingoo Han reg_val = pdata->fled_pins; 810ab7b20fa011f25f900b04e8f6f6e8221864eefdJingoo Han reg_val |= pdata->bled_pins; 820ab7b20fa011f25f900b04e8f6f6e8221864eefdJingoo Han } else { 830ab7b20fa011f25f900b04e8f6f6e8221864eefdJingoo Han reg_val = pdata->fled_pins; 840ab7b20fa011f25f900b04e8f6f6e8221864eefdJingoo Han reg_val |= pdata->bled_pins | 0x01; 850ab7b20fa011f25f900b04e8f6f6e8221864eefdJingoo Han } 860f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 870f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x79, reg_val); 880f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 890f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 900f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 910f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return ret; 920f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongout: 930f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 940f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return ret; 950f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong} 960f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 970f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong/* update and get brightness */ 980f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongstatic int lm3639_bled_update_status(struct backlight_device *bl) 990f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong{ 1000f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong int ret; 1010f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong unsigned int reg_val; 1020f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct lm3639_chip_data *pchip = bl_get_data(bl); 1030f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct lm3639_platform_data *pdata = pchip->pdata; 1040f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1050f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); 1060f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 1070f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 1080f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1090f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (reg_val != 0) 1100f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); 1110f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1120f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong /* pwm control */ 1130f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (pdata->pin_pwm) { 1140f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (pdata->pwm_set_intensity) 1150f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pdata->pwm_set_intensity(bl->props.brightness, 1160f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pdata->max_brt_led); 1170f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong else 1180f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(pchip->dev, 1190f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong "No pwm control func. in plat-data\n"); 1200f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return bl->props.brightness; 1210f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong } 1220f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1230f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong /* i2c control and set brigtness */ 1240f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_write(pchip->regmap, REG_BL_CONF_4, bl->props.brightness); 1250f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 1260f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 1270f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_write(pchip->regmap, REG_BL_CONF_3, bl->props.brightness); 1280f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 1290f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 1300f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1310f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (!bl->props.brightness) 1320f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x00); 1330f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong else 1340f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x01); 1350f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 1360f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 1370f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1380f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return bl->props.brightness; 1390f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongout: 1400f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(pchip->dev, "i2c failed to access registers\n"); 1410f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return bl->props.brightness; 1420f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong} 1430f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1440f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongstatic int lm3639_bled_get_brightness(struct backlight_device *bl) 1450f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong{ 1460f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong int ret; 1470f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong unsigned int reg_val; 1480f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct lm3639_chip_data *pchip = bl_get_data(bl); 1490f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct lm3639_platform_data *pdata = pchip->pdata; 1500f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1510f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (pdata->pin_pwm) { 1520f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (pdata->pwm_get_intensity) 1530f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong bl->props.brightness = pdata->pwm_get_intensity(); 1540f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong else 1550f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(pchip->dev, 1560f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong "No pwm control func. in plat-data\n"); 1570f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return bl->props.brightness; 1580f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong } 1590f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1600f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_read(pchip->regmap, REG_BL_CONF_1, ®_val); 1610f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 1620f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 1630f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (reg_val & 0x10) 1640f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_read(pchip->regmap, REG_BL_CONF_4, ®_val); 1650f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong else 1660f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_read(pchip->regmap, REG_BL_CONF_3, ®_val); 1670f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 1680f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 1690f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong bl->props.brightness = reg_val; 1700f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1710f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return bl->props.brightness; 1720f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongout: 1730f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 1740f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return bl->props.brightness; 1750f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong} 1760f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1770f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongstatic const struct backlight_ops lm3639_bled_ops = { 1780f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong .options = BL_CORE_SUSPENDRESUME, 1790f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong .update_status = lm3639_bled_update_status, 1800f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong .get_brightness = lm3639_bled_get_brightness, 1810f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong}; 1820f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1830f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong/* backlight mapping mode */ 1840f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongstatic ssize_t lm3639_bled_mode_store(struct device *dev, 1850f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct device_attribute *devAttr, 1860f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong const char *buf, size_t size) 1870f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong{ 1880f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ssize_t ret; 1890f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct lm3639_chip_data *pchip = dev_get_drvdata(dev); 1900f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong unsigned int state; 1910f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1920f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = kstrtouint(buf, 10, &state); 1930f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret) 1940f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out_input; 1950f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 1960f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (!state) 1970f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = 1980f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10, 1990f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 0x00); 2000f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong else 2010f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = 2020f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10, 2030f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 0x10); 2040f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2050f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 2060f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 2070f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2080f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return size; 2090f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2100f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongout: 2110f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(pchip->dev, "%s:i2c access fail to register\n", __func__); 212dc36d7e7cd422d69b15e7ec7cc1f021f581a6b6dAxel Lin return ret; 2130f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2140f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongout_input: 2150f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(pchip->dev, "%s:input conversion fail\n", __func__); 216dc36d7e7cd422d69b15e7ec7cc1f021f581a6b6dAxel Lin return ret; 2170f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2180f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong} 2190f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 220fb08cd9b111c6a922f468ef5e33acc67eb91d40bAxel Linstatic DEVICE_ATTR(bled_mode, S_IWUSR, NULL, lm3639_bled_mode_store); 2210f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2220f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong/* torch */ 2230f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongstatic void lm3639_torch_brightness_set(struct led_classdev *cdev, 2240f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong enum led_brightness brightness) 2250f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong{ 2260f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong int ret; 2270f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong unsigned int reg_val; 2280f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct lm3639_chip_data *pchip; 2290f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2300f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pchip = container_of(cdev, struct lm3639_chip_data, cdev_torch); 2310f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2320f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); 2330f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 2340f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 2350f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (reg_val != 0) 2360f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); 2370f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2380f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong /* brightness 0 means off state */ 2390f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (!brightness) { 2400f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00); 2410f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 2420f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 2430f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return; 2440f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong } 2450f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2460f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_update_bits(pchip->regmap, 2470f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong REG_FL_CONF_1, 0x70, (brightness - 1) << 4); 2480f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 2490f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 2500f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x02); 2510f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 2520f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 2530f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2540f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return; 2550f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongout: 2560f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 2570f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong} 2580f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2590f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong/* flash */ 2600f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongstatic void lm3639_flash_brightness_set(struct led_classdev *cdev, 2610f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong enum led_brightness brightness) 2620f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong{ 2630f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong int ret; 2640f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong unsigned int reg_val; 2650f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct lm3639_chip_data *pchip; 2660f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2670f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pchip = container_of(cdev, struct lm3639_chip_data, cdev_flash); 2680f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2690f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_read(pchip->regmap, REG_FLAG, ®_val); 2700f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 2710f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 2720f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (reg_val != 0) 2730f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_info(pchip->dev, "last flag is 0x%x\n", reg_val); 2740f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2750f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong /* torch off before flash control */ 2760f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00); 2770f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 2780f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 2790f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2800f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong /* brightness 0 means off state */ 2810f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (!brightness) 2820f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return; 2830f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2840f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_update_bits(pchip->regmap, 2850f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong REG_FL_CONF_1, 0x0F, brightness - 1); 2860f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 2870f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 2880f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x06); 2890f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) 2900f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto out; 2910f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2920f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return; 2930f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongout: 2940f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(pchip->dev, "i2c failed to access register\n"); 2950f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong} 2960f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 2970f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongstatic const struct regmap_config lm3639_regmap = { 2980f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong .reg_bits = 8, 2990f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong .val_bits = 8, 3000f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong .max_register = REG_MAX, 3010f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong}; 3020f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3031b9e450de105c1429a15f4e2566695f4f425672aBill Pembertonstatic int lm3639_probe(struct i2c_client *client, 3040f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong const struct i2c_device_id *id) 3050f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong{ 3060f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong int ret; 3070f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct lm3639_chip_data *pchip; 308c512794cada491e008eeca822af7e4ad5db72a56Jingoo Han struct lm3639_platform_data *pdata = dev_get_platdata(&client->dev); 3090f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct backlight_properties props; 3100f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3110f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 3120f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(&client->dev, "i2c functionality check fail.\n"); 3130f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return -EOPNOTSUPP; 3140f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong } 3150f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3160f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (pdata == NULL) { 3170f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(&client->dev, "Needs Platform Data.\n"); 3180f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return -ENODATA; 3190f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong } 3200f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3210f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pchip = devm_kzalloc(&client->dev, 3220f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong sizeof(struct lm3639_chip_data), GFP_KERNEL); 3230f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (!pchip) 3240f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return -ENOMEM; 3250f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3260f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pchip->pdata = pdata; 3270f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pchip->dev = &client->dev; 3280f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3290f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pchip->regmap = devm_regmap_init_i2c(client, &lm3639_regmap); 3300f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (IS_ERR(pchip->regmap)) { 3310f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = PTR_ERR(pchip->regmap); 3320f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(&client->dev, "fail : allocate register map: %d\n", 3330f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret); 3340f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return ret; 3350f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong } 3360f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong i2c_set_clientdata(client, pchip); 3370f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3380f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong /* chip initialize */ 3390f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = lm3639_chip_init(pchip); 3400f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) { 3410f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(&client->dev, "fail : chip init\n"); 3420f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto err_out; 3430f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong } 3440f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3450f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong /* backlight */ 3460f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong props.type = BACKLIGHT_RAW; 3470f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong props.brightness = pdata->init_brt_led; 3480f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong props.max_brightness = pdata->max_brt_led; 3490f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pchip->bled = 350f1740e4cffede3e919a3511bf4e5113d642f09ecDaniel Jeong devm_backlight_device_register(pchip->dev, "lm3639_bled", 351f1740e4cffede3e919a3511bf4e5113d642f09ecDaniel Jeong pchip->dev, pchip, &lm3639_bled_ops, 352f1740e4cffede3e919a3511bf4e5113d642f09ecDaniel Jeong &props); 3530f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (IS_ERR(pchip->bled)) { 3540f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(&client->dev, "fail : backlight register\n"); 355aea00a6c370cff79b58503c012943d6a298eb527Devendra Naga ret = PTR_ERR(pchip->bled); 3560f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto err_out; 3570f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong } 3580f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3590f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode); 3600f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) { 3610f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(&client->dev, "failed : add sysfs entries\n"); 362f1740e4cffede3e919a3511bf4e5113d642f09ecDaniel Jeong goto err_out; 3630f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong } 3640f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3650f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong /* flash */ 3660f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pchip->cdev_flash.name = "lm3639_flash"; 3670f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pchip->cdev_flash.max_brightness = 16; 3680f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pchip->cdev_flash.brightness_set = lm3639_flash_brightness_set; 3690f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = led_classdev_register((struct device *) 3700f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong &client->dev, &pchip->cdev_flash); 3710f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) { 3720f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(&client->dev, "fail : flash register\n"); 3730f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto err_flash; 3740f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong } 3750f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3760f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong /* torch */ 3770f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pchip->cdev_torch.name = "lm3639_torch"; 3780f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pchip->cdev_torch.max_brightness = 8; 3790f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong pchip->cdev_torch.brightness_set = lm3639_torch_brightness_set; 3800f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong ret = led_classdev_register((struct device *) 3810f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong &client->dev, &pchip->cdev_torch); 3820f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (ret < 0) { 3830f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong dev_err(&client->dev, "fail : torch register\n"); 3840f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong goto err_torch; 3850f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong } 3860f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3870f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return 0; 3880f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3890f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongerr_torch: 3900f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong led_classdev_unregister(&pchip->cdev_flash); 3910f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongerr_flash: 3920f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); 3930f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongerr_out: 3940f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return ret; 3950f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong} 3960f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 3977e4b9d0bb2a6464e541d51a1e59ba73470c7c453Bill Pembertonstatic int lm3639_remove(struct i2c_client *client) 3980f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong{ 3990f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong struct lm3639_chip_data *pchip = i2c_get_clientdata(client); 4000f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 4010f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong regmap_write(pchip->regmap, REG_ENABLE, 0x00); 4020f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 4030f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (&pchip->cdev_torch) 4040f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong led_classdev_unregister(&pchip->cdev_torch); 4050f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong if (&pchip->cdev_flash) 4060f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong led_classdev_unregister(&pchip->cdev_flash); 407f1740e4cffede3e919a3511bf4e5113d642f09ecDaniel Jeong if (pchip->bled) 4080f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode); 4090f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong return 0; 4100f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong} 4110f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 4120f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongstatic const struct i2c_device_id lm3639_id[] = { 4130f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong {LM3639_NAME, 0}, 4140f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong {} 4150f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong}; 4160f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 4170f59858d511960caefb42c4535dc73c2c5f3136cG.Shark JeongMODULE_DEVICE_TABLE(i2c, lm3639_id); 4180f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongstatic struct i2c_driver lm3639_i2c_driver = { 4190f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong .driver = { 4200f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong .name = LM3639_NAME, 4210f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong }, 4220f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong .probe = lm3639_probe, 423d1723fa266aff677571cad0bac7203ed2e424823Bill Pemberton .remove = lm3639_remove, 4240f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong .id_table = lm3639_id, 4250f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong}; 4260f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 4270f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeongmodule_i2c_driver(lm3639_i2c_driver); 4280f59858d511960caefb42c4535dc73c2c5f3136cG.Shark Jeong 4290f59858d511960caefb42c4535dc73c2c5f3136cG.Shark JeongMODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639"); 430f1740e4cffede3e919a3511bf4e5113d642f09ecDaniel JeongMODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>"); 431f1740e4cffede3e919a3511bf4e5113d642f09ecDaniel JeongMODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>"); 4320f59858d511960caefb42c4535dc73c2c5f3136cG.Shark JeongMODULE_LICENSE("GPL v2"); 433