File Index
Files and directories
Sign in
FILE

aat2870_bl.c

File preview with syntax highlighting.

linux-6.19.14/drivers/video/backlight/aat2870_bl.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * linux/drivers/video/backlight/aat2870_bl.c
  4 *
  5 * Copyright (c) 2011, NVIDIA Corporation.
  6 * Author: Jin Park <jinyoungp@nvidia.com>
  7 */
  8
  9#include <linux/module.h>
 10#include <linux/kernel.h>
 11#include <linux/init.h>
 12#include <linux/platform_device.h>
 13#include <linux/mutex.h>
 14#include <linux/delay.h>
 15#include <linux/backlight.h>
 16#include <linux/mfd/aat2870.h>
 17
 18struct aat2870_bl_driver_data {
 19	struct platform_device *pdev;
 20	struct backlight_device *bd;
 21
 22	int channels;
 23	int max_current;
 24	int brightness; /* current brightness */
 25};
 26
 27static inline int aat2870_brightness(struct aat2870_bl_driver_data *aat2870_bl,
 28				     int brightness)
 29{
 30	struct backlight_device *bd = aat2870_bl->bd;
 31	int val;
 32
 33	val = brightness * (aat2870_bl->max_current - 1);
 34	val /= bd->props.max_brightness;
 35
 36	return val;
 37}
 38
 39static inline int aat2870_bl_enable(struct aat2870_bl_driver_data *aat2870_bl)
 40{
 41	struct aat2870_data *aat2870
 42			= dev_get_drvdata(aat2870_bl->pdev->dev.parent);
 43
 44	return aat2870->write(aat2870, AAT2870_BL_CH_EN,
 45			      (u8)aat2870_bl->channels);
 46}
 47
 48static inline int aat2870_bl_disable(struct aat2870_bl_driver_data *aat2870_bl)
 49{
 50	struct aat2870_data *aat2870
 51			= dev_get_drvdata(aat2870_bl->pdev->dev.parent);
 52
 53	return aat2870->write(aat2870, AAT2870_BL_CH_EN, 0x0);
 54}
 55
 56static int aat2870_bl_update_status(struct backlight_device *bd)
 57{
 58	struct aat2870_bl_driver_data *aat2870_bl = bl_get_data(bd);
 59	struct aat2870_data *aat2870 =
 60			dev_get_drvdata(aat2870_bl->pdev->dev.parent);
 61	int brightness = backlight_get_brightness(bd);
 62	int ret;
 63
 64	if ((brightness < 0) || (bd->props.max_brightness < brightness)) {
 65		dev_err(&bd->dev, "invalid brightness, %d\n", brightness);
 66		return -EINVAL;
 67	}
 68
 69	dev_dbg(&bd->dev, "brightness=%d, power=%d, state=%d\n",
 70		 bd->props.brightness, bd->props.power, bd->props.state);
 71
 72	ret = aat2870->write(aat2870, AAT2870_BLM,
 73			     (u8)aat2870_brightness(aat2870_bl, brightness));
 74	if (ret < 0)
 75		return ret;
 76
 77	if (brightness == 0) {
 78		ret = aat2870_bl_disable(aat2870_bl);
 79		if (ret < 0)
 80			return ret;
 81	} else if (aat2870_bl->brightness == 0) {
 82		ret = aat2870_bl_enable(aat2870_bl);
 83		if (ret < 0)
 84			return ret;
 85	}
 86
 87	aat2870_bl->brightness = brightness;
 88
 89	return 0;
 90}
 91
 92static const struct backlight_ops aat2870_bl_ops = {
 93	.options = BL_CORE_SUSPENDRESUME,
 94	.update_status = aat2870_bl_update_status,
 95};
 96
 97static int aat2870_bl_probe(struct platform_device *pdev)
 98{
 99	struct aat2870_bl_platform_data *pdata = dev_get_platdata(&pdev->dev);
100	struct aat2870_bl_driver_data *aat2870_bl;
101	struct backlight_device *bd;
102	struct backlight_properties props;
103	int ret = 0;
104
105	if (!pdata) {
106		dev_err(&pdev->dev, "No platform data\n");
107		ret = -ENXIO;
108		goto out;
109	}
110
111	if (pdev->id != AAT2870_ID_BL) {
112		dev_err(&pdev->dev, "Invalid device ID, %d\n", pdev->id);
113		ret = -EINVAL;
114		goto out;
115	}
116
117	aat2870_bl = devm_kzalloc(&pdev->dev,
118				  sizeof(struct aat2870_bl_driver_data),
119				  GFP_KERNEL);
120	if (!aat2870_bl) {
121		ret = -ENOMEM;
122		goto out;
123	}
124
125	memset(&props, 0, sizeof(struct backlight_properties));
126
127	props.type = BACKLIGHT_RAW;
128	bd = devm_backlight_device_register(&pdev->dev, "aat2870-backlight",
129					&pdev->dev, aat2870_bl, &aat2870_bl_ops,
130					&props);
131	if (IS_ERR(bd)) {
132		dev_err(&pdev->dev,
133			"Failed allocate memory for backlight device\n");
134		ret = PTR_ERR(bd);
135		goto out;
136	}
137
138	aat2870_bl->pdev = pdev;
139	platform_set_drvdata(pdev, aat2870_bl);
140
141	aat2870_bl->bd = bd;
142
143	if (pdata->channels > 0)
144		aat2870_bl->channels = pdata->channels;
145	else
146		aat2870_bl->channels = AAT2870_BL_CH_ALL;
147
148	if (pdata->max_current > 0)
149		aat2870_bl->max_current = pdata->max_current;
150	else
151		aat2870_bl->max_current = AAT2870_CURRENT_27_9;
152
153	if (pdata->max_brightness > 0)
154		bd->props.max_brightness = pdata->max_brightness;
155	else
156		bd->props.max_brightness = 255;
157
158	aat2870_bl->brightness = 0;
159	bd->props.power = BACKLIGHT_POWER_ON;
160	bd->props.brightness = bd->props.max_brightness;
161
162	ret = aat2870_bl_update_status(bd);
163	if (ret < 0) {
164		dev_err(&pdev->dev, "Failed to initialize\n");
165		return ret;
166	}
167
168	return 0;
169
170out:
171	return ret;
172}
173
174static void aat2870_bl_remove(struct platform_device *pdev)
175{
176	struct aat2870_bl_driver_data *aat2870_bl = platform_get_drvdata(pdev);
177	struct backlight_device *bd = aat2870_bl->bd;
178
179	bd->props.power = BACKLIGHT_POWER_OFF;
180	bd->props.brightness = 0;
181	backlight_update_status(bd);
182}
183
184static struct platform_driver aat2870_bl_driver = {
185	.driver = {
186		.name	= "aat2870-backlight",
187	},
188	.probe		= aat2870_bl_probe,
189	.remove		= aat2870_bl_remove,
190};
191
192static int __init aat2870_bl_init(void)
193{
194	return platform_driver_register(&aat2870_bl_driver);
195}
196subsys_initcall(aat2870_bl_init);
197
198static void __exit aat2870_bl_exit(void)
199{
200	platform_driver_unregister(&aat2870_bl_driver);
201}
202module_exit(aat2870_bl_exit);
203
204MODULE_DESCRIPTION("AnalogicTech AAT2870 Backlight");
205MODULE_LICENSE("GPL");
206MODULE_AUTHOR("Jin Park <jinyoungp@nvidia.com>");
~/ Read-only file preview.