cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tps65217_bl.c (7424B)


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