brintos

brintos / linux-shallow public Read only

0
0
Text · 4.1 KiB · 8a63ded Raw
160 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Backlight driver for Pandora handheld.4 * Pandora uses TWL4030 PWM0 -> TPS61161 combo for control backlight.5 * Based on pwm_bl.c6 *7 * Copyright 2009,2012 Gražvydas Ignotas <notasas@gmail.com>8 */9 10#include <linux/module.h>11#include <linux/kernel.h>12#include <linux/platform_device.h>13#include <linux/delay.h>14#include <linux/backlight.h>15#include <linux/mfd/twl.h>16#include <linux/err.h>17 18#define TWL_PWM0_ON		0x0019#define TWL_PWM0_OFF		0x0120 21#define TWL_INTBR_GPBR1		0x0c22#define TWL_INTBR_PMBR1		0x0d23 24#define TWL_PMBR1_PWM0_MUXMASK	0x0c25#define TWL_PMBR1_PWM0		0x0426#define PWM0_CLK_ENABLE		BIT(0)27#define PWM0_ENABLE		BIT(2)28 29/* range accepted by hardware */30#define MIN_VALUE 931#define MAX_VALUE 6332#define MAX_USER_VALUE (MAX_VALUE - MIN_VALUE)33 34struct pandora_private {35	unsigned old_state;36#define PANDORABL_WAS_OFF 137};38 39static int pandora_backlight_update_status(struct backlight_device *bl)40{41	int brightness = bl->props.brightness;42	struct pandora_private *priv = bl_get_data(bl);43	u8 r;44 45	if (bl->props.power != BACKLIGHT_POWER_ON)46		brightness = 0;47	if (bl->props.state & BL_CORE_FBBLANK)48		brightness = 0;49	if (bl->props.state & BL_CORE_SUSPENDED)50		brightness = 0;51 52	if ((unsigned int)brightness > MAX_USER_VALUE)53		brightness = MAX_USER_VALUE;54 55	if (brightness == 0) {56		if (priv->old_state == PANDORABL_WAS_OFF)57			goto done;58 59		/* first disable PWM0 output, then clock */60		twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_GPBR1);61		r &= ~PWM0_ENABLE;62		twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);63		r &= ~PWM0_CLK_ENABLE;64		twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);65 66		goto done;67	}68 69	if (priv->old_state == PANDORABL_WAS_OFF) {70		/*71		 * set PWM duty cycle to max. TPS61161 seems to use this72		 * to calibrate it's PWM sensitivity when it starts.73		 */74		twl_i2c_write_u8(TWL_MODULE_PWM, MAX_VALUE, TWL_PWM0_OFF);75 76		/* first enable clock, then PWM0 out */77		twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_GPBR1);78		r &= ~PWM0_ENABLE;79		r |= PWM0_CLK_ENABLE;80		twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);81		r |= PWM0_ENABLE;82		twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_GPBR1);83 84		/*85		 * TI made it very easy to enable digital control, so easy that86		 * it often triggers unintentionally and disabes PWM control,87		 * so wait until 1 wire mode detection window ends.88		 */89		usleep_range(2000, 10000);90	}91 92	twl_i2c_write_u8(TWL_MODULE_PWM, MIN_VALUE + brightness, TWL_PWM0_OFF);93 94done:95	if (brightness != 0)96		priv->old_state = 0;97	else98		priv->old_state = PANDORABL_WAS_OFF;99 100	return 0;101}102 103static const struct backlight_ops pandora_backlight_ops = {104	.options	= BL_CORE_SUSPENDRESUME,105	.update_status	= pandora_backlight_update_status,106};107 108static int pandora_backlight_probe(struct platform_device *pdev)109{110	struct backlight_properties props;111	struct backlight_device *bl;112	struct pandora_private *priv;113	u8 r;114 115	priv = devm_kmalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);116	if (!priv)117		return -ENOMEM;118 119	memset(&props, 0, sizeof(props));120	props.max_brightness = MAX_USER_VALUE;121	props.type = BACKLIGHT_RAW;122	bl = devm_backlight_device_register(&pdev->dev, pdev->name, &pdev->dev,123					priv, &pandora_backlight_ops, &props);124	if (IS_ERR(bl)) {125		dev_err(&pdev->dev, "failed to register backlight\n");126		return PTR_ERR(bl);127	}128 129	platform_set_drvdata(pdev, bl);130 131	/* 64 cycle period, ON position 0 */132	twl_i2c_write_u8(TWL_MODULE_PWM, 0x80, TWL_PWM0_ON);133 134	priv->old_state = PANDORABL_WAS_OFF;135	bl->props.brightness = MAX_USER_VALUE;136	backlight_update_status(bl);137 138	/* enable PWM function in pin mux */139	twl_i2c_read_u8(TWL4030_MODULE_INTBR, &r, TWL_INTBR_PMBR1);140	r &= ~TWL_PMBR1_PWM0_MUXMASK;141	r |= TWL_PMBR1_PWM0;142	twl_i2c_write_u8(TWL4030_MODULE_INTBR, r, TWL_INTBR_PMBR1);143 144	return 0;145}146 147static struct platform_driver pandora_backlight_driver = {148	.driver		= {149		.name	= "pandora-backlight",150	},151	.probe		= pandora_backlight_probe,152};153 154module_platform_driver(pandora_backlight_driver);155 156MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>");157MODULE_DESCRIPTION("Pandora Backlight Driver");158MODULE_LICENSE("GPL");159MODULE_ALIAS("platform:pandora-backlight");160