brintos

brintos / linux-shallow public Read only

0
0
Text · 10.9 KiB · f16358b Raw
431 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2 3#include <linux/bitops.h>4#include <linux/i2c.h>5#include <linux/kernel.h>6#include <linux/led-class-flash.h>7#include <linux/module.h>8#include <linux/mutex.h>9#include <linux/property.h>10#include <linux/regmap.h>11#include <media/v4l2-flash-led-class.h>12 13#define RT4505_REG_RESET	0x014#define RT4505_REG_CONFIG	0x815#define RT4505_REG_ILED		0x916#define RT4505_REG_ENABLE	0xA17#define RT4505_REG_FLAGS	0xB18 19#define RT4505_RESET_MASK	BIT(7)20#define RT4505_FLASHTO_MASK	GENMASK(2, 0)21#define RT4505_ITORCH_MASK	GENMASK(7, 5)22#define RT4505_ITORCH_SHIFT	523#define RT4505_IFLASH_MASK	GENMASK(4, 0)24#define RT4505_ENABLE_MASK	GENMASK(5, 0)25#define RT4505_TORCH_SET	(BIT(0) | BIT(4))26#define RT4505_FLASH_SET	(BIT(0) | BIT(1) | BIT(2) | BIT(4))27#define RT4505_EXT_FLASH_SET	(BIT(0) | BIT(1) | BIT(4) | BIT(5))28#define RT4505_FLASH_GET	(BIT(0) | BIT(1) | BIT(4))29#define RT4505_OVP_MASK		BIT(3)30#define RT4505_SHORT_MASK	BIT(2)31#define RT4505_OTP_MASK		BIT(1)32#define RT4505_TIMEOUT_MASK	BIT(0)33 34#define RT4505_ITORCH_MINUA	4600035#define RT4505_ITORCH_MAXUA	37500036#define RT4505_ITORCH_STPUA	4700037#define RT4505_IFLASH_MINUA	9375038#define RT4505_IFLASH_MAXUA	150000039#define RT4505_IFLASH_STPUA	9375040#define RT4505_FLASHTO_MINUS	10000041#define RT4505_FLASHTO_MAXUS	80000042#define RT4505_FLASHTO_STPUS	10000043 44struct rt4505_priv {45	struct device *dev;46	struct regmap *regmap;47	struct mutex lock;48	struct led_classdev_flash flash;49	struct v4l2_flash *v4l2_flash;50};51 52static int rt4505_torch_brightness_set(struct led_classdev *lcdev,53				       enum led_brightness level)54{55	struct rt4505_priv *priv =56		container_of(lcdev, struct rt4505_priv, flash.led_cdev);57	u32 val = 0;58	int ret;59 60	mutex_lock(&priv->lock);61 62	if (level != LED_OFF) {63		ret = regmap_update_bits(priv->regmap,64					 RT4505_REG_ILED, RT4505_ITORCH_MASK,65					 (level - 1) << RT4505_ITORCH_SHIFT);66		if (ret)67			goto unlock;68 69		val = RT4505_TORCH_SET;70	}71 72	ret = regmap_update_bits(priv->regmap, RT4505_REG_ENABLE,73				 RT4505_ENABLE_MASK, val);74 75unlock:76	mutex_unlock(&priv->lock);77	return ret;78}79 80static enum led_brightness rt4505_torch_brightness_get(81						struct led_classdev *lcdev)82{83	struct rt4505_priv *priv =84		container_of(lcdev, struct rt4505_priv, flash.led_cdev);85	u32 val;86	int ret;87 88	mutex_lock(&priv->lock);89 90	ret = regmap_read(priv->regmap, RT4505_REG_ENABLE, &val);91	if (ret) {92		dev_err(lcdev->dev, "Failed to get LED enable\n");93		ret = LED_OFF;94		goto unlock;95	}96 97	if ((val & RT4505_ENABLE_MASK) != RT4505_TORCH_SET) {98		ret = LED_OFF;99		goto unlock;100	}101 102	ret = regmap_read(priv->regmap, RT4505_REG_ILED, &val);103	if (ret) {104		dev_err(lcdev->dev, "Failed to get LED brightness\n");105		ret = LED_OFF;106		goto unlock;107	}108 109	ret = ((val & RT4505_ITORCH_MASK) >> RT4505_ITORCH_SHIFT) + 1;110 111unlock:112	mutex_unlock(&priv->lock);113	return ret;114}115 116static int rt4505_flash_brightness_set(struct led_classdev_flash *fled_cdev,117				       u32 brightness)118{119	struct rt4505_priv *priv =120		container_of(fled_cdev, struct rt4505_priv, flash);121	struct led_flash_setting *s = &fled_cdev->brightness;122	u32 val = (brightness - s->min) / s->step;123	int ret;124 125	mutex_lock(&priv->lock);126	ret = regmap_update_bits(priv->regmap, RT4505_REG_ILED,127				 RT4505_IFLASH_MASK, val);128	mutex_unlock(&priv->lock);129 130	return ret;131}132 133static int rt4505_flash_strobe_set(struct led_classdev_flash *fled_cdev,134				   bool state)135{136	struct rt4505_priv *priv =137		container_of(fled_cdev, struct rt4505_priv, flash);138	u32 val = state ? RT4505_FLASH_SET : 0;139	int ret;140 141	mutex_lock(&priv->lock);142	ret = regmap_update_bits(priv->regmap, RT4505_REG_ENABLE,143				 RT4505_ENABLE_MASK, val);144	mutex_unlock(&priv->lock);145 146	return ret;147}148 149static int rt4505_flash_strobe_get(struct led_classdev_flash *fled_cdev,150				   bool *state)151{152	struct rt4505_priv *priv =153		container_of(fled_cdev, struct rt4505_priv, flash);154	u32 val;155	int ret;156 157	mutex_lock(&priv->lock);158 159	ret = regmap_read(priv->regmap, RT4505_REG_ENABLE, &val);160	if (ret)161		goto unlock;162 163	*state = (val & RT4505_FLASH_GET) == RT4505_FLASH_GET;164 165unlock:166	mutex_unlock(&priv->lock);167	return ret;168}169 170static int rt4505_flash_timeout_set(struct led_classdev_flash *fled_cdev,171				    u32 timeout)172{173	struct rt4505_priv *priv =174		container_of(fled_cdev, struct rt4505_priv, flash);175	struct led_flash_setting *s = &fled_cdev->timeout;176	u32 val = (timeout - s->min) / s->step;177	int ret;178 179	mutex_lock(&priv->lock);180	ret = regmap_update_bits(priv->regmap, RT4505_REG_CONFIG,181				 RT4505_FLASHTO_MASK, val);182	mutex_unlock(&priv->lock);183 184	return ret;185}186 187static int rt4505_fault_get(struct led_classdev_flash *fled_cdev, u32 *fault)188{189	struct rt4505_priv *priv =190		container_of(fled_cdev, struct rt4505_priv, flash);191	u32 val, led_faults = 0;192	int ret;193 194	ret = regmap_read(priv->regmap, RT4505_REG_FLAGS, &val);195	if (ret)196		return ret;197 198	if (val & RT4505_OVP_MASK)199		led_faults |= LED_FAULT_OVER_VOLTAGE;200 201	if (val & RT4505_SHORT_MASK)202		led_faults |= LED_FAULT_SHORT_CIRCUIT;203 204	if (val & RT4505_OTP_MASK)205		led_faults |= LED_FAULT_OVER_TEMPERATURE;206 207	if (val & RT4505_TIMEOUT_MASK)208		led_faults |= LED_FAULT_TIMEOUT;209 210	*fault = led_faults;211	return 0;212}213 214static const struct led_flash_ops rt4505_flash_ops = {215	.flash_brightness_set = rt4505_flash_brightness_set,216	.strobe_set = rt4505_flash_strobe_set,217	.strobe_get = rt4505_flash_strobe_get,218	.timeout_set = rt4505_flash_timeout_set,219	.fault_get = rt4505_fault_get,220};221 222static bool rt4505_is_accessible_reg(struct device *dev, unsigned int reg)223{224	if (reg == RT4505_REG_RESET ||225		(reg >= RT4505_REG_CONFIG && reg <= RT4505_REG_FLAGS))226		return true;227	return false;228}229 230static const struct regmap_config rt4505_regmap_config = {231	.reg_bits = 8,232	.val_bits = 8,233	.max_register = RT4505_REG_FLAGS,234 235	.readable_reg = rt4505_is_accessible_reg,236	.writeable_reg = rt4505_is_accessible_reg,237};238 239#if IS_ENABLED(CONFIG_V4L2_FLASH_LED_CLASS)240static int rt4505_flash_external_strobe_set(struct v4l2_flash *v4l2_flash,241					    bool enable)242{243	struct led_classdev_flash *flash = v4l2_flash->fled_cdev;244	struct rt4505_priv *priv =245		container_of(flash, struct rt4505_priv, flash);246	u32 val = enable ? RT4505_EXT_FLASH_SET : 0;247	int ret;248 249	mutex_lock(&priv->lock);250	ret = regmap_update_bits(priv->regmap, RT4505_REG_ENABLE,251				 RT4505_ENABLE_MASK, val);252	mutex_unlock(&priv->lock);253 254	return ret;255}256 257static const struct v4l2_flash_ops v4l2_flash_ops = {258	.external_strobe_set = rt4505_flash_external_strobe_set,259};260 261static void rt4505_init_v4l2_config(struct rt4505_priv *priv,262				    struct v4l2_flash_config *config)263{264	struct led_classdev_flash *flash = &priv->flash;265	struct led_classdev *lcdev = &flash->led_cdev;266	struct led_flash_setting *s;267 268	strscpy(config->dev_name, lcdev->dev->kobj.name,269		sizeof(config->dev_name));270 271	s = &config->intensity;272	s->min = RT4505_ITORCH_MINUA;273	s->step = RT4505_ITORCH_STPUA;274	s->max = s->val = s->min + (lcdev->max_brightness - 1) * s->step;275 276	config->flash_faults = LED_FAULT_OVER_VOLTAGE |277			       LED_FAULT_SHORT_CIRCUIT |278			       LED_FAULT_LED_OVER_TEMPERATURE |279			       LED_FAULT_TIMEOUT;280	config->has_external_strobe = 1;281}282#else283static const struct v4l2_flash_ops v4l2_flash_ops;284static void rt4505_init_v4l2_config(struct rt4505_priv *priv,285				    struct v4l2_flash_config *config)286{287}288#endif289 290static void rt4505_init_flash_properties(struct rt4505_priv *priv,291					 struct fwnode_handle *child)292{293	struct led_classdev_flash *flash = &priv->flash;294	struct led_classdev *lcdev = &flash->led_cdev;295	struct led_flash_setting *s;296	u32 val;297	int ret;298 299	ret = fwnode_property_read_u32(child, "led-max-microamp", &val);300	if (ret) {301		dev_warn(priv->dev, "led-max-microamp DT property missing\n");302		val = RT4505_ITORCH_MINUA;303	} else304		val = clamp_val(val, RT4505_ITORCH_MINUA, RT4505_ITORCH_MAXUA);305 306	lcdev->max_brightness =307		(val - RT4505_ITORCH_MINUA) / RT4505_ITORCH_STPUA + 1;308	lcdev->brightness_set_blocking = rt4505_torch_brightness_set;309	lcdev->brightness_get = rt4505_torch_brightness_get;310	lcdev->flags |= LED_DEV_CAP_FLASH;311 312	ret = fwnode_property_read_u32(child, "flash-max-microamp", &val);313	if (ret) {314		dev_warn(priv->dev, "flash-max-microamp DT property missing\n");315		val = RT4505_IFLASH_MINUA;316	} else317		val = clamp_val(val, RT4505_IFLASH_MINUA, RT4505_IFLASH_MAXUA);318 319	s = &flash->brightness;320	s->min = RT4505_IFLASH_MINUA;321	s->step = RT4505_IFLASH_STPUA;322	s->max = s->val = val;323 324	ret = fwnode_property_read_u32(child, "flash-max-timeout-us", &val);325	if (ret) {326		dev_warn(priv->dev,327			 "flash-max-timeout-us DT property missing\n");328		val = RT4505_FLASHTO_MINUS;329	} else330		val = clamp_val(val, RT4505_FLASHTO_MINUS,331				RT4505_FLASHTO_MAXUS);332 333	s = &flash->timeout;334	s->min = RT4505_FLASHTO_MINUS;335	s->step = RT4505_FLASHTO_STPUS;336	s->max = s->val = val;337 338	flash->ops = &rt4505_flash_ops;339}340 341static int rt4505_probe(struct i2c_client *client)342{343	struct rt4505_priv *priv;344	struct fwnode_handle *child;345	struct led_init_data init_data = {};346	struct v4l2_flash_config v4l2_config = {};347	int ret;348 349	priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);350	if (!priv)351		return -ENOMEM;352 353	priv->dev = &client->dev;354	mutex_init(&priv->lock);355 356	priv->regmap = devm_regmap_init_i2c(client, &rt4505_regmap_config);357	if (IS_ERR(priv->regmap)) {358		dev_err(priv->dev, "Failed to allocate register map\n");359		return PTR_ERR(priv->regmap);360	}361 362	ret = regmap_write(priv->regmap, RT4505_REG_RESET, RT4505_RESET_MASK);363	if (ret) {364		dev_err(priv->dev, "Failed to reset registers\n");365		return ret;366	}367 368	child = fwnode_get_next_available_child_node(client->dev.fwnode, NULL);369	if (!child) {370		dev_err(priv->dev, "Failed to get child node\n");371		return -EINVAL;372	}373	init_data.fwnode = child;374 375	rt4505_init_flash_properties(priv, child);376	ret = devm_led_classdev_flash_register_ext(priv->dev, &priv->flash,377						   &init_data);378	if (ret) {379		dev_err(priv->dev, "Failed to register flash\n");380		return ret;381	}382 383	rt4505_init_v4l2_config(priv, &v4l2_config);384	priv->v4l2_flash = v4l2_flash_init(priv->dev, init_data.fwnode,385					   &priv->flash, &v4l2_flash_ops,386					   &v4l2_config);387	if (IS_ERR(priv->v4l2_flash)) {388		dev_err(priv->dev, "Failed to register v4l2 flash\n");389		return PTR_ERR(priv->v4l2_flash);390	}391 392	i2c_set_clientdata(client, priv);393	return 0;394}395 396static void rt4505_remove(struct i2c_client *client)397{398	struct rt4505_priv *priv = i2c_get_clientdata(client);399 400	v4l2_flash_release(priv->v4l2_flash);401}402 403static void rt4505_shutdown(struct i2c_client *client)404{405	struct rt4505_priv *priv = i2c_get_clientdata(client);406 407	/* Reset registers to make sure all off before shutdown */408	regmap_write(priv->regmap, RT4505_REG_RESET, RT4505_RESET_MASK);409}410 411static const struct of_device_id __maybe_unused rt4505_leds_match[] = {412	{ .compatible = "richtek,rt4505", },413	{}414};415MODULE_DEVICE_TABLE(of, rt4505_leds_match);416 417static struct i2c_driver rt4505_driver = {418	.driver = {419		.name = "rt4505",420		.of_match_table = of_match_ptr(rt4505_leds_match),421	},422	.probe = rt4505_probe,423	.remove = rt4505_remove,424	.shutdown = rt4505_shutdown,425};426module_i2c_driver(rt4505_driver);427 428MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");429MODULE_DESCRIPTION("Richtek RT4505 LED driver");430MODULE_LICENSE("GPL v2");431