cregit-Linux how code gets into the kernel

Release 4.14 drivers/video/backlight/lm3630a_bl.c

/*
* Simple driver for Texas Instruments LM3630A Backlight driver chip
* Copyright (C) 2012 Texas Instruments
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/backlight.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/regmap.h>
#include <linux/pwm.h>
#include <linux/platform_data/lm3630a_bl.h>


#define REG_CTRL	0x00

#define REG_BOOST	0x02

#define REG_CONFIG	0x01

#define REG_BRT_A	0x03

#define REG_BRT_B	0x04

#define REG_I_A		0x05

#define REG_I_B		0x06

#define REG_INT_STATUS	0x09

#define REG_INT_EN	0x0A

#define REG_FAULT	0x0B

#define REG_PWM_OUTLOW	0x12

#define REG_PWM_OUTHIGH	0x13

#define REG_FILTER_STRENGTH	0x50

#define REG_MAX		0x50


#define INT_DEBOUNCE_MSEC	10

struct lm3630a_chip {
	
struct device *dev;
	
struct delayed_work work;

	
int irq;
	
struct workqueue_struct *irqthread;
	
struct lm3630a_platform_data *pdata;
	
struct backlight_device *bleda;
	
struct backlight_device *bledb;
	
struct regmap *regmap;
	
struct pwm_device *pwmd;
};

/* i2c access */

static int lm3630a_read(struct lm3630a_chip *pchip, unsigned int reg) { int rval; unsigned int reg_val; rval = regmap_read(pchip->regmap, reg, &reg_val); if (rval < 0) return rval; return reg_val & 0xFF; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong50100.00%2100.00%
Total50100.00%2100.00%


static int lm3630a_write(struct lm3630a_chip *pchip, unsigned int reg, unsigned int data) { return regmap_write(pchip->regmap, reg, data); }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong31100.00%2100.00%
Total31100.00%2100.00%


static int lm3630a_update(struct lm3630a_chip *pchip, unsigned int reg, unsigned int mask, unsigned int data) { return regmap_update_bits(pchip->regmap, reg, mask, data); }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong37100.00%2100.00%
Total37100.00%2100.00%

/* initialize chip */
static int lm3630a_chip_init(struct lm3630a_chip *pchip) { int rval; struct lm3630a_platform_data *pdata = pchip->pdata; usleep_range(1000, 2000); /* set Filter Strength Register */ rval = lm3630a_write(pchip, REG_FILTER_STRENGTH, 0x03); /* set Cofig. register */ rval |= lm3630a_update(pchip, REG_CONFIG, 0x07, pdata->pwm_ctrl); /* set boost control */ rval |= lm3630a_write(pchip, REG_BOOST, 0x38); /* set current A */ rval |= lm3630a_update(pchip, REG_I_A, 0x1F, 0x1F); /* set current B */ rval |= lm3630a_write(pchip, REG_I_B, 0x1F); /* set control */ rval |= lm3630a_update(pchip, REG_CTRL, 0x14, pdata->leda_ctrl); rval |= lm3630a_update(pchip, REG_CTRL, 0x0B, pdata->ledb_ctrl); usleep_range(1000, 2000); /* set brightness A and B */ rval |= lm3630a_write(pchip, REG_BRT_A, pdata->leda_init_brt); rval |= lm3630a_write(pchip, REG_BRT_B, pdata->ledb_init_brt); if (rval < 0) dev_err(pchip->dev, "i2c failed to access register\n"); return rval; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong17899.44%375.00%
Bhushan Shah10.56%125.00%
Total179100.00%4100.00%

/* interrupt handling */
static void lm3630a_delayed_func(struct work_struct *work) { int rval; struct lm3630a_chip *pchip; pchip = container_of(work, struct lm3630a_chip, work.work); rval = lm3630a_read(pchip, REG_INT_STATUS); if (rval < 0) { dev_err(pchip->dev, "i2c failed to access REG_INT_STATUS Register\n"); return; } dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", rval); }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong71100.00%2100.00%
Total71100.00%2100.00%


static irqreturn_t lm3630a_isr_func(int irq, void *chip) { int rval; struct lm3630a_chip *pchip = chip; unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC); queue_delayed_work(pchip->irqthread, &pchip->work, delay); rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); if (rval < 0) { dev_err(pchip->dev, "i2c failed to access register\n"); return IRQ_NONE; } return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong82100.00%2100.00%
Total82100.00%2100.00%


static int lm3630a_intr_config(struct lm3630a_chip *pchip) { int rval; rval = lm3630a_write(pchip, REG_INT_EN, 0x87); if (rval < 0) return rval; INIT_DELAYED_WORK(&pchip->work, lm3630a_delayed_func); pchip->irqthread = create_singlethread_workqueue("lm3630a-irqthd"); if (!pchip->irqthread) { dev_err(pchip->dev, "create irq thread fail\n"); return -ENOMEM; } if (request_threaded_irq (pchip->irq, NULL, lm3630a_isr_func, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630a_irq", pchip)) { dev_err(pchip->dev, "request threaded irq fail\n"); destroy_workqueue(pchip->irqthread); return -ENOMEM; } return rval; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong11494.21%266.67%
Wei Yongjun75.79%133.33%
Total121100.00%3100.00%


static void lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max) { unsigned int period = pchip->pdata->pwm_period; unsigned int duty = br * period / br_max; pwm_config(pchip->pwmd, duty, period); if (duty) pwm_enable(pchip->pwmd); else pwm_disable(pchip->pwmd); }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong6495.52%266.67%
Boris Brezillon34.48%133.33%
Total67100.00%3100.00%

/* update and get brightness */
static int lm3630a_bank_a_update_status(struct backlight_device *bl) { int ret; struct lm3630a_chip *pchip = bl_get_data(bl); enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; /* pwm control */ if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) { lm3630a_pwm_ctrl(pchip, bl->props.brightness, bl->props.max_brightness); return bl->props.brightness; } /* disable sleep */ ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); if (ret < 0) goto out_i2c_err; usleep_range(1000, 2000); /* minimum brightness is 0x04 */ ret = lm3630a_write(pchip, REG_BRT_A, bl->props.brightness); if (bl->props.brightness < 0x4) ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0); else ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE); if (ret < 0) goto out_i2c_err; return bl->props.brightness; out_i2c_err: dev_err(pchip->dev, "i2c failed to access\n"); return bl->props.brightness; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong188100.00%2100.00%
Total188100.00%2100.00%


static int lm3630a_bank_a_get_brightness(struct backlight_device *bl) { int brightness, rval; struct lm3630a_chip *pchip = bl_get_data(bl); enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) { rval = lm3630a_read(pchip, REG_PWM_OUTHIGH); if (rval < 0) goto out_i2c_err; brightness = (rval & 0x01) << 8; rval = lm3630a_read(pchip, REG_PWM_OUTLOW); if (rval < 0) goto out_i2c_err; brightness |= rval; goto out; } /* disable sleep */ rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); if (rval < 0) goto out_i2c_err; usleep_range(1000, 2000); rval = lm3630a_read(pchip, REG_BRT_A); if (rval < 0) goto out_i2c_err; brightness = rval; out: bl->props.brightness = brightness; return bl->props.brightness; out_i2c_err: dev_err(pchip->dev, "i2c failed to access register\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong184100.00%2100.00%
Total184100.00%2100.00%

static const struct backlight_ops lm3630a_bank_a_ops = { .options = BL_CORE_SUSPENDRESUME, .update_status = lm3630a_bank_a_update_status, .get_brightness = lm3630a_bank_a_get_brightness, }; /* update and get brightness */
static int lm3630a_bank_b_update_status(struct backlight_device *bl) { int ret; struct lm3630a_chip *pchip = bl_get_data(bl); enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; /* pwm control */ if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) { lm3630a_pwm_ctrl(pchip, bl->props.brightness, bl->props.max_brightness); return bl->props.brightness; } /* disable sleep */ ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); if (ret < 0) goto out_i2c_err; usleep_range(1000, 2000); /* minimum brightness is 0x04 */ ret = lm3630a_write(pchip, REG_BRT_B, bl->props.brightness); if (bl->props.brightness < 0x4) ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0); else ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE); if (ret < 0) goto out_i2c_err; return bl->props.brightness; out_i2c_err: dev_err(pchip->dev, "i2c failed to access REG_CTRL\n"); return bl->props.brightness; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong188100.00%2100.00%
Total188100.00%2100.00%


static int lm3630a_bank_b_get_brightness(struct backlight_device *bl) { int brightness, rval; struct lm3630a_chip *pchip = bl_get_data(bl); enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl; if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) { rval = lm3630a_read(pchip, REG_PWM_OUTHIGH); if (rval < 0) goto out_i2c_err; brightness = (rval & 0x01) << 8; rval = lm3630a_read(pchip, REG_PWM_OUTLOW); if (rval < 0) goto out_i2c_err; brightness |= rval; goto out; } /* disable sleep */ rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00); if (rval < 0) goto out_i2c_err; usleep_range(1000, 2000); rval = lm3630a_read(pchip, REG_BRT_B); if (rval < 0) goto out_i2c_err; brightness = rval; out: bl->props.brightness = brightness; return bl->props.brightness; out_i2c_err: dev_err(pchip->dev, "i2c failed to access register\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong184100.00%2100.00%
Total184100.00%2100.00%

static const struct backlight_ops lm3630a_bank_b_ops = { .options = BL_CORE_SUSPENDRESUME, .update_status = lm3630a_bank_b_update_status, .get_brightness = lm3630a_bank_b_get_brightness, };
static int lm3630a_backlight_register(struct lm3630a_chip *pchip) { struct backlight_properties props; struct lm3630a_platform_data *pdata = pchip->pdata; props.type = BACKLIGHT_RAW; if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) { props.brightness = pdata->leda_init_brt; props.max_brightness = pdata->leda_max_brt; pchip->bleda = devm_backlight_device_register(pchip->dev, "lm3630a_leda", pchip->dev, pchip, &lm3630a_bank_a_ops, &props); if (IS_ERR(pchip->bleda)) return PTR_ERR(pchip->bleda); } if ((pdata->ledb_ctrl != LM3630A_LEDB_DISABLE) && (pdata->ledb_ctrl != LM3630A_LEDB_ON_A)) { props.brightness = pdata->ledb_init_brt; props.max_brightness = pdata->ledb_max_brt; pchip->bledb = devm_backlight_device_register(pchip->dev, "lm3630a_ledb", pchip->dev, pchip, &lm3630a_bank_b_ops, &props); if (IS_ERR(pchip->bledb)) return PTR_ERR(pchip->bledb); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong16994.41%266.67%
Jingoo Han105.59%133.33%
Total179100.00%3100.00%

static const struct regmap_config lm3630a_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = REG_MAX, };
static int lm3630a_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lm3630a_platform_data *pdata = dev_get_platdata(&client->dev); struct lm3630a_chip *pchip; int rval; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "fail : i2c functionality check\n"); return -EOPNOTSUPP; } pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630a_chip), GFP_KERNEL); if (!pchip) return -ENOMEM; pchip->dev = &client->dev; pchip->regmap = devm_regmap_init_i2c(client, &lm3630a_regmap); if (IS_ERR(pchip->regmap)) { rval = PTR_ERR(pchip->regmap); dev_err(&client->dev, "fail : allocate reg. map: %d\n", rval); return rval; } i2c_set_clientdata(client, pchip); if (pdata == NULL) { pdata = devm_kzalloc(pchip->dev, sizeof(struct lm3630a_platform_data), GFP_KERNEL); if (pdata == NULL) return -ENOMEM; /* default values */ pdata->leda_ctrl = LM3630A_LEDA_ENABLE; pdata->ledb_ctrl = LM3630A_LEDB_ENABLE; pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS; pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS; pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS; pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS; } pchip->pdata = pdata; /* chip initialize */ rval = lm3630a_chip_init(pchip); if (rval < 0) { dev_err(&client->dev, "fail : init chip\n"); return rval; } /* backlight register */ rval = lm3630a_backlight_register(pchip); if (rval < 0) { dev_err(&client->dev, "fail : backlight register.\n"); return rval; } /* pwm */ if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) { pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm"); if (IS_ERR(pchip->pwmd)) { dev_err(&client->dev, "fail : get pwm device\n"); return PTR_ERR(pchip->pwmd); } /* * FIXME: pwm_apply_args() should be removed when switching to * the atomic PWM API. */ pwm_apply_args(pchip->pwmd); } /* interrupt enable : irq 0 is not allowed */ pchip->irq = client->irq; if (pchip->irq) { rval = lm3630a_intr_config(pchip); if (rval < 0) return rval; } dev_info(&client->dev, "LM3630A backlight register OK.\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong38796.99%250.00%
Boris Brezillon82.01%125.00%
Jingoo Han41.00%125.00%
Total399100.00%4100.00%


static int lm3630a_remove(struct i2c_client *client) { int rval; struct lm3630a_chip *pchip = i2c_get_clientdata(client); rval = lm3630a_write(pchip, REG_BRT_A, 0); if (rval < 0) dev_err(pchip->dev, "i2c failed to access register\n"); rval = lm3630a_write(pchip, REG_BRT_B, 0); if (rval < 0) dev_err(pchip->dev, "i2c failed to access register\n"); if (pchip->irq) { free_irq(pchip->irq, pchip); flush_workqueue(pchip->irqthread); destroy_workqueue(pchip->irqthread); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong110100.00%2100.00%
Total110100.00%2100.00%

static const struct i2c_device_id lm3630a_id[] = { {LM3630A_NAME, 0}, {} }; MODULE_DEVICE_TABLE(i2c, lm3630a_id); static struct i2c_driver lm3630a_i2c_driver = { .driver = { .name = LM3630A_NAME, }, .probe = lm3630a_probe, .remove = lm3630a_remove, .id_table = lm3630a_id, }; module_i2c_driver(lm3630a_i2c_driver); MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630A"); MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>"); MODULE_AUTHOR("LDD MLP <ldd-mlp@list.ti.com>"); MODULE_LICENSE("GPL v2");

Overall Contributors

PersonTokensPropCommitsCommitProp
Daniel Jeong232898.39%333.33%
Jingoo Han140.59%222.22%
Boris Brezillon110.46%222.22%
Wei Yongjun70.30%111.11%
Bhushan Shah60.25%111.11%
Total2366100.00%9100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.