brintos

brintos / linux-shallow public Read only

0
0
Text · 7.3 KiB · c8d7f55 Raw
295 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * leds-max8997.c - LED class driver for MAX8997 LEDs.4 *5 * Copyright (C) 2011 Samsung Electronics6 * Donggeun Kim <dg77.kim@samsung.com>7 */8 9#include <linux/module.h>10#include <linux/err.h>11#include <linux/slab.h>12#include <linux/leds.h>13#include <linux/mfd/max8997.h>14#include <linux/mfd/max8997-private.h>15#include <linux/platform_device.h>16 17#define MAX8997_LED_FLASH_SHIFT			318#define MAX8997_LED_FLASH_CUR_MASK		0xf819#define MAX8997_LED_MOVIE_SHIFT			420#define MAX8997_LED_MOVIE_CUR_MASK		0xf021 22#define MAX8997_LED_FLASH_MAX_BRIGHTNESS	0x1f23#define MAX8997_LED_MOVIE_MAX_BRIGHTNESS	0xf24#define MAX8997_LED_NONE_MAX_BRIGHTNESS		025 26#define MAX8997_LED0_FLASH_MASK			0x127#define MAX8997_LED0_FLASH_PIN_MASK		0x528#define MAX8997_LED0_MOVIE_MASK			0x829#define MAX8997_LED0_MOVIE_PIN_MASK		0x2830 31#define MAX8997_LED1_FLASH_MASK			0x232#define MAX8997_LED1_FLASH_PIN_MASK		0x633#define MAX8997_LED1_MOVIE_MASK			0x1034#define MAX8997_LED1_MOVIE_PIN_MASK		0x3035 36#define MAX8997_LED_BOOST_ENABLE_MASK		(1 << 6)37 38struct max8997_led {39	struct max8997_dev *iodev;40	struct led_classdev cdev;41	bool enabled;42	int id;43	enum max8997_led_mode led_mode;44	struct mutex mutex;45};46 47static void max8997_led_set_mode(struct max8997_led *led,48			enum max8997_led_mode mode)49{50	int ret;51	struct i2c_client *client = led->iodev->i2c;52	u8 mask = 0, val;53 54	switch (mode) {55	case MAX8997_FLASH_MODE:56		mask = MAX8997_LED1_FLASH_MASK | MAX8997_LED0_FLASH_MASK;57		val = led->id ?58		      MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK;59		led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;60		break;61	case MAX8997_MOVIE_MODE:62		mask = MAX8997_LED1_MOVIE_MASK | MAX8997_LED0_MOVIE_MASK;63		val = led->id ?64		      MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK;65		led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;66		break;67	case MAX8997_FLASH_PIN_CONTROL_MODE:68		mask = MAX8997_LED1_FLASH_PIN_MASK |69		       MAX8997_LED0_FLASH_PIN_MASK;70		val = led->id ?71		      MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK;72		led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;73		break;74	case MAX8997_MOVIE_PIN_CONTROL_MODE:75		mask = MAX8997_LED1_MOVIE_PIN_MASK |76		       MAX8997_LED0_MOVIE_PIN_MASK;77		val = led->id ?78		      MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK;79		led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;80		break;81	default:82		led->cdev.max_brightness = MAX8997_LED_NONE_MAX_BRIGHTNESS;83		break;84	}85 86	if (mask) {87		ret = max8997_update_reg(client, MAX8997_REG_LEN_CNTL, val,88					 mask);89		if (ret)90			dev_err(led->iodev->dev,91				"failed to update register(%d)\n", ret);92	}93 94	led->led_mode = mode;95}96 97static void max8997_led_enable(struct max8997_led *led, bool enable)98{99	int ret;100	struct i2c_client *client = led->iodev->i2c;101	u8 val = 0, mask = MAX8997_LED_BOOST_ENABLE_MASK;102 103	if (led->enabled == enable)104		return;105 106	val = enable ? MAX8997_LED_BOOST_ENABLE_MASK : 0;107 108	ret = max8997_update_reg(client, MAX8997_REG_BOOST_CNTL, val, mask);109	if (ret)110		dev_err(led->iodev->dev,111			"failed to update register(%d)\n", ret);112 113	led->enabled = enable;114}115 116static void max8997_led_set_current(struct max8997_led *led,117				enum led_brightness value)118{119	int ret;120	struct i2c_client *client = led->iodev->i2c;121	u8 val = 0, mask = 0, reg = 0;122 123	switch (led->led_mode) {124	case MAX8997_FLASH_MODE:125	case MAX8997_FLASH_PIN_CONTROL_MODE:126		val = value << MAX8997_LED_FLASH_SHIFT;127		mask = MAX8997_LED_FLASH_CUR_MASK;128		reg = led->id ? MAX8997_REG_FLASH2_CUR : MAX8997_REG_FLASH1_CUR;129		break;130	case MAX8997_MOVIE_MODE:131	case MAX8997_MOVIE_PIN_CONTROL_MODE:132		val = value << MAX8997_LED_MOVIE_SHIFT;133		mask = MAX8997_LED_MOVIE_CUR_MASK;134		reg = MAX8997_REG_MOVIE_CUR;135		break;136	default:137		break;138	}139 140	if (mask) {141		ret = max8997_update_reg(client, reg, val, mask);142		if (ret)143			dev_err(led->iodev->dev,144				"failed to update register(%d)\n", ret);145	}146}147 148static void max8997_led_brightness_set(struct led_classdev *led_cdev,149				enum led_brightness value)150{151	struct max8997_led *led =152			container_of(led_cdev, struct max8997_led, cdev);153 154	if (value) {155		max8997_led_set_current(led, value);156		max8997_led_enable(led, true);157	} else {158		max8997_led_set_current(led, value);159		max8997_led_enable(led, false);160	}161}162 163static ssize_t mode_show(struct device *dev,164			 struct device_attribute *attr, char *buf)165{166	struct led_classdev *led_cdev = dev_get_drvdata(dev);167	struct max8997_led *led =168			container_of(led_cdev, struct max8997_led, cdev);169	ssize_t ret = 0;170 171	mutex_lock(&led->mutex);172 173	switch (led->led_mode) {174	case MAX8997_FLASH_MODE:175		ret += sprintf(buf, "FLASH\n");176		break;177	case MAX8997_MOVIE_MODE:178		ret += sprintf(buf, "MOVIE\n");179		break;180	case MAX8997_FLASH_PIN_CONTROL_MODE:181		ret += sprintf(buf, "FLASH_PIN_CONTROL\n");182		break;183	case MAX8997_MOVIE_PIN_CONTROL_MODE:184		ret += sprintf(buf, "MOVIE_PIN_CONTROL\n");185		break;186	default:187		ret += sprintf(buf, "NONE\n");188		break;189	}190 191	mutex_unlock(&led->mutex);192 193	return ret;194}195 196static ssize_t mode_store(struct device *dev,197			  struct device_attribute *attr,198			  const char *buf, size_t size)199{200	struct led_classdev *led_cdev = dev_get_drvdata(dev);201	struct max8997_led *led =202			container_of(led_cdev, struct max8997_led, cdev);203	enum max8997_led_mode mode;204 205	mutex_lock(&led->mutex);206 207	if (!strncmp(buf, "FLASH_PIN_CONTROL", 17))208		mode = MAX8997_FLASH_PIN_CONTROL_MODE;209	else if (!strncmp(buf, "MOVIE_PIN_CONTROL", 17))210		mode = MAX8997_MOVIE_PIN_CONTROL_MODE;211	else if (!strncmp(buf, "FLASH", 5))212		mode = MAX8997_FLASH_MODE;213	else if (!strncmp(buf, "MOVIE", 5))214		mode = MAX8997_MOVIE_MODE;215	else216		mode = MAX8997_NONE;217 218	max8997_led_set_mode(led, mode);219 220	mutex_unlock(&led->mutex);221 222	return size;223}224 225static DEVICE_ATTR_RW(mode);226 227static struct attribute *max8997_attrs[] = {228	&dev_attr_mode.attr,229	NULL230};231ATTRIBUTE_GROUPS(max8997);232 233static int max8997_led_probe(struct platform_device *pdev)234{235	struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);236	struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);237	struct max8997_led *led;238	char name[20];239	int ret = 0;240 241	led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);242	if (led == NULL)243		return -ENOMEM;244 245	led->id = pdev->id;246	snprintf(name, sizeof(name), "max8997-led%d", pdev->id);247 248	led->cdev.name = name;249	led->cdev.brightness_set = max8997_led_brightness_set;250	led->cdev.flags |= LED_CORE_SUSPENDRESUME;251	led->cdev.brightness = 0;252	led->cdev.groups = max8997_groups;253	led->iodev = iodev;254 255	/* initialize mode and brightness according to platform_data */256	if (pdata && pdata->led_pdata) {257		u8 mode = 0, brightness = 0;258 259		mode = pdata->led_pdata->mode[led->id];260		brightness = pdata->led_pdata->brightness[led->id];261 262		max8997_led_set_mode(led, mode);263 264		if (brightness > led->cdev.max_brightness)265			brightness = led->cdev.max_brightness;266		max8997_led_set_current(led, brightness);267		led->cdev.brightness = brightness;268	} else {269		max8997_led_set_mode(led, MAX8997_NONE);270		max8997_led_set_current(led, 0);271	}272 273	mutex_init(&led->mutex);274 275	ret = devm_led_classdev_register(&pdev->dev, &led->cdev);276	if (ret < 0)277		return ret;278 279	return 0;280}281 282static struct platform_driver max8997_led_driver = {283	.driver = {284		.name  = "max8997-led",285	},286	.probe  = max8997_led_probe,287};288 289module_platform_driver(max8997_led_driver);290 291MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");292MODULE_DESCRIPTION("MAX8997 LED driver");293MODULE_LICENSE("GPL");294MODULE_ALIAS("platform:max8997-led");295