brintos

brintos / linux-shallow public Read only

0
0
Text · 6.9 KiB · d96d713 Raw
319 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * tps65217_bl.c4 *5 * TPS65217 backlight driver6 *7 * Copyright (C) 2012 Matthias Kaehlcke8 * Author: Matthias Kaehlcke <matthias@kaehlcke.net>9 */10 11#include <linux/kernel.h>12#include <linux/backlight.h>13#include <linux/err.h>14#include <linux/fb.h>15#include <linux/mfd/tps65217.h>16#include <linux/module.h>17#include <linux/platform_device.h>18#include <linux/slab.h>19 20struct tps65217_bl {21	struct tps65217 *tps;22	struct device *dev;23	struct backlight_device *bl;24	bool is_enabled;25};26 27static int tps65217_bl_enable(struct tps65217_bl *tps65217_bl)28{29	int rc;30 31	rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1,32			TPS65217_WLEDCTRL1_ISINK_ENABLE,33			TPS65217_WLEDCTRL1_ISINK_ENABLE, TPS65217_PROTECT_NONE);34	if (rc) {35		dev_err(tps65217_bl->dev,36			"failed to enable backlight: %d\n", rc);37		return rc;38	}39 40	tps65217_bl->is_enabled = true;41 42	dev_dbg(tps65217_bl->dev, "backlight enabled\n");43 44	return 0;45}46 47static int tps65217_bl_disable(struct tps65217_bl *tps65217_bl)48{49	int rc;50 51	rc = tps65217_clear_bits(tps65217_bl->tps,52				TPS65217_REG_WLEDCTRL1,53				TPS65217_WLEDCTRL1_ISINK_ENABLE,54				TPS65217_PROTECT_NONE);55	if (rc) {56		dev_err(tps65217_bl->dev,57			"failed to disable backlight: %d\n", rc);58		return rc;59	}60 61	tps65217_bl->is_enabled = false;62 63	dev_dbg(tps65217_bl->dev, "backlight disabled\n");64 65	return 0;66}67 68static int tps65217_bl_update_status(struct backlight_device *bl)69{70	struct tps65217_bl *tps65217_bl = bl_get_data(bl);71	int rc;72	int brightness = backlight_get_brightness(bl);73 74	if (brightness > 0) {75		rc = tps65217_reg_write(tps65217_bl->tps,76					TPS65217_REG_WLEDCTRL2,77					brightness - 1,78					TPS65217_PROTECT_NONE);79		if (rc) {80			dev_err(tps65217_bl->dev,81				"failed to set brightness level: %d\n", rc);82			return rc;83		}84 85		dev_dbg(tps65217_bl->dev, "brightness set to %d\n", brightness);86 87		if (!tps65217_bl->is_enabled)88			rc = tps65217_bl_enable(tps65217_bl);89	} else {90		rc = tps65217_bl_disable(tps65217_bl);91	}92 93	return rc;94}95 96static const struct backlight_ops tps65217_bl_ops = {97	.options	= BL_CORE_SUSPENDRESUME,98	.update_status	= tps65217_bl_update_status,99};100 101static int tps65217_bl_hw_init(struct tps65217_bl *tps65217_bl,102			struct tps65217_bl_pdata *pdata)103{104	int rc;105 106	rc = tps65217_bl_disable(tps65217_bl);107	if (rc)108		return rc;109 110	switch (pdata->isel) {111	case TPS65217_BL_ISET1:112		/* select ISET_1 current level */113		rc = tps65217_clear_bits(tps65217_bl->tps,114					TPS65217_REG_WLEDCTRL1,115					TPS65217_WLEDCTRL1_ISEL,116					TPS65217_PROTECT_NONE);117		if (rc) {118			dev_err(tps65217_bl->dev,119				"failed to select ISET1 current level: %d)\n",120				rc);121			return rc;122		}123 124		dev_dbg(tps65217_bl->dev, "selected ISET1 current level\n");125 126		break;127 128	case TPS65217_BL_ISET2:129		/* select ISET2 current level */130		rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1,131				TPS65217_WLEDCTRL1_ISEL,132				TPS65217_WLEDCTRL1_ISEL, TPS65217_PROTECT_NONE);133		if (rc) {134			dev_err(tps65217_bl->dev,135				"failed to select ISET2 current level: %d\n",136				rc);137			return rc;138		}139 140		dev_dbg(tps65217_bl->dev, "selected ISET2 current level\n");141 142		break;143 144	default:145		dev_err(tps65217_bl->dev,146			"invalid value for current level: %d\n", pdata->isel);147		return -EINVAL;148	}149 150	/* set PWM frequency */151	rc = tps65217_set_bits(tps65217_bl->tps,152			TPS65217_REG_WLEDCTRL1,153			TPS65217_WLEDCTRL1_FDIM_MASK,154			pdata->fdim,155			TPS65217_PROTECT_NONE);156	if (rc) {157		dev_err(tps65217_bl->dev,158			"failed to select PWM dimming frequency: %d\n",159			rc);160		return rc;161	}162 163	return 0;164}165 166#ifdef CONFIG_OF167static struct tps65217_bl_pdata *168tps65217_bl_parse_dt(struct platform_device *pdev)169{170	struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);171	struct device_node *node;172	struct tps65217_bl_pdata *pdata, *err;173	u32 val;174 175	node = of_get_child_by_name(tps->dev->of_node, "backlight");176	if (!node)177		return ERR_PTR(-ENODEV);178 179	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);180	if (!pdata) {181		err = ERR_PTR(-ENOMEM);182		goto err;183	}184 185	pdata->isel = TPS65217_BL_ISET1;186	if (!of_property_read_u32(node, "isel", &val)) {187		if (val < TPS65217_BL_ISET1 ||188			val > TPS65217_BL_ISET2) {189			dev_err(&pdev->dev,190				"invalid 'isel' value in the device tree\n");191			err = ERR_PTR(-EINVAL);192			goto err;193		}194 195		pdata->isel = val;196	}197 198	pdata->fdim = TPS65217_BL_FDIM_200HZ;199	if (!of_property_read_u32(node, "fdim", &val)) {200		switch (val) {201		case 100:202			pdata->fdim = TPS65217_BL_FDIM_100HZ;203			break;204 205		case 200:206			pdata->fdim = TPS65217_BL_FDIM_200HZ;207			break;208 209		case 500:210			pdata->fdim = TPS65217_BL_FDIM_500HZ;211			break;212 213		case 1000:214			pdata->fdim = TPS65217_BL_FDIM_1000HZ;215			break;216 217		default:218			dev_err(&pdev->dev,219				"invalid 'fdim' value in the device tree\n");220			err = ERR_PTR(-EINVAL);221			goto err;222		}223	}224 225	if (!of_property_read_u32(node, "default-brightness", &val)) {226		if (val > 100) {227			dev_err(&pdev->dev,228				"invalid 'default-brightness' value in the device tree\n");229			err = ERR_PTR(-EINVAL);230			goto err;231		}232 233		pdata->dft_brightness = val;234	}235 236	of_node_put(node);237 238	return pdata;239 240err:241	of_node_put(node);242 243	return err;244}245#else246static struct tps65217_bl_pdata *247tps65217_bl_parse_dt(struct platform_device *pdev)248{249	return NULL;250}251#endif252 253static int tps65217_bl_probe(struct platform_device *pdev)254{255	int rc;256	struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent);257	struct tps65217_bl *tps65217_bl;258	struct tps65217_bl_pdata *pdata;259	struct backlight_properties bl_props;260 261	pdata = tps65217_bl_parse_dt(pdev);262	if (IS_ERR(pdata))263		return PTR_ERR(pdata);264 265	tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl),266				GFP_KERNEL);267	if (tps65217_bl == NULL)268		return -ENOMEM;269 270	tps65217_bl->tps = tps;271	tps65217_bl->dev = &pdev->dev;272	tps65217_bl->is_enabled = false;273 274	rc = tps65217_bl_hw_init(tps65217_bl, pdata);275	if (rc)276		return rc;277 278	memset(&bl_props, 0, sizeof(struct backlight_properties));279	bl_props.type = BACKLIGHT_RAW;280	bl_props.max_brightness = 100;281 282	tps65217_bl->bl = devm_backlight_device_register(&pdev->dev, pdev->name,283						tps65217_bl->dev, tps65217_bl,284						&tps65217_bl_ops, &bl_props);285	if (IS_ERR(tps65217_bl->bl)) {286		dev_err(tps65217_bl->dev,287			"registration of backlight device failed: %d\n", rc);288		return PTR_ERR(tps65217_bl->bl);289	}290 291	tps65217_bl->bl->props.brightness = pdata->dft_brightness;292	backlight_update_status(tps65217_bl->bl);293	platform_set_drvdata(pdev, tps65217_bl);294 295	return 0;296}297 298#ifdef CONFIG_OF299static const struct of_device_id tps65217_bl_of_match[] = {300	{ .compatible = "ti,tps65217-bl", },301	{ /* sentinel */ },302};303MODULE_DEVICE_TABLE(of, tps65217_bl_of_match);304#endif305 306static struct platform_driver tps65217_bl_driver = {307	.probe		= tps65217_bl_probe,308	.driver		= {309		.name	= "tps65217-bl",310		.of_match_table = of_match_ptr(tps65217_bl_of_match),311	},312};313 314module_platform_driver(tps65217_bl_driver);315 316MODULE_DESCRIPTION("TPS65217 Backlight driver");317MODULE_LICENSE("GPL v2");318MODULE_AUTHOR("Matthias Kaehlcke <matthias@kaehlcke.net>");319