brintos

brintos / linux-shallow public Read only

0
0
Text · 15.6 KiB · 37651c2 Raw
628 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3* Simple driver for Texas Instruments LM3630A Backlight driver chip4* Copyright (C) 2012 Texas Instruments5*/6#include <linux/module.h>7#include <linux/slab.h>8#include <linux/i2c.h>9#include <linux/backlight.h>10#include <linux/err.h>11#include <linux/delay.h>12#include <linux/uaccess.h>13#include <linux/interrupt.h>14#include <linux/regmap.h>15#include <linux/gpio/consumer.h>16#include <linux/pwm.h>17#include <linux/platform_data/lm3630a_bl.h>18 19#define REG_CTRL	0x0020#define REG_BOOST	0x0221#define REG_CONFIG	0x0122#define REG_BRT_A	0x0323#define REG_BRT_B	0x0424#define REG_I_A		0x0525#define REG_I_B		0x0626#define REG_INT_STATUS	0x0927#define REG_INT_EN	0x0A28#define REG_FAULT	0x0B29#define REG_PWM_OUTLOW	0x1230#define REG_PWM_OUTHIGH	0x1331#define REG_FILTER_STRENGTH	0x5032#define REG_MAX		0x5033 34#define INT_DEBOUNCE_MSEC	1035 36#define LM3630A_BANK_0		037#define LM3630A_BANK_1		138 39#define LM3630A_NUM_SINKS	240#define LM3630A_SINK_0		041#define LM3630A_SINK_1		142 43struct lm3630a_chip {44	struct device *dev;45	struct delayed_work work;46 47	int irq;48	struct workqueue_struct *irqthread;49	struct lm3630a_platform_data *pdata;50	struct backlight_device *bleda;51	struct backlight_device *bledb;52	struct gpio_desc *enable_gpio;53	struct regmap *regmap;54	struct pwm_device *pwmd;55	struct pwm_state pwmd_state;56};57 58/* i2c access */59static int lm3630a_read(struct lm3630a_chip *pchip, unsigned int reg)60{61	int rval;62	unsigned int reg_val;63 64	rval = regmap_read(pchip->regmap, reg, &reg_val);65	if (rval < 0)66		return rval;67	return reg_val & 0xFF;68}69 70static int lm3630a_write(struct lm3630a_chip *pchip,71			 unsigned int reg, unsigned int data)72{73	return regmap_write(pchip->regmap, reg, data);74}75 76static int lm3630a_update(struct lm3630a_chip *pchip,77			  unsigned int reg, unsigned int mask,78			  unsigned int data)79{80	return regmap_update_bits(pchip->regmap, reg, mask, data);81}82 83/* initialize chip */84static int lm3630a_chip_init(struct lm3630a_chip *pchip)85{86	int rval;87	struct lm3630a_platform_data *pdata = pchip->pdata;88 89	usleep_range(1000, 2000);90	/* set Filter Strength Register */91	rval = lm3630a_write(pchip, REG_FILTER_STRENGTH, 0x03);92	/* set Cofig. register */93	rval |= lm3630a_update(pchip, REG_CONFIG, 0x07, pdata->pwm_ctrl);94	/* set boost control */95	rval |= lm3630a_write(pchip, REG_BOOST, 0x38);96	/* set current A */97	rval |= lm3630a_update(pchip, REG_I_A, 0x1F, 0x1F);98	/* set current B */99	rval |= lm3630a_write(pchip, REG_I_B, 0x1F);100	/* set control */101	rval |= lm3630a_update(pchip, REG_CTRL, 0x14, pdata->leda_ctrl);102	rval |= lm3630a_update(pchip, REG_CTRL, 0x0B, pdata->ledb_ctrl);103	usleep_range(1000, 2000);104	/* set brightness A and B */105	rval |= lm3630a_write(pchip, REG_BRT_A, pdata->leda_init_brt);106	rval |= lm3630a_write(pchip, REG_BRT_B, pdata->ledb_init_brt);107 108	if (rval < 0)109		dev_err(pchip->dev, "i2c failed to access register\n");110	return rval;111}112 113/* interrupt handling */114static void lm3630a_delayed_func(struct work_struct *work)115{116	int rval;117	struct lm3630a_chip *pchip;118 119	pchip = container_of(work, struct lm3630a_chip, work.work);120 121	rval = lm3630a_read(pchip, REG_INT_STATUS);122	if (rval < 0) {123		dev_err(pchip->dev,124			"i2c failed to access REG_INT_STATUS Register\n");125		return;126	}127 128	dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", rval);129}130 131static irqreturn_t lm3630a_isr_func(int irq, void *chip)132{133	int rval;134	struct lm3630a_chip *pchip = chip;135	unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC);136 137	queue_delayed_work(pchip->irqthread, &pchip->work, delay);138 139	rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);140	if (rval < 0) {141		dev_err(pchip->dev, "i2c failed to access register\n");142		return IRQ_NONE;143	}144	return IRQ_HANDLED;145}146 147static int lm3630a_intr_config(struct lm3630a_chip *pchip)148{149	int rval;150 151	rval = lm3630a_write(pchip, REG_INT_EN, 0x87);152	if (rval < 0)153		return rval;154 155	INIT_DELAYED_WORK(&pchip->work, lm3630a_delayed_func);156	pchip->irqthread = create_singlethread_workqueue("lm3630a-irqthd");157	if (!pchip->irqthread) {158		dev_err(pchip->dev, "create irq thread fail\n");159		return -ENOMEM;160	}161	if (request_threaded_irq162	    (pchip->irq, NULL, lm3630a_isr_func,163	     IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630a_irq", pchip)) {164		dev_err(pchip->dev, "request threaded irq fail\n");165		destroy_workqueue(pchip->irqthread);166		return -ENOMEM;167	}168	return rval;169}170 171static int lm3630a_pwm_ctrl(struct lm3630a_chip *pchip, int br, int br_max)172{173	int err;174 175	pchip->pwmd_state.period = pchip->pdata->pwm_period;176 177	err = pwm_set_relative_duty_cycle(&pchip->pwmd_state, br, br_max);178	if (err)179		return err;180 181	pchip->pwmd_state.enabled = pchip->pwmd_state.duty_cycle ? true : false;182 183	return pwm_apply_might_sleep(pchip->pwmd, &pchip->pwmd_state);184}185 186/* update and get brightness */187static int lm3630a_bank_a_update_status(struct backlight_device *bl)188{189	int ret;190	struct lm3630a_chip *pchip = bl_get_data(bl);191	enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;192	int brightness = backlight_get_brightness(bl);193 194	/* pwm control */195	if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0)196		return lm3630a_pwm_ctrl(pchip, brightness,197					bl->props.max_brightness);198 199	/* disable sleep */200	ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);201	if (ret < 0)202		goto out_i2c_err;203	usleep_range(1000, 2000);204	/* minimum brightness is 0x04 */205	ret = lm3630a_write(pchip, REG_BRT_A, brightness);206 207	if (brightness < 0x4)208		/* turn the string off  */209		ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDA_ENABLE, 0);210	else211		ret |= lm3630a_update(pchip, REG_CTRL,212				      LM3630A_LEDA_ENABLE, LM3630A_LEDA_ENABLE);213	if (ret < 0)214		goto out_i2c_err;215	return 0;216 217out_i2c_err:218	dev_err(pchip->dev, "i2c failed to access (%pe)\n", ERR_PTR(ret));219	return ret;220}221 222static int lm3630a_bank_a_get_brightness(struct backlight_device *bl)223{224	int brightness, rval;225	struct lm3630a_chip *pchip = bl_get_data(bl);226	enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;227 228	if ((pwm_ctrl & LM3630A_PWM_BANK_A) != 0) {229		rval = lm3630a_read(pchip, REG_PWM_OUTHIGH);230		if (rval < 0)231			goto out_i2c_err;232		brightness = (rval & 0x01) << 8;233		rval = lm3630a_read(pchip, REG_PWM_OUTLOW);234		if (rval < 0)235			goto out_i2c_err;236		brightness |= rval;237		return brightness;238	}239 240	/* disable sleep */241	rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);242	if (rval < 0)243		goto out_i2c_err;244	usleep_range(1000, 2000);245	rval = lm3630a_read(pchip, REG_BRT_A);246	if (rval < 0)247		goto out_i2c_err;248	return rval;249 250out_i2c_err:251	dev_err(pchip->dev, "i2c failed to access register\n");252	return 0;253}254 255static const struct backlight_ops lm3630a_bank_a_ops = {256	.options = BL_CORE_SUSPENDRESUME,257	.update_status = lm3630a_bank_a_update_status,258	.get_brightness = lm3630a_bank_a_get_brightness,259};260 261/* update and get brightness */262static int lm3630a_bank_b_update_status(struct backlight_device *bl)263{264	int ret;265	struct lm3630a_chip *pchip = bl_get_data(bl);266	enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;267	int brightness = backlight_get_brightness(bl);268 269	/* pwm control */270	if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0)271		return lm3630a_pwm_ctrl(pchip, brightness,272					bl->props.max_brightness);273 274	/* disable sleep */275	ret = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);276	if (ret < 0)277		goto out_i2c_err;278	usleep_range(1000, 2000);279	/* minimum brightness is 0x04 */280	ret = lm3630a_write(pchip, REG_BRT_B, brightness);281 282	if (brightness < 0x4)283		/* turn the string off  */284		ret |= lm3630a_update(pchip, REG_CTRL, LM3630A_LEDB_ENABLE, 0);285	else286		ret |= lm3630a_update(pchip, REG_CTRL,287				      LM3630A_LEDB_ENABLE, LM3630A_LEDB_ENABLE);288	if (ret < 0)289		goto out_i2c_err;290	return 0;291 292out_i2c_err:293	dev_err(pchip->dev, "i2c failed to access (%pe)\n", ERR_PTR(ret));294	return ret;295}296 297static int lm3630a_bank_b_get_brightness(struct backlight_device *bl)298{299	int brightness, rval;300	struct lm3630a_chip *pchip = bl_get_data(bl);301	enum lm3630a_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;302 303	if ((pwm_ctrl & LM3630A_PWM_BANK_B) != 0) {304		rval = lm3630a_read(pchip, REG_PWM_OUTHIGH);305		if (rval < 0)306			goto out_i2c_err;307		brightness = (rval & 0x01) << 8;308		rval = lm3630a_read(pchip, REG_PWM_OUTLOW);309		if (rval < 0)310			goto out_i2c_err;311		brightness |= rval;312		return brightness;313	}314 315	/* disable sleep */316	rval = lm3630a_update(pchip, REG_CTRL, 0x80, 0x00);317	if (rval < 0)318		goto out_i2c_err;319	usleep_range(1000, 2000);320	rval = lm3630a_read(pchip, REG_BRT_B);321	if (rval < 0)322		goto out_i2c_err;323	return rval;324 325out_i2c_err:326	dev_err(pchip->dev, "i2c failed to access register\n");327	return 0;328}329 330static const struct backlight_ops lm3630a_bank_b_ops = {331	.options = BL_CORE_SUSPENDRESUME,332	.update_status = lm3630a_bank_b_update_status,333	.get_brightness = lm3630a_bank_b_get_brightness,334};335 336static int lm3630a_backlight_register(struct lm3630a_chip *pchip)337{338	struct lm3630a_platform_data *pdata = pchip->pdata;339	struct backlight_properties props;340	const char *label;341 342	memset(&props, 0, sizeof(struct backlight_properties));343	props.type = BACKLIGHT_RAW;344	if (pdata->leda_ctrl != LM3630A_LEDA_DISABLE) {345		props.brightness = pdata->leda_init_brt;346		props.max_brightness = pdata->leda_max_brt;347		label = pdata->leda_label ? pdata->leda_label : "lm3630a_leda";348		pchip->bleda =349		    devm_backlight_device_register(pchip->dev, label,350						   pchip->dev, pchip,351						   &lm3630a_bank_a_ops, &props);352		if (IS_ERR(pchip->bleda))353			return PTR_ERR(pchip->bleda);354	}355 356	if ((pdata->ledb_ctrl != LM3630A_LEDB_DISABLE) &&357	    (pdata->ledb_ctrl != LM3630A_LEDB_ON_A)) {358		props.brightness = pdata->ledb_init_brt;359		props.max_brightness = pdata->ledb_max_brt;360		label = pdata->ledb_label ? pdata->ledb_label : "lm3630a_ledb";361		pchip->bledb =362		    devm_backlight_device_register(pchip->dev, label,363						   pchip->dev, pchip,364						   &lm3630a_bank_b_ops, &props);365		if (IS_ERR(pchip->bledb))366			return PTR_ERR(pchip->bledb);367	}368	return 0;369}370 371static const struct regmap_config lm3630a_regmap = {372	.reg_bits = 8,373	.val_bits = 8,374	.max_register = REG_MAX,375};376 377static int lm3630a_parse_led_sources(struct fwnode_handle *node,378				     int default_led_sources)379{380	u32 sources[LM3630A_NUM_SINKS];381	int ret, num_sources, i;382 383	num_sources = fwnode_property_count_u32(node, "led-sources");384	if (num_sources < 0)385		return default_led_sources;386	else if (num_sources > ARRAY_SIZE(sources))387		return -EINVAL;388 389	ret = fwnode_property_read_u32_array(node, "led-sources", sources,390					     num_sources);391	if (ret)392		return ret;393 394	for (i = 0; i < num_sources; i++) {395		if (sources[i] != LM3630A_SINK_0 && sources[i] != LM3630A_SINK_1)396			return -EINVAL;397 398		ret |= BIT(sources[i]);399	}400 401	return ret;402}403 404static int lm3630a_parse_bank(struct lm3630a_platform_data *pdata,405			      struct fwnode_handle *node, int *seen_led_sources)406{407	int led_sources, ret;408	const char *label;409	u32 bank, val;410	bool linear;411 412	ret = fwnode_property_read_u32(node, "reg", &bank);413	if (ret)414		return ret;415 416	if (bank != LM3630A_BANK_0 && bank != LM3630A_BANK_1)417		return -EINVAL;418 419	led_sources = lm3630a_parse_led_sources(node, BIT(bank));420	if (led_sources < 0)421		return led_sources;422 423	if (*seen_led_sources & led_sources)424		return -EINVAL;425 426	*seen_led_sources |= led_sources;427 428	linear = fwnode_property_read_bool(node,429					   "ti,linear-mapping-mode");430	if (bank) {431		if (led_sources & BIT(LM3630A_SINK_0) ||432		    !(led_sources & BIT(LM3630A_SINK_1)))433			return -EINVAL;434 435		pdata->ledb_ctrl = linear ?436			LM3630A_LEDB_ENABLE_LINEAR :437			LM3630A_LEDB_ENABLE;438	} else {439		if (!(led_sources & BIT(LM3630A_SINK_0)))440			return -EINVAL;441 442		pdata->leda_ctrl = linear ?443			LM3630A_LEDA_ENABLE_LINEAR :444			LM3630A_LEDA_ENABLE;445 446		if (led_sources & BIT(LM3630A_SINK_1))447			pdata->ledb_ctrl = LM3630A_LEDB_ON_A;448	}449 450	ret = fwnode_property_read_string(node, "label", &label);451	if (!ret) {452		if (bank)453			pdata->ledb_label = label;454		else455			pdata->leda_label = label;456	}457 458	ret = fwnode_property_read_u32(node, "default-brightness",459				       &val);460	if (!ret) {461		if (bank)462			pdata->ledb_init_brt = val;463		else464			pdata->leda_init_brt = val;465	}466 467	ret = fwnode_property_read_u32(node, "max-brightness", &val);468	if (!ret) {469		if (bank)470			pdata->ledb_max_brt = val;471		else472			pdata->leda_max_brt = val;473	}474 475	return 0;476}477 478static int lm3630a_parse_node(struct lm3630a_chip *pchip,479			      struct lm3630a_platform_data *pdata)480{481	int ret = -ENODEV, seen_led_sources = 0;482	struct fwnode_handle *node;483 484	device_for_each_child_node(pchip->dev, node) {485		ret = lm3630a_parse_bank(pdata, node, &seen_led_sources);486		if (ret) {487			fwnode_handle_put(node);488			return ret;489		}490	}491 492	return ret;493}494 495static int lm3630a_probe(struct i2c_client *client)496{497	struct lm3630a_platform_data *pdata = dev_get_platdata(&client->dev);498	struct lm3630a_chip *pchip;499	int rval;500 501	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {502		dev_err(&client->dev, "fail : i2c functionality check\n");503		return -EOPNOTSUPP;504	}505 506	pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630a_chip),507			     GFP_KERNEL);508	if (!pchip)509		return -ENOMEM;510	pchip->dev = &client->dev;511 512	pchip->regmap = devm_regmap_init_i2c(client, &lm3630a_regmap);513	if (IS_ERR(pchip->regmap)) {514		rval = PTR_ERR(pchip->regmap);515		dev_err(&client->dev, "fail : allocate reg. map: %d\n", rval);516		return rval;517	}518 519	i2c_set_clientdata(client, pchip);520	if (pdata == NULL) {521		pdata = devm_kzalloc(pchip->dev,522				     sizeof(struct lm3630a_platform_data),523				     GFP_KERNEL);524		if (pdata == NULL)525			return -ENOMEM;526 527		/* default values */528		pdata->leda_max_brt = LM3630A_MAX_BRIGHTNESS;529		pdata->ledb_max_brt = LM3630A_MAX_BRIGHTNESS;530		pdata->leda_init_brt = LM3630A_MAX_BRIGHTNESS;531		pdata->ledb_init_brt = LM3630A_MAX_BRIGHTNESS;532 533		rval = lm3630a_parse_node(pchip, pdata);534		if (rval) {535			dev_err(&client->dev, "fail : parse node\n");536			return rval;537		}538	}539	pchip->pdata = pdata;540 541	pchip->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable",542						GPIOD_OUT_HIGH);543	if (IS_ERR(pchip->enable_gpio))544		return PTR_ERR(pchip->enable_gpio);545 546	/* chip initialize */547	rval = lm3630a_chip_init(pchip);548	if (rval < 0) {549		dev_err(&client->dev, "fail : init chip\n");550		return rval;551	}552	/* backlight register */553	rval = lm3630a_backlight_register(pchip);554	if (rval < 0) {555		dev_err(&client->dev, "fail : backlight register.\n");556		return rval;557	}558	/* pwm */559	if (pdata->pwm_ctrl != LM3630A_PWM_DISABLE) {560		pchip->pwmd = devm_pwm_get(pchip->dev, "lm3630a-pwm");561		if (IS_ERR(pchip->pwmd))562			return dev_err_probe(&client->dev, PTR_ERR(pchip->pwmd),563					     "fail : get pwm device\n");564 565		pwm_init_state(pchip->pwmd, &pchip->pwmd_state);566	}567 568	/* interrupt enable  : irq 0 is not allowed */569	pchip->irq = client->irq;570	if (pchip->irq) {571		rval = lm3630a_intr_config(pchip);572		if (rval < 0)573			return rval;574	}575	dev_info(&client->dev, "LM3630A backlight register OK.\n");576	return 0;577}578 579static void lm3630a_remove(struct i2c_client *client)580{581	int rval;582	struct lm3630a_chip *pchip = i2c_get_clientdata(client);583 584	rval = lm3630a_write(pchip, REG_BRT_A, 0);585	if (rval < 0)586		dev_err(pchip->dev, "i2c failed to access register\n");587 588	rval = lm3630a_write(pchip, REG_BRT_B, 0);589	if (rval < 0)590		dev_err(pchip->dev, "i2c failed to access register\n");591 592	if (pchip->irq) {593		free_irq(pchip->irq, pchip);594		destroy_workqueue(pchip->irqthread);595	}596}597 598static const struct i2c_device_id lm3630a_id[] = {599	{ LM3630A_NAME },600	{}601};602 603MODULE_DEVICE_TABLE(i2c, lm3630a_id);604 605static const struct of_device_id lm3630a_match_table[] = {606	{ .compatible = "ti,lm3630a", },607	{ },608};609 610MODULE_DEVICE_TABLE(of, lm3630a_match_table);611 612static struct i2c_driver lm3630a_i2c_driver = {613	.driver = {614		   .name = LM3630A_NAME,615		   .of_match_table = lm3630a_match_table,616		   },617	.probe = lm3630a_probe,618	.remove = lm3630a_remove,619	.id_table = lm3630a_id,620};621 622module_i2c_driver(lm3630a_i2c_driver);623 624MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630A");625MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");626MODULE_AUTHOR("LDD MLP <ldd-mlp@list.ti.com>");627MODULE_LICENSE("GPL v2");628