18584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim/* 28584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim * leds-max8997.c - LED class driver for MAX8997 LEDs. 38584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim * 48584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim * Copyright (C) 2011 Samsung Electronics 58584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim * Donggeun Kim <dg77.kim@samsung.com> 68584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim * 78584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim * This program is free software; you can redistribute it and/or modify 88584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim * it under the terms of the GNU General Public License version 2 as 98584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim * published by the Free Software Foundation. 108584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim * 118584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim */ 128584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 138584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#include <linux/module.h> 148584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#include <linux/err.h> 158584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#include <linux/slab.h> 168584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#include <linux/workqueue.h> 178584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#include <linux/leds.h> 188584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#include <linux/mfd/max8997.h> 198584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#include <linux/mfd/max8997-private.h> 208584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#include <linux/platform_device.h> 218584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 228584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED_FLASH_SHIFT 3 238584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED_FLASH_CUR_MASK 0xf8 248584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED_MOVIE_SHIFT 4 258584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED_MOVIE_CUR_MASK 0xf0 268584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 278584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED_FLASH_MAX_BRIGHTNESS 0x1f 288584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED_MOVIE_MAX_BRIGHTNESS 0xf 298584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED_NONE_MAX_BRIGHTNESS 0 308584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 318584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED0_FLASH_MASK 0x1 328584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED0_FLASH_PIN_MASK 0x5 338584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED0_MOVIE_MASK 0x8 348584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED0_MOVIE_PIN_MASK 0x28 358584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 368584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED1_FLASH_MASK 0x2 378584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED1_FLASH_PIN_MASK 0x6 388584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED1_MOVIE_MASK 0x10 398584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED1_MOVIE_PIN_MASK 0x30 408584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 418584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim#define MAX8997_LED_BOOST_ENABLE_MASK (1 << 6) 428584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 438584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstruct max8997_led { 448584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct max8997_dev *iodev; 458584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct led_classdev cdev; 468584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim bool enabled; 478584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim int id; 488584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim enum max8997_led_mode led_mode; 498584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct mutex mutex; 508584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim}; 518584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 528584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstatic void max8997_led_clear_mode(struct max8997_led *led, 538584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim enum max8997_led_mode mode) 548584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim{ 558584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct i2c_client *client = led->iodev->i2c; 568584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim u8 val = 0, mask = 0; 578584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim int ret; 588584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 598584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim switch (mode) { 608584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_FLASH_MODE: 618584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mask = led->id ? 628584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK; 638584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 648584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_MOVIE_MODE: 658584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mask = led->id ? 668584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK; 678584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 688584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_FLASH_PIN_CONTROL_MODE: 698584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mask = led->id ? 708584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK; 718584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 728584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_MOVIE_PIN_CONTROL_MODE: 738584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mask = led->id ? 748584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK; 758584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 768584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim default: 778584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 788584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } 798584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 808584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (mask) { 818584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim ret = max8997_update_reg(client, 828584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim MAX8997_REG_LEN_CNTL, val, mask); 838584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (ret) 848584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim dev_err(led->iodev->dev, 858584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim "failed to update register(%d)\n", ret); 868584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } 878584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim} 888584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 898584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstatic void max8997_led_set_mode(struct max8997_led *led, 908584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim enum max8997_led_mode mode) 918584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim{ 928584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim int ret; 938584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct i2c_client *client = led->iodev->i2c; 948584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim u8 mask = 0; 958584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 968584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim /* First, clear the previous mode */ 978584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim max8997_led_clear_mode(led, led->led_mode); 988584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 998584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim switch (mode) { 1008584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_FLASH_MODE: 1018584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mask = led->id ? 1028584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK; 1038584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS; 1048584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 1058584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_MOVIE_MODE: 1068584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mask = led->id ? 1078584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK; 1088584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS; 1098584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 1108584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_FLASH_PIN_CONTROL_MODE: 1118584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mask = led->id ? 1128584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK; 1138584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS; 1148584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 1158584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_MOVIE_PIN_CONTROL_MODE: 1168584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mask = led->id ? 1178584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK; 1188584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS; 1198584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 1208584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim default: 1218584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->cdev.max_brightness = MAX8997_LED_NONE_MAX_BRIGHTNESS; 1228584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 1238584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } 1248584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 1258584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (mask) { 1268584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim ret = max8997_update_reg(client, 1278584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim MAX8997_REG_LEN_CNTL, mask, mask); 1288584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (ret) 1298584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim dev_err(led->iodev->dev, 1308584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim "failed to update register(%d)\n", ret); 1318584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } 1328584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 1338584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->led_mode = mode; 1348584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim} 1358584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 1368584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstatic void max8997_led_enable(struct max8997_led *led, bool enable) 1378584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim{ 1388584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim int ret; 1398584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct i2c_client *client = led->iodev->i2c; 1408584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim u8 val = 0, mask = MAX8997_LED_BOOST_ENABLE_MASK; 1418584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 1428584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (led->enabled == enable) 1438584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim return; 1448584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 1458584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim val = enable ? MAX8997_LED_BOOST_ENABLE_MASK : 0; 1468584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 1478584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim ret = max8997_update_reg(client, MAX8997_REG_BOOST_CNTL, val, mask); 1488584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (ret) 1498584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim dev_err(led->iodev->dev, 1508584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim "failed to update register(%d)\n", ret); 1518584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 1528584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->enabled = enable; 1538584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim} 1548584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 1558584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstatic void max8997_led_set_current(struct max8997_led *led, 1568584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim enum led_brightness value) 1578584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim{ 1588584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim int ret; 1598584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct i2c_client *client = led->iodev->i2c; 1608584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim u8 val = 0, mask = 0, reg = 0; 1618584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 1628584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim switch (led->led_mode) { 1638584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_FLASH_MODE: 1648584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_FLASH_PIN_CONTROL_MODE: 1658584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim val = value << MAX8997_LED_FLASH_SHIFT; 1668584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mask = MAX8997_LED_FLASH_CUR_MASK; 1678584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim reg = led->id ? MAX8997_REG_FLASH2_CUR : MAX8997_REG_FLASH1_CUR; 1688584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 1698584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_MOVIE_MODE: 1708584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_MOVIE_PIN_CONTROL_MODE: 1718584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim val = value << MAX8997_LED_MOVIE_SHIFT; 1728584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mask = MAX8997_LED_MOVIE_CUR_MASK; 1738584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim reg = MAX8997_REG_MOVIE_CUR; 1748584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 1758584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim default: 1768584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 1778584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } 1788584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 1798584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (mask) { 1808584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim ret = max8997_update_reg(client, reg, val, mask); 1818584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (ret) 1828584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim dev_err(led->iodev->dev, 1838584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim "failed to update register(%d)\n", ret); 1848584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } 1858584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim} 1868584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 1878584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstatic void max8997_led_brightness_set(struct led_classdev *led_cdev, 1888584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim enum led_brightness value) 1898584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim{ 1908584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct max8997_led *led = 1918584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim container_of(led_cdev, struct max8997_led, cdev); 1928584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 1938584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (value) { 1948584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim max8997_led_set_current(led, value); 1958584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim max8997_led_enable(led, true); 1968584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } else { 1978584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim max8997_led_set_current(led, value); 1988584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim max8997_led_enable(led, false); 1998584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } 2008584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim} 2018584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2028584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstatic ssize_t max8997_led_show_mode(struct device *dev, 2038584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct device_attribute *attr, char *buf) 2048584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim{ 2058584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct led_classdev *led_cdev = dev_get_drvdata(dev); 2068584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct max8997_led *led = 2078584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim container_of(led_cdev, struct max8997_led, cdev); 2088584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim ssize_t ret = 0; 2098584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2108584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mutex_lock(&led->mutex); 2118584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2128584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim switch (led->led_mode) { 2138584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_FLASH_MODE: 2148584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim ret += sprintf(buf, "FLASH\n"); 2158584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 2168584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_MOVIE_MODE: 2178584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim ret += sprintf(buf, "MOVIE\n"); 2188584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 2198584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_FLASH_PIN_CONTROL_MODE: 2208584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim ret += sprintf(buf, "FLASH_PIN_CONTROL\n"); 2218584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 2228584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim case MAX8997_MOVIE_PIN_CONTROL_MODE: 2238584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim ret += sprintf(buf, "MOVIE_PIN_CONTROL\n"); 2248584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 2258584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim default: 2268584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim ret += sprintf(buf, "NONE\n"); 2278584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim break; 2288584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } 2298584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2308584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mutex_unlock(&led->mutex); 2318584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2328584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim return ret; 2338584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim} 2348584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2358584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstatic ssize_t max8997_led_store_mode(struct device *dev, 2368584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct device_attribute *attr, 2378584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim const char *buf, size_t size) 2388584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim{ 2398584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct led_classdev *led_cdev = dev_get_drvdata(dev); 2408584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct max8997_led *led = 2418584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim container_of(led_cdev, struct max8997_led, cdev); 2428584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim enum max8997_led_mode mode; 2438584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2448584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mutex_lock(&led->mutex); 2458584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2468584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (!strncmp(buf, "FLASH_PIN_CONTROL", 17)) 2478584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mode = MAX8997_FLASH_PIN_CONTROL_MODE; 2488584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim else if (!strncmp(buf, "MOVIE_PIN_CONTROL", 17)) 2498584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mode = MAX8997_MOVIE_PIN_CONTROL_MODE; 2508584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim else if (!strncmp(buf, "FLASH", 5)) 2518584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mode = MAX8997_FLASH_MODE; 2528584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim else if (!strncmp(buf, "MOVIE", 5)) 2538584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mode = MAX8997_MOVIE_MODE; 2548584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim else 2558584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mode = MAX8997_NONE; 2568584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2578584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim max8997_led_set_mode(led, mode); 2588584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2598584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mutex_unlock(&led->mutex); 2608584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2618584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim return size; 2628584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim} 2638584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2648584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstatic DEVICE_ATTR(mode, 0644, max8997_led_show_mode, max8997_led_store_mode); 2658584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2668584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstatic int __devinit max8997_led_probe(struct platform_device *pdev) 2678584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim{ 2688584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); 2698584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); 2708584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct max8997_led *led; 2718584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim char name[20]; 2728584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim int ret = 0; 2738584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2748584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (pdata == NULL) { 2758584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim dev_err(&pdev->dev, "no platform data\n"); 2768584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim return -ENODEV; 2778584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } 2788584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2798584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led = kzalloc(sizeof(*led), GFP_KERNEL); 2808584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (led == NULL) { 2818584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim ret = -ENOMEM; 2828584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim goto err_mem; 2838584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } 2848584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2858584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->id = pdev->id; 2868584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim snprintf(name, sizeof(name), "max8997-led%d", pdev->id); 2878584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2888584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->cdev.name = name; 2898584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->cdev.brightness_set = max8997_led_brightness_set; 2908584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->cdev.flags |= LED_CORE_SUSPENDRESUME; 2918584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->cdev.brightness = 0; 2928584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->iodev = iodev; 2938584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2948584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim /* initialize mode and brightness according to platform_data */ 2958584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (pdata->led_pdata) { 2968584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim u8 mode = 0, brightness = 0; 2978584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 2988584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mode = pdata->led_pdata->mode[led->id]; 2998584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim brightness = pdata->led_pdata->brightness[led->id]; 3008584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3018584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim max8997_led_set_mode(led, pdata->led_pdata->mode[led->id]); 3028584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3038584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (brightness > led->cdev.max_brightness) 3048584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim brightness = led->cdev.max_brightness; 3058584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim max8997_led_set_current(led, brightness); 3068584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led->cdev.brightness = brightness; 3078584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } else { 3088584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim max8997_led_set_mode(led, MAX8997_NONE); 3098584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim max8997_led_set_current(led, 0); 3108584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } 3118584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3128584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim mutex_init(&led->mutex); 3138584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3148584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim platform_set_drvdata(pdev, led); 3158584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3168584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim ret = led_classdev_register(&pdev->dev, &led->cdev); 3178584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (ret < 0) 3188584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim goto err_led; 3198584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3208584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim ret = device_create_file(led->cdev.dev, &dev_attr_mode); 3218584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim if (ret != 0) { 3228584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim dev_err(&pdev->dev, 3238584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim "failed to create file: %d\n", ret); 3248584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim goto err_file; 3258584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim } 3268584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3278584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim return 0; 3288584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3298584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimerr_file: 3308584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led_classdev_unregister(&led->cdev); 3318584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimerr_led: 3328584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim kfree(led); 3338584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimerr_mem: 3348584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim return ret; 3358584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim} 3368584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3378584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstatic int __devexit max8997_led_remove(struct platform_device *pdev) 3388584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim{ 3398584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim struct max8997_led *led = platform_get_drvdata(pdev); 3408584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3418584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim device_remove_file(led->cdev.dev, &dev_attr_mode); 3428584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim led_classdev_unregister(&led->cdev); 3438584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim kfree(led); 3448584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3458584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim return 0; 3468584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim} 3478584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3488584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstatic struct platform_driver max8997_led_driver = { 3498584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim .driver = { 3508584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim .name = "max8997-led", 3518584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim .owner = THIS_MODULE, 3528584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim }, 3538584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim .probe = max8997_led_probe, 3548584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim .remove = __devexit_p(max8997_led_remove), 3558584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim}; 3568584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3578584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstatic int __init max8997_led_init(void) 3588584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim{ 3598584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim return platform_driver_register(&max8997_led_driver); 3608584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim} 3618584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimmodule_init(max8997_led_init); 3628584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3638584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimstatic void __exit max8997_led_exit(void) 3648584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim{ 3658584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim platform_driver_unregister(&max8997_led_driver); 3668584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim} 3678584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kimmodule_exit(max8997_led_exit); 3688584cb82f1516042e7390082d27b7c29329e21f4Donggeun Kim 3698584cb82f1516042e7390082d27b7c29329e21f4Donggeun KimMODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); 3708584cb82f1516042e7390082d27b7c29329e21f4Donggeun KimMODULE_DESCRIPTION("MAX8997 LED driver"); 3718584cb82f1516042e7390082d27b7c29329e21f4Donggeun KimMODULE_LICENSE("GPL"); 3728584cb82f1516042e7390082d27b7c29329e21f4Donggeun KimMODULE_ALIAS("platform:max8997-led"); 373