diff --git a/[refs] b/[refs] index cde46a141833..218a94318011 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: fe7e96f66b2622d8492ee9dd7fc08b811086caca +refs/heads/master: 5d0af85cd0964bb845b63d5059bb20e8f7731e65 diff --git a/trunk/Documentation/ABI/obsolete/proc-pid-oom_adj b/trunk/Documentation/ABI/obsolete/proc-pid-oom_adj deleted file mode 100644 index cf63f264ce0f..000000000000 --- a/trunk/Documentation/ABI/obsolete/proc-pid-oom_adj +++ /dev/null @@ -1,22 +0,0 @@ -What: /proc//oom_adj -When: August 2012 -Why: /proc//oom_adj allows userspace to influence the oom killer's - badness heuristic used to determine which task to kill when the kernel - is out of memory. - - The badness heuristic has since been rewritten since the introduction of - this tunable such that its meaning is deprecated. The value was - implemented as a bitshift on a score generated by the badness() - function that did not have any precise units of measure. With the - rewrite, the score is given as a proportion of available memory to the - task allocating pages, so using a bitshift which grows the score - exponentially is, thus, impossible to tune with fine granularity. - - A much more powerful interface, /proc//oom_score_adj, was - introduced with the oom killer rewrite that allows users to increase or - decrease the badness() score linearly. This interface will replace - /proc//oom_adj. - - A warning will be emitted to the kernel log if an application uses this - deprecated interface. After it is printed once, future warnings will be - suppressed until the kernel is rebooted. diff --git a/trunk/Documentation/filesystems/xfs-delayed-logging-design.txt b/trunk/Documentation/filesystems/xfs-delayed-logging-design.txt index 96d0df28bed3..7445bf335dae 100644 --- a/trunk/Documentation/filesystems/xfs-delayed-logging-design.txt +++ b/trunk/Documentation/filesystems/xfs-delayed-logging-design.txt @@ -794,17 +794,6 @@ designed. Roadmap: -2.6.37 Remove experimental tag from mount option - => should be roughly 6 months after initial merge - => enough time to: - => gain confidence and fix problems reported by early - adopters (a.k.a. guinea pigs) - => address worst performance regressions and undesired - behaviours - => start tuning/optimising code for parallelism - => start tuning/optimising algorithms consuming - excessive CPU time - 2.6.39 Switch default mount option to use delayed logging => should be roughly 12 months after initial merge => enough time to shake out remaining problems before next round of diff --git a/trunk/Documentation/leds-class.txt b/trunk/Documentation/leds-class.txt index 58b266bd1846..8fd5ca2ae32d 100644 --- a/trunk/Documentation/leds-class.txt +++ b/trunk/Documentation/leds-class.txt @@ -60,18 +60,15 @@ Hardware accelerated blink of LEDs Some LEDs can be programmed to blink without any CPU interaction. To support this feature, a LED driver can optionally implement the -blink_set() function (see ). To set an LED to blinking, -however, it is better to use use the API function led_blink_set(), -as it will check and implement software fallback if necessary. - -To turn off blinking again, use the API function led_brightness_set() -as that will not just set the LED brightness but also stop any software -timers that may have been required for blinking. - -The blink_set() function should choose a user friendly blinking value -if it is called with *delay_on==0 && *delay_off==0 parameters. In this -case the driver should give back the chosen value through delay_on and -delay_off parameters to the leds subsystem. +blink_set() function (see ). If implemented, triggers can +attempt to use it before falling back to software timers. The blink_set() +function should return 0 if the blink setting is supported, or -EINVAL +otherwise, which means that LED blinking will be handled by software. + +The blink_set() function should choose a user friendly blinking +value if it is called with *delay_on==0 && *delay_off==0 parameters. In +this case the driver should give back the chosen value through delay_on +and delay_off parameters to the leds subsystem. Setting the brightness to zero with brightness_set() callback function should completely turn off the LED and cancel the previously programmed diff --git a/trunk/Documentation/leds/leds-lp5521.txt b/trunk/Documentation/leds/leds-lp5521.txt deleted file mode 100644 index c4d8d151e0fe..000000000000 --- a/trunk/Documentation/leds/leds-lp5521.txt +++ /dev/null @@ -1,88 +0,0 @@ -Kernel driver for lp5521 -======================== - -* National Semiconductor LP5521 led driver chip -* Datasheet: http://www.national.com/pf/LP/LP5521.html - -Authors: Mathias Nyman, Yuri Zaporozhets, Samu Onkalo -Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com) - -Description ------------ - -LP5521 can drive up to 3 channels. Leds can be controlled directly via -the led class control interface. Channels have generic names: -lp5521:channelx, where x is 0 .. 2 - -All three channels can be also controlled using the engine micro programs. -More details of the instructions can be found from the public data sheet. - -Control interface for the engines: -x is 1 .. 3 -enginex_mode : disabled, load, run -enginex_load : store program (visible only in engine load mode) - -Example (start to blink the channel 2 led): -cd /sys/class/leds/lp5521:channel2/device -echo "load" > engine3_mode -echo "037f4d0003ff6000" > engine3_load -echo "run" > engine3_mode - -stop the engine: -echo "disabled" > engine3_mode - -sysfs contains a selftest entry. -The test communicates with the chip and checks that -the clock mode is automatically set to the requested one. - -Each channel has its own led current settings. -/sys/class/leds/lp5521:channel0/led_current - RW -/sys/class/leds/lp5521:channel0/max_current - RO -Format: 10x mA i.e 10 means 1.0 mA - -example platform data: - -Note: chan_nr can have values between 0 and 2. - -static struct lp5521_led_config lp5521_led_config[] = { - { - .chan_nr = 0, - .led_current = 50, - .max_current = 130, - }, { - .chan_nr = 1, - .led_current = 0, - .max_current = 130, - }, { - .chan_nr = 2, - .led_current = 0, - .max_current = 130, - } -}; - -static int lp5521_setup(void) -{ - /* setup HW resources */ -} - -static void lp5521_release(void) -{ - /* Release HW resources */ -} - -static void lp5521_enable(bool state) -{ - /* Control of chip enable signal */ -} - -static struct lp5521_platform_data lp5521_platform_data = { - .led_config = lp5521_led_config, - .num_channels = ARRAY_SIZE(lp5521_led_config), - .clock_mode = LP5521_CLOCK_EXT, - .setup_resources = lp5521_setup, - .release_resources = lp5521_release, - .enable = lp5521_enable, -}; - -If the current is set to 0 in the platform data, that channel is -disabled and it is not visible in the sysfs. diff --git a/trunk/Documentation/leds/leds-lp5523.txt b/trunk/Documentation/leds/leds-lp5523.txt deleted file mode 100644 index fad2feb8b7ce..000000000000 --- a/trunk/Documentation/leds/leds-lp5523.txt +++ /dev/null @@ -1,83 +0,0 @@ -Kernel driver for lp5523 -======================== - -* National Semiconductor LP5523 led driver chip -* Datasheet: http://www.national.com/pf/LP/LP5523.html - -Authors: Mathias Nyman, Yuri Zaporozhets, Samu Onkalo -Contact: Samu Onkalo (samu.p.onkalo-at-nokia.com) - -Description ------------ -LP5523 can drive up to 9 channels. Leds can be controlled directly via -the led class control interface. Channels have generic names: -lp5523:channelx where x is 0...8 - -The chip provides 3 engines. Each engine can control channels without -interaction from the main CPU. Details of the micro engine code can be found -from the public data sheet. Leds can be muxed to different channels. - -Control interface for the engines: -x is 1 .. 3 -enginex_mode : disabled, load, run -enginex_load : microcode load (visible only in load mode) -enginex_leds : led mux control (visible only in load mode) - -cd /sys/class/leds/lp5523:channel2/device -echo "load" > engine3_mode -echo "9d80400004ff05ff437f0000" > engine3_load -echo "111111111" > engine3_leds -echo "run" > engine3_mode - -sysfs contains a selftest entry. It measures each channel -voltage level and checks if it looks reasonable. If the level is too high, -the led is missing; if the level is too low, there is a short circuit. - -Selftest uses always the current from the platform data. - -Each channel contains led current settings. -/sys/class/leds/lp5523:channel2/led_current - RW -/sys/class/leds/lp5523:channel2/max_current - RO -Format: 10x mA i.e 10 means 1.0 mA - -Example platform data: - -Note - chan_nr can have values between 0 and 8. - -static struct lp5523_led_config lp5523_led_config[] = { - { - .chan_nr = 0, - .led_current = 50, - .max_current = 130, - }, -... - }, { - .chan_nr = 8, - .led_current = 50, - .max_current = 130, - } -}; - -static int lp5523_setup(void) -{ - /* Setup HW resources */ -} - -static void lp5523_release(void) -{ - /* Release HW resources */ -} - -static void lp5523_enable(bool state) -{ - /* Control chip enable signal */ -} - -static struct lp5523_platform_data lp5523_platform_data = { - .led_config = lp5523_led_config, - .num_channels = ARRAY_SIZE(lp5523_led_config), - .clock_mode = LP5523_CLOCK_EXT, - .setup_resources = lp5523_setup, - .release_resources = lp5523_release, - .enable = lp5523_enable, -}; diff --git a/trunk/Documentation/sysctl/kernel.txt b/trunk/Documentation/sysctl/kernel.txt index 209e1584c3dc..3894eaa23486 100644 --- a/trunk/Documentation/sysctl/kernel.txt +++ b/trunk/Documentation/sysctl/kernel.txt @@ -28,7 +28,6 @@ show up in /proc/sys/kernel: - core_uses_pid - ctrl-alt-del - dentry-state -- dmesg_restrict - domainname - hostname - hotplug @@ -214,19 +213,6 @@ to decide what to do with it. ============================================================== -dmesg_restrict: - -This toggle indicates whether unprivileged users are prevented from using -dmesg(8) to view messages from the kernel's log buffer. When -dmesg_restrict is set to (0) there are no restrictions. When -dmesg_restrict is set set to (1), users must have CAP_SYS_ADMIN to use -dmesg(8). - -The kernel config option CONFIG_SECURITY_DMESG_RESTRICT sets the default -value of dmesg_restrict. - -============================================================== - domainname & hostname: These files can be used to set the NIS/YP domainname and the diff --git a/trunk/arch/um/include/asm/ptrace-generic.h b/trunk/arch/um/include/asm/ptrace-generic.h index b7c5bab9bd77..2cd899f75a3c 100644 --- a/trunk/arch/um/include/asm/ptrace-generic.h +++ b/trunk/arch/um/include/asm/ptrace-generic.h @@ -38,8 +38,8 @@ struct pt_regs { struct task_struct; -extern long subarch_ptrace(struct task_struct *child, long request, - unsigned long addr, unsigned long data); +extern long subarch_ptrace(struct task_struct *child, long request, long addr, + long data); extern unsigned long getreg(struct task_struct *child, int regno); extern int putreg(struct task_struct *child, int regno, unsigned long value); extern int get_fpregs(struct user_i387_struct __user *buf, diff --git a/trunk/arch/um/kernel/ptrace.c b/trunk/arch/um/kernel/ptrace.c index 701b672c1122..a5e33f29bbeb 100644 --- a/trunk/arch/um/kernel/ptrace.c +++ b/trunk/arch/um/kernel/ptrace.c @@ -122,7 +122,7 @@ long arch_ptrace(struct task_struct *child, long request, break; case PTRACE_SET_THREAD_AREA: - ret = ptrace_set_thread_area(child, addr, vp); + ret = ptrace_set_thread_area(child, addr, datavp); break; case PTRACE_FAULTINFO: { diff --git a/trunk/crypto/pcrypt.c b/trunk/crypto/pcrypt.c index 75586f1f86e7..de3078215fe6 100644 --- a/trunk/crypto/pcrypt.c +++ b/trunk/crypto/pcrypt.c @@ -504,6 +504,7 @@ static int pcrypt_init_padata(struct padata_pcrypt *pcrypt, static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt) { + kobject_put(&pcrypt->pinst->kobj); free_cpumask_var(pcrypt->cb_cpumask->mask); kfree(pcrypt->cb_cpumask); diff --git a/trunk/drivers/leds/Kconfig b/trunk/drivers/leds/Kconfig index 77b8fd20cd90..cc2a88d5192f 100644 --- a/trunk/drivers/leds/Kconfig +++ b/trunk/drivers/leds/Kconfig @@ -10,7 +10,7 @@ menuconfig NEW_LEDS if NEW_LEDS config LEDS_CLASS - bool "LED Class Support" + tristate "LED Class Support" help This option enables the led sysfs class in /sys/class/leds. You'll need this to do anything useful with LEDs. If unsure, say N. @@ -176,24 +176,6 @@ config LEDS_LP3944 To compile this driver as a module, choose M here: the module will be called leds-lp3944. -config LEDS_LP5521 - tristate "LED Support for N.S. LP5521 LED driver chip" - depends on LEDS_CLASS && I2C - help - If you say yes here you get support for the National Semiconductor - LP5521 LED driver. It is 3 channel chip with programmable engines. - Driver provides direct control via LED class and interface for - programming the engines. - -config LEDS_LP5523 - tristate "LED Support for N.S. LP5523 LED driver chip" - depends on LEDS_CLASS && I2C - help - If you say yes here you get support for the National Semiconductor - LP5523 LED driver. It is 9 channel chip with programmable engines. - Driver provides direct control via LED class and interface for - programming the engines. - config LEDS_CLEVO_MAIL tristate "Mail LED on Clevo notebook" depends on X86 && SERIO_I8042 && DMI diff --git a/trunk/drivers/leds/Makefile b/trunk/drivers/leds/Makefile index aae6989ff6b6..9c96db40ef6d 100644 --- a/trunk/drivers/leds/Makefile +++ b/trunk/drivers/leds/Makefile @@ -23,8 +23,6 @@ obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o -obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o -obj-$(CONFIG_LEDS_LP5523) += leds-lp5523.o obj-$(CONFIG_LEDS_CLEVO_MAIL) += leds-clevo-mail.o obj-$(CONFIG_LEDS_HP6XX) += leds-hp6xx.o obj-$(CONFIG_LEDS_FSG) += leds-fsg.o diff --git a/trunk/drivers/leds/led-class.c b/trunk/drivers/leds/led-class.c index 211e21f34bd5..260660076507 100644 --- a/trunk/drivers/leds/led-class.c +++ b/trunk/drivers/leds/led-class.c @@ -81,79 +81,6 @@ static struct device_attribute led_class_attrs[] = { __ATTR_NULL, }; -static void led_timer_function(unsigned long data) -{ - struct led_classdev *led_cdev = (void *)data; - unsigned long brightness; - unsigned long delay; - - if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) { - led_set_brightness(led_cdev, LED_OFF); - return; - } - - brightness = led_get_brightness(led_cdev); - if (!brightness) { - /* Time to switch the LED on. */ - brightness = led_cdev->blink_brightness; - delay = led_cdev->blink_delay_on; - } else { - /* Store the current brightness value to be able - * to restore it when the delay_off period is over. - */ - led_cdev->blink_brightness = brightness; - brightness = LED_OFF; - delay = led_cdev->blink_delay_off; - } - - led_set_brightness(led_cdev, brightness); - - mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay)); -} - -static void led_stop_software_blink(struct led_classdev *led_cdev) -{ - /* deactivate previous settings */ - del_timer_sync(&led_cdev->blink_timer); - led_cdev->blink_delay_on = 0; - led_cdev->blink_delay_off = 0; -} - -static void led_set_software_blink(struct led_classdev *led_cdev, - unsigned long delay_on, - unsigned long delay_off) -{ - int current_brightness; - - current_brightness = led_get_brightness(led_cdev); - if (current_brightness) - led_cdev->blink_brightness = current_brightness; - if (!led_cdev->blink_brightness) - led_cdev->blink_brightness = led_cdev->max_brightness; - - if (delay_on == led_cdev->blink_delay_on && - delay_off == led_cdev->blink_delay_off) - return; - - led_stop_software_blink(led_cdev); - - led_cdev->blink_delay_on = delay_on; - led_cdev->blink_delay_off = delay_off; - - /* never on - don't blink */ - if (!delay_on) - return; - - /* never off - just set to brightness */ - if (!delay_off) { - led_set_brightness(led_cdev, led_cdev->blink_brightness); - return; - } - - mod_timer(&led_cdev->blink_timer, jiffies + 1); -} - - /** * led_classdev_suspend - suspend an led_classdev. * @led_cdev: the led_classdev to suspend. @@ -221,10 +148,6 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) led_update_brightness(led_cdev); - init_timer(&led_cdev->blink_timer); - led_cdev->blink_timer.function = led_timer_function; - led_cdev->blink_timer.data = (unsigned long)led_cdev; - #ifdef CONFIG_LEDS_TRIGGERS led_trigger_set_default(led_cdev); #endif @@ -234,6 +157,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) return 0; } + EXPORT_SYMBOL_GPL(led_classdev_register); /** @@ -251,9 +175,6 @@ void led_classdev_unregister(struct led_classdev *led_cdev) up_write(&led_cdev->trigger_lock); #endif - /* Stop blinking */ - led_brightness_set(led_cdev, LED_OFF); - device_unregister(led_cdev->dev); down_write(&leds_list_lock); @@ -262,30 +183,6 @@ void led_classdev_unregister(struct led_classdev *led_cdev) } EXPORT_SYMBOL_GPL(led_classdev_unregister); -void led_blink_set(struct led_classdev *led_cdev, - unsigned long *delay_on, - unsigned long *delay_off) -{ - if (led_cdev->blink_set && - led_cdev->blink_set(led_cdev, delay_on, delay_off)) - return; - - /* blink with 1 Hz as default if nothing specified */ - if (!*delay_on && !*delay_off) - *delay_on = *delay_off = 500; - - led_set_software_blink(led_cdev, *delay_on, *delay_off); -} -EXPORT_SYMBOL(led_blink_set); - -void led_brightness_set(struct led_classdev *led_cdev, - enum led_brightness brightness) -{ - led_stop_software_blink(led_cdev); - led_cdev->brightness_set(led_cdev, brightness); -} -EXPORT_SYMBOL(led_brightness_set); - static int __init leds_init(void) { leds_class = class_create(THIS_MODULE, "leds"); diff --git a/trunk/drivers/leds/led-triggers.c b/trunk/drivers/leds/led-triggers.c index c41eb6180c9c..f1c00db88b5e 100644 --- a/trunk/drivers/leds/led-triggers.c +++ b/trunk/drivers/leds/led-triggers.c @@ -113,7 +113,7 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger) if (led_cdev->trigger->deactivate) led_cdev->trigger->deactivate(led_cdev); led_cdev->trigger = NULL; - led_brightness_set(led_cdev, LED_OFF); + led_set_brightness(led_cdev, LED_OFF); } if (trigger) { write_lock_irqsave(&trigger->leddev_list_lock, flags); diff --git a/trunk/drivers/leds/leds-gpio.c b/trunk/drivers/leds/leds-gpio.c index 4d9fa38d9ff6..ea57e05d08f3 100644 --- a/trunk/drivers/leds/leds-gpio.c +++ b/trunk/drivers/leds/leds-gpio.c @@ -316,7 +316,7 @@ static struct of_platform_driver of_gpio_leds_driver = { static int __init gpio_led_init(void) { - int ret = 0; + int ret; #ifdef CONFIG_LEDS_GPIO_PLATFORM ret = platform_driver_register(&gpio_led_driver); diff --git a/trunk/drivers/leds/leds-lp5521.c b/trunk/drivers/leds/leds-lp5521.c deleted file mode 100644 index 3782f31f06d2..000000000000 --- a/trunk/drivers/leds/leds-lp5521.c +++ /dev/null @@ -1,821 +0,0 @@ -/* - * LP5521 LED chip driver. - * - * Copyright (C) 2010 Nokia Corporation - * - * Contact: Samu Onkalo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define LP5521_PROGRAM_LENGTH 32 /* in bytes */ - -#define LP5521_MAX_LEDS 3 /* Maximum number of LEDs */ -#define LP5521_MAX_ENGINES 3 /* Maximum number of engines */ - -#define LP5521_ENG_MASK_BASE 0x30 /* 00110000 */ -#define LP5521_ENG_STATUS_MASK 0x07 /* 00000111 */ - -#define LP5521_CMD_LOAD 0x15 /* 00010101 */ -#define LP5521_CMD_RUN 0x2a /* 00101010 */ -#define LP5521_CMD_DIRECT 0x3f /* 00111111 */ -#define LP5521_CMD_DISABLED 0x00 /* 00000000 */ - -/* Registers */ -#define LP5521_REG_ENABLE 0x00 -#define LP5521_REG_OP_MODE 0x01 -#define LP5521_REG_R_PWM 0x02 -#define LP5521_REG_G_PWM 0x03 -#define LP5521_REG_B_PWM 0x04 -#define LP5521_REG_R_CURRENT 0x05 -#define LP5521_REG_G_CURRENT 0x06 -#define LP5521_REG_B_CURRENT 0x07 -#define LP5521_REG_CONFIG 0x08 -#define LP5521_REG_R_CHANNEL_PC 0x09 -#define LP5521_REG_G_CHANNEL_PC 0x0A -#define LP5521_REG_B_CHANNEL_PC 0x0B -#define LP5521_REG_STATUS 0x0C -#define LP5521_REG_RESET 0x0D -#define LP5521_REG_GPO 0x0E -#define LP5521_REG_R_PROG_MEM 0x10 -#define LP5521_REG_G_PROG_MEM 0x30 -#define LP5521_REG_B_PROG_MEM 0x50 - -#define LP5521_PROG_MEM_BASE LP5521_REG_R_PROG_MEM -#define LP5521_PROG_MEM_SIZE 0x20 - -/* Base register to set LED current */ -#define LP5521_REG_LED_CURRENT_BASE LP5521_REG_R_CURRENT - -/* Base register to set the brightness */ -#define LP5521_REG_LED_PWM_BASE LP5521_REG_R_PWM - -/* Bits in ENABLE register */ -#define LP5521_MASTER_ENABLE 0x40 /* Chip master enable */ -#define LP5521_LOGARITHMIC_PWM 0x80 /* Logarithmic PWM adjustment */ -#define LP5521_EXEC_RUN 0x2A - -/* Bits in CONFIG register */ -#define LP5521_PWM_HF 0x40 /* PWM: 0 = 256Hz, 1 = 558Hz */ -#define LP5521_PWRSAVE_EN 0x20 /* 1 = Power save mode */ -#define LP5521_CP_MODE_OFF 0 /* Charge pump (CP) off */ -#define LP5521_CP_MODE_BYPASS 8 /* CP forced to bypass mode */ -#define LP5521_CP_MODE_1X5 0x10 /* CP forced to 1.5x mode */ -#define LP5521_CP_MODE_AUTO 0x18 /* Automatic mode selection */ -#define LP5521_R_TO_BATT 4 /* R out: 0 = CP, 1 = Vbat */ -#define LP5521_CLK_SRC_EXT 0 /* Ext-clk source (CLK_32K) */ -#define LP5521_CLK_INT 1 /* Internal clock */ -#define LP5521_CLK_AUTO 2 /* Automatic clock selection */ - -/* Status */ -#define LP5521_EXT_CLK_USED 0x08 - -struct lp5521_engine { - const struct attribute_group *attributes; - int id; - u8 mode; - u8 prog_page; - u8 engine_mask; -}; - -struct lp5521_led { - int id; - u8 chan_nr; - u8 led_current; - u8 max_current; - struct led_classdev cdev; - struct work_struct brightness_work; - u8 brightness; -}; - -struct lp5521_chip { - struct lp5521_platform_data *pdata; - struct mutex lock; /* Serialize control */ - struct i2c_client *client; - struct lp5521_engine engines[LP5521_MAX_ENGINES]; - struct lp5521_led leds[LP5521_MAX_LEDS]; - u8 num_channels; - u8 num_leds; -}; - -#define cdev_to_led(c) container_of(c, struct lp5521_led, cdev) -#define engine_to_lp5521(eng) container_of((eng), struct lp5521_chip, \ - engines[(eng)->id - 1]) -#define led_to_lp5521(led) container_of((led), struct lp5521_chip, \ - leds[(led)->id]) - -static void lp5521_led_brightness_work(struct work_struct *work); - -static inline int lp5521_write(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int lp5521_read(struct i2c_client *client, u8 reg, u8 *buf) -{ - s32 ret; - - ret = i2c_smbus_read_byte_data(client, reg); - if (ret < 0) - return -EIO; - - *buf = ret; - return 0; -} - -static int lp5521_set_engine_mode(struct lp5521_engine *engine, u8 mode) -{ - struct lp5521_chip *chip = engine_to_lp5521(engine); - struct i2c_client *client = chip->client; - int ret; - u8 engine_state; - - /* Only transition between RUN and DIRECT mode are handled here */ - if (mode == LP5521_CMD_LOAD) - return 0; - - if (mode == LP5521_CMD_DISABLED) - mode = LP5521_CMD_DIRECT; - - ret = lp5521_read(client, LP5521_REG_OP_MODE, &engine_state); - - /* set mode only for this engine */ - engine_state &= ~(engine->engine_mask); - mode &= engine->engine_mask; - engine_state |= mode; - ret |= lp5521_write(client, LP5521_REG_OP_MODE, engine_state); - - return ret; -} - -static int lp5521_load_program(struct lp5521_engine *eng, const u8 *pattern) -{ - struct lp5521_chip *chip = engine_to_lp5521(eng); - struct i2c_client *client = chip->client; - int ret; - int addr; - u8 mode; - - /* move current engine to direct mode and remember the state */ - ret = lp5521_set_engine_mode(eng, LP5521_CMD_DIRECT); - usleep_range(1000, 10000); - ret |= lp5521_read(client, LP5521_REG_OP_MODE, &mode); - - /* For loading, all the engines to load mode */ - lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_DIRECT); - usleep_range(1000, 10000); - lp5521_write(client, LP5521_REG_OP_MODE, LP5521_CMD_LOAD); - usleep_range(1000, 10000); - - addr = LP5521_PROG_MEM_BASE + eng->prog_page * LP5521_PROG_MEM_SIZE; - i2c_smbus_write_i2c_block_data(client, - addr, - LP5521_PROG_MEM_SIZE, - pattern); - - ret |= lp5521_write(client, LP5521_REG_OP_MODE, mode); - return ret; -} - -static int lp5521_set_led_current(struct lp5521_chip *chip, int led, u8 curr) -{ - return lp5521_write(chip->client, - LP5521_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr, - curr); -} - -static void lp5521_init_engine(struct lp5521_chip *chip, - const struct attribute_group *attr_group) -{ - int i; - for (i = 0; i < ARRAY_SIZE(chip->engines); i++) { - chip->engines[i].id = i + 1; - chip->engines[i].engine_mask = LP5521_ENG_MASK_BASE >> (i * 2); - chip->engines[i].prog_page = i; - chip->engines[i].attributes = &attr_group[i]; - } -} - -static int lp5521_configure(struct i2c_client *client, - const struct attribute_group *attr_group) -{ - struct lp5521_chip *chip = i2c_get_clientdata(client); - int ret; - - lp5521_init_engine(chip, attr_group); - - lp5521_write(client, LP5521_REG_RESET, 0xff); - - usleep_range(10000, 20000); - - /* Set all PWMs to direct control mode */ - ret = lp5521_write(client, LP5521_REG_OP_MODE, 0x3F); - - /* Enable auto-powersave, set charge pump to auto, red to battery */ - ret |= lp5521_write(client, LP5521_REG_CONFIG, - LP5521_PWRSAVE_EN | LP5521_CP_MODE_AUTO | LP5521_R_TO_BATT); - - /* Initialize all channels PWM to zero -> leds off */ - ret |= lp5521_write(client, LP5521_REG_R_PWM, 0); - ret |= lp5521_write(client, LP5521_REG_G_PWM, 0); - ret |= lp5521_write(client, LP5521_REG_B_PWM, 0); - - /* Set engines are set to run state when OP_MODE enables engines */ - ret |= lp5521_write(client, LP5521_REG_ENABLE, - LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM | - LP5521_EXEC_RUN); - /* enable takes 500us */ - usleep_range(500, 20000); - - return ret; -} - -static int lp5521_run_selftest(struct lp5521_chip *chip, char *buf) -{ - int ret; - u8 status; - - ret = lp5521_read(chip->client, LP5521_REG_STATUS, &status); - if (ret < 0) - return ret; - - /* Check that ext clock is really in use if requested */ - if (chip->pdata && chip->pdata->clock_mode == LP5521_CLOCK_EXT) - if ((status & LP5521_EXT_CLK_USED) == 0) - return -EIO; - return 0; -} - -static void lp5521_set_brightness(struct led_classdev *cdev, - enum led_brightness brightness) -{ - struct lp5521_led *led = cdev_to_led(cdev); - led->brightness = (u8)brightness; - schedule_work(&led->brightness_work); -} - -static void lp5521_led_brightness_work(struct work_struct *work) -{ - struct lp5521_led *led = container_of(work, - struct lp5521_led, - brightness_work); - struct lp5521_chip *chip = led_to_lp5521(led); - struct i2c_client *client = chip->client; - - mutex_lock(&chip->lock); - lp5521_write(client, LP5521_REG_LED_PWM_BASE + led->chan_nr, - led->brightness); - mutex_unlock(&chip->lock); -} - -/* Detect the chip by setting its ENABLE register and reading it back. */ -static int lp5521_detect(struct i2c_client *client) -{ - int ret; - u8 buf; - - ret = lp5521_write(client, LP5521_REG_ENABLE, - LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM); - if (ret) - return ret; - usleep_range(1000, 10000); - ret = lp5521_read(client, LP5521_REG_ENABLE, &buf); - if (ret) - return ret; - if (buf != (LP5521_MASTER_ENABLE | LP5521_LOGARITHMIC_PWM)) - return -ENODEV; - - return 0; -} - -/* Set engine mode and create appropriate sysfs attributes, if required. */ -static int lp5521_set_mode(struct lp5521_engine *engine, u8 mode) -{ - struct lp5521_chip *chip = engine_to_lp5521(engine); - struct i2c_client *client = chip->client; - struct device *dev = &client->dev; - int ret = 0; - - /* if in that mode already do nothing, except for run */ - if (mode == engine->mode && mode != LP5521_CMD_RUN) - return 0; - - if (mode == LP5521_CMD_RUN) { - ret = lp5521_set_engine_mode(engine, LP5521_CMD_RUN); - } else if (mode == LP5521_CMD_LOAD) { - lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED); - lp5521_set_engine_mode(engine, LP5521_CMD_LOAD); - - ret = sysfs_create_group(&dev->kobj, engine->attributes); - if (ret) - return ret; - } else if (mode == LP5521_CMD_DISABLED) { - lp5521_set_engine_mode(engine, LP5521_CMD_DISABLED); - } - - /* remove load attribute from sysfs if not in load mode */ - if (engine->mode == LP5521_CMD_LOAD && mode != LP5521_CMD_LOAD) - sysfs_remove_group(&dev->kobj, engine->attributes); - - engine->mode = mode; - - return ret; -} - -static int lp5521_do_store_load(struct lp5521_engine *engine, - const char *buf, size_t len) -{ - struct lp5521_chip *chip = engine_to_lp5521(engine); - struct i2c_client *client = chip->client; - int ret, nrchars, offset = 0, i = 0; - char c[3]; - unsigned cmd; - u8 pattern[LP5521_PROGRAM_LENGTH] = {0}; - - while ((offset < len - 1) && (i < LP5521_PROGRAM_LENGTH)) { - /* separate sscanfs because length is working only for %s */ - ret = sscanf(buf + offset, "%2s%n ", c, &nrchars); - ret = sscanf(c, "%2x", &cmd); - if (ret != 1) - goto fail; - pattern[i] = (u8)cmd; - - offset += nrchars; - i++; - } - - /* Each instruction is 16bit long. Check that length is even */ - if (i % 2) - goto fail; - - mutex_lock(&chip->lock); - ret = lp5521_load_program(engine, pattern); - mutex_unlock(&chip->lock); - - if (ret) { - dev_err(&client->dev, "failed loading pattern\n"); - return ret; - } - - return len; -fail: - dev_err(&client->dev, "wrong pattern format\n"); - return -EINVAL; -} - -static ssize_t store_engine_load(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lp5521_chip *chip = i2c_get_clientdata(client); - return lp5521_do_store_load(&chip->engines[nr - 1], buf, len); -} - -#define store_load(nr) \ -static ssize_t store_engine##nr##_load(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t len) \ -{ \ - return store_engine_load(dev, attr, buf, len, nr); \ -} -store_load(1) -store_load(2) -store_load(3) - -static ssize_t show_engine_mode(struct device *dev, - struct device_attribute *attr, - char *buf, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lp5521_chip *chip = i2c_get_clientdata(client); - switch (chip->engines[nr - 1].mode) { - case LP5521_CMD_RUN: - return sprintf(buf, "run\n"); - case LP5521_CMD_LOAD: - return sprintf(buf, "load\n"); - case LP5521_CMD_DISABLED: - return sprintf(buf, "disabled\n"); - default: - return sprintf(buf, "disabled\n"); - } -} - -#define show_mode(nr) \ -static ssize_t show_engine##nr##_mode(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_engine_mode(dev, attr, buf, nr); \ -} -show_mode(1) -show_mode(2) -show_mode(3) - -static ssize_t store_engine_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lp5521_chip *chip = i2c_get_clientdata(client); - struct lp5521_engine *engine = &chip->engines[nr - 1]; - mutex_lock(&chip->lock); - - if (!strncmp(buf, "run", 3)) - lp5521_set_mode(engine, LP5521_CMD_RUN); - else if (!strncmp(buf, "load", 4)) - lp5521_set_mode(engine, LP5521_CMD_LOAD); - else if (!strncmp(buf, "disabled", 8)) - lp5521_set_mode(engine, LP5521_CMD_DISABLED); - - mutex_unlock(&chip->lock); - return len; -} - -#define store_mode(nr) \ -static ssize_t store_engine##nr##_mode(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t len) \ -{ \ - return store_engine_mode(dev, attr, buf, len, nr); \ -} -store_mode(1) -store_mode(2) -store_mode(3) - -static ssize_t show_max_current(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct lp5521_led *led = cdev_to_led(led_cdev); - - return sprintf(buf, "%d\n", led->max_current); -} - -static ssize_t show_current(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct lp5521_led *led = cdev_to_led(led_cdev); - - return sprintf(buf, "%d\n", led->led_current); -} - -static ssize_t store_current(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct lp5521_led *led = cdev_to_led(led_cdev); - struct lp5521_chip *chip = led_to_lp5521(led); - ssize_t ret; - unsigned long curr; - - if (strict_strtoul(buf, 0, &curr)) - return -EINVAL; - - if (curr > led->max_current) - return -EINVAL; - - mutex_lock(&chip->lock); - ret = lp5521_set_led_current(chip, led->id, curr); - mutex_unlock(&chip->lock); - - if (ret < 0) - return ret; - - led->led_current = (u8)curr; - - return len; -} - -static ssize_t lp5521_selftest(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lp5521_chip *chip = i2c_get_clientdata(client); - int ret; - - mutex_lock(&chip->lock); - ret = lp5521_run_selftest(chip, buf); - mutex_unlock(&chip->lock); - return sprintf(buf, "%s\n", ret ? "FAIL" : "OK"); -} - -/* led class device attributes */ -static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current); -static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL); - -static struct attribute *lp5521_led_attributes[] = { - &dev_attr_led_current.attr, - &dev_attr_max_current.attr, - NULL, -}; - -static struct attribute_group lp5521_led_attribute_group = { - .attrs = lp5521_led_attributes -}; - -/* device attributes */ -static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO, - show_engine1_mode, store_engine1_mode); -static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO, - show_engine2_mode, store_engine2_mode); -static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO, - show_engine3_mode, store_engine3_mode); -static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load); -static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load); -static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load); -static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL); - -static struct attribute *lp5521_attributes[] = { - &dev_attr_engine1_mode.attr, - &dev_attr_engine2_mode.attr, - &dev_attr_engine3_mode.attr, - &dev_attr_selftest.attr, - NULL -}; - -static struct attribute *lp5521_engine1_attributes[] = { - &dev_attr_engine1_load.attr, - NULL -}; - -static struct attribute *lp5521_engine2_attributes[] = { - &dev_attr_engine2_load.attr, - NULL -}; - -static struct attribute *lp5521_engine3_attributes[] = { - &dev_attr_engine3_load.attr, - NULL -}; - -static const struct attribute_group lp5521_group = { - .attrs = lp5521_attributes, -}; - -static const struct attribute_group lp5521_engine_group[] = { - {.attrs = lp5521_engine1_attributes }, - {.attrs = lp5521_engine2_attributes }, - {.attrs = lp5521_engine3_attributes }, -}; - -static int lp5521_register_sysfs(struct i2c_client *client) -{ - struct device *dev = &client->dev; - return sysfs_create_group(&dev->kobj, &lp5521_group); -} - -static void lp5521_unregister_sysfs(struct i2c_client *client) -{ - struct lp5521_chip *chip = i2c_get_clientdata(client); - struct device *dev = &client->dev; - int i; - - sysfs_remove_group(&dev->kobj, &lp5521_group); - - for (i = 0; i < ARRAY_SIZE(chip->engines); i++) { - if (chip->engines[i].mode == LP5521_CMD_LOAD) - sysfs_remove_group(&dev->kobj, - chip->engines[i].attributes); - } - - for (i = 0; i < chip->num_leds; i++) - sysfs_remove_group(&chip->leds[i].cdev.dev->kobj, - &lp5521_led_attribute_group); -} - -static int __init lp5521_init_led(struct lp5521_led *led, - struct i2c_client *client, - int chan, struct lp5521_platform_data *pdata) -{ - struct device *dev = &client->dev; - char name[32]; - int res; - - if (chan >= LP5521_MAX_LEDS) - return -EINVAL; - - if (pdata->led_config[chan].led_current == 0) - return 0; - - led->led_current = pdata->led_config[chan].led_current; - led->max_current = pdata->led_config[chan].max_current; - led->chan_nr = pdata->led_config[chan].chan_nr; - - if (led->chan_nr >= LP5521_MAX_LEDS) { - dev_err(dev, "Use channel numbers between 0 and %d\n", - LP5521_MAX_LEDS - 1); - return -EINVAL; - } - - snprintf(name, sizeof(name), "%s:channel%d", client->name, chan); - led->cdev.brightness_set = lp5521_set_brightness; - led->cdev.name = name; - res = led_classdev_register(dev, &led->cdev); - if (res < 0) { - dev_err(dev, "couldn't register led on channel %d\n", chan); - return res; - } - - res = sysfs_create_group(&led->cdev.dev->kobj, - &lp5521_led_attribute_group); - if (res < 0) { - dev_err(dev, "couldn't register current attribute\n"); - led_classdev_unregister(&led->cdev); - return res; - } - return 0; -} - -static int lp5521_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct lp5521_chip *chip; - struct lp5521_platform_data *pdata; - int ret, i, led; - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - i2c_set_clientdata(client, chip); - chip->client = client; - - pdata = client->dev.platform_data; - - if (!pdata) { - dev_err(&client->dev, "no platform data\n"); - ret = -EINVAL; - goto fail1; - } - - mutex_init(&chip->lock); - - chip->pdata = pdata; - - if (pdata->setup_resources) { - ret = pdata->setup_resources(); - if (ret < 0) - goto fail1; - } - - if (pdata->enable) { - pdata->enable(0); - usleep_range(1000, 10000); - pdata->enable(1); - usleep_range(1000, 10000); /* Spec says min 500us */ - } - - ret = lp5521_detect(client); - - if (ret) { - dev_err(&client->dev, "Chip not found\n"); - goto fail2; - } - - dev_info(&client->dev, "%s programmable led chip found\n", id->name); - - ret = lp5521_configure(client, lp5521_engine_group); - if (ret < 0) { - dev_err(&client->dev, "error configuring chip\n"); - goto fail2; - } - - /* Initialize leds */ - chip->num_channels = pdata->num_channels; - chip->num_leds = 0; - led = 0; - for (i = 0; i < pdata->num_channels; i++) { - /* Do not initialize channels that are not connected */ - if (pdata->led_config[i].led_current == 0) - continue; - - ret = lp5521_init_led(&chip->leds[led], client, i, pdata); - if (ret) { - dev_err(&client->dev, "error initializing leds\n"); - goto fail3; - } - chip->num_leds++; - - chip->leds[led].id = led; - /* Set initial LED current */ - lp5521_set_led_current(chip, led, - chip->leds[led].led_current); - - INIT_WORK(&(chip->leds[led].brightness_work), - lp5521_led_brightness_work); - - led++; - } - - ret = lp5521_register_sysfs(client); - if (ret) { - dev_err(&client->dev, "registering sysfs failed\n"); - goto fail3; - } - return ret; -fail3: - for (i = 0; i < chip->num_leds; i++) { - led_classdev_unregister(&chip->leds[i].cdev); - cancel_work_sync(&chip->leds[i].brightness_work); - } -fail2: - if (pdata->enable) - pdata->enable(0); - if (pdata->release_resources) - pdata->release_resources(); -fail1: - kfree(chip); - return ret; -} - -static int lp5521_remove(struct i2c_client *client) -{ - struct lp5521_chip *chip = i2c_get_clientdata(client); - int i; - - lp5521_unregister_sysfs(client); - - for (i = 0; i < chip->num_leds; i++) { - led_classdev_unregister(&chip->leds[i].cdev); - cancel_work_sync(&chip->leds[i].brightness_work); - } - - if (chip->pdata->enable) - chip->pdata->enable(0); - if (chip->pdata->release_resources) - chip->pdata->release_resources(); - kfree(chip); - return 0; -} - -static const struct i2c_device_id lp5521_id[] = { - { "lp5521", 0 }, /* Three channel chip */ - { } -}; -MODULE_DEVICE_TABLE(i2c, lp5521_id); - -static struct i2c_driver lp5521_driver = { - .driver = { - .name = "lp5521", - }, - .probe = lp5521_probe, - .remove = lp5521_remove, - .id_table = lp5521_id, -}; - -static int __init lp5521_init(void) -{ - int ret; - - ret = i2c_add_driver(&lp5521_driver); - - if (ret < 0) - printk(KERN_ALERT "Adding lp5521 driver failed\n"); - - return ret; -} - -static void __exit lp5521_exit(void) -{ - i2c_del_driver(&lp5521_driver); -} - -module_init(lp5521_init); -module_exit(lp5521_exit); - -MODULE_AUTHOR("Mathias Nyman, Yuri Zaporozhets, Samu Onkalo"); -MODULE_DESCRIPTION("LP5521 LED engine"); -MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/leds/leds-lp5523.c b/trunk/drivers/leds/leds-lp5523.c deleted file mode 100644 index 1e11fcc08b28..000000000000 --- a/trunk/drivers/leds/leds-lp5523.c +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * lp5523.c - LP5523 LED Driver - * - * Copyright (C) 2010 Nokia Corporation - * - * Contact: Samu Onkalo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define LP5523_REG_ENABLE 0x00 -#define LP5523_REG_OP_MODE 0x01 -#define LP5523_REG_RATIOMETRIC_MSB 0x02 -#define LP5523_REG_RATIOMETRIC_LSB 0x03 -#define LP5523_REG_ENABLE_LEDS_MSB 0x04 -#define LP5523_REG_ENABLE_LEDS_LSB 0x05 -#define LP5523_REG_LED_CNTRL_BASE 0x06 -#define LP5523_REG_LED_PWM_BASE 0x16 -#define LP5523_REG_LED_CURRENT_BASE 0x26 -#define LP5523_REG_CONFIG 0x36 -#define LP5523_REG_CHANNEL1_PC 0x37 -#define LP5523_REG_CHANNEL2_PC 0x38 -#define LP5523_REG_CHANNEL3_PC 0x39 -#define LP5523_REG_STATUS 0x3a -#define LP5523_REG_GPO 0x3b -#define LP5523_REG_VARIABLE 0x3c -#define LP5523_REG_RESET 0x3d -#define LP5523_REG_TEMP_CTRL 0x3e -#define LP5523_REG_TEMP_READ 0x3f -#define LP5523_REG_TEMP_WRITE 0x40 -#define LP5523_REG_LED_TEST_CTRL 0x41 -#define LP5523_REG_LED_TEST_ADC 0x42 -#define LP5523_REG_ENG1_VARIABLE 0x45 -#define LP5523_REG_ENG2_VARIABLE 0x46 -#define LP5523_REG_ENG3_VARIABLE 0x47 -#define LP5523_REG_MASTER_FADER1 0x48 -#define LP5523_REG_MASTER_FADER2 0x49 -#define LP5523_REG_MASTER_FADER3 0x4a -#define LP5523_REG_CH1_PROG_START 0x4c -#define LP5523_REG_CH2_PROG_START 0x4d -#define LP5523_REG_CH3_PROG_START 0x4e -#define LP5523_REG_PROG_PAGE_SEL 0x4f -#define LP5523_REG_PROG_MEM 0x50 - -#define LP5523_CMD_LOAD 0x15 /* 00010101 */ -#define LP5523_CMD_RUN 0x2a /* 00101010 */ -#define LP5523_CMD_DISABLED 0x00 /* 00000000 */ - -#define LP5523_ENABLE 0x40 -#define LP5523_AUTO_INC 0x40 -#define LP5523_PWR_SAVE 0x20 -#define LP5523_PWM_PWR_SAVE 0x04 -#define LP5523_CP_1 0x08 -#define LP5523_CP_1_5 0x10 -#define LP5523_CP_AUTO 0x18 -#define LP5523_INT_CLK 0x01 -#define LP5523_AUTO_CLK 0x02 -#define LP5523_EN_LEDTEST 0x80 -#define LP5523_LEDTEST_DONE 0x80 - -#define LP5523_DEFAULT_CURRENT 50 /* microAmps */ -#define LP5523_PROGRAM_LENGTH 32 /* in bytes */ -#define LP5523_PROGRAM_PAGES 6 -#define LP5523_ADC_SHORTCIRC_LIM 80 - -#define LP5523_LEDS 9 -#define LP5523_ENGINES 3 - -#define LP5523_ENG_MASK_BASE 0x30 /* 00110000 */ - -#define LP5523_ENG_STATUS_MASK 0x07 /* 00000111 */ - -#define LP5523_IRQ_FLAGS IRQF_TRIGGER_FALLING - -#define LP5523_EXT_CLK_USED 0x08 - -#define LED_ACTIVE(mux, led) (!!(mux & (0x0001 << led))) -#define SHIFT_MASK(id) (((id) - 1) * 2) - -struct lp5523_engine { - const struct attribute_group *attributes; - int id; - u8 mode; - u8 prog_page; - u8 mux_page; - u16 led_mux; - u8 engine_mask; -}; - -struct lp5523_led { - int id; - u8 chan_nr; - u8 led_current; - u8 max_current; - struct led_classdev cdev; - struct work_struct brightness_work; - u8 brightness; -}; - -struct lp5523_chip { - struct mutex lock; /* Serialize control */ - struct i2c_client *client; - struct lp5523_engine engines[LP5523_ENGINES]; - struct lp5523_led leds[LP5523_LEDS]; - struct lp5523_platform_data *pdata; - u8 num_channels; - u8 num_leds; -}; - -#define cdev_to_led(c) container_of(c, struct lp5523_led, cdev) - -static struct lp5523_chip *engine_to_lp5523(struct lp5523_engine *engine) -{ - return container_of(engine, struct lp5523_chip, - engines[engine->id - 1]); -} - -static struct lp5523_chip *led_to_lp5523(struct lp5523_led *led) -{ - return container_of(led, struct lp5523_chip, - leds[led->id]); -} - -static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode); -static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode); -static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern); - -static void lp5523_led_brightness_work(struct work_struct *work); - -static int lp5523_write(struct i2c_client *client, u8 reg, u8 value) -{ - return i2c_smbus_write_byte_data(client, reg, value); -} - -static int lp5523_read(struct i2c_client *client, u8 reg, u8 *buf) -{ - s32 ret = i2c_smbus_read_byte_data(client, reg); - - if (ret < 0) - return -EIO; - - *buf = ret; - return 0; -} - -static int lp5523_detect(struct i2c_client *client) -{ - int ret; - u8 buf; - - ret = lp5523_write(client, LP5523_REG_ENABLE, 0x40); - if (ret) - return ret; - ret = lp5523_read(client, LP5523_REG_ENABLE, &buf); - if (ret) - return ret; - if (buf == 0x40) - return 0; - else - return -ENODEV; -} - -static int lp5523_configure(struct i2c_client *client) -{ - struct lp5523_chip *chip = i2c_get_clientdata(client); - int ret = 0; - u8 status; - - /* one pattern per engine setting led mux start and stop addresses */ - u8 pattern[][LP5523_PROGRAM_LENGTH] = { - { 0x9c, 0x30, 0x9c, 0xb0, 0x9d, 0x80, 0xd8, 0x00, 0}, - { 0x9c, 0x40, 0x9c, 0xc0, 0x9d, 0x80, 0xd8, 0x00, 0}, - { 0x9c, 0x50, 0x9c, 0xd0, 0x9d, 0x80, 0xd8, 0x00, 0}, - }; - - lp5523_write(client, LP5523_REG_RESET, 0xff); - - usleep_range(10000, 100000); - - ret |= lp5523_write(client, LP5523_REG_ENABLE, LP5523_ENABLE); - /* Chip startup time after reset is 500 us */ - usleep_range(1000, 10000); - - ret |= lp5523_write(client, LP5523_REG_CONFIG, - LP5523_AUTO_INC | LP5523_PWR_SAVE | - LP5523_CP_AUTO | LP5523_AUTO_CLK | - LP5523_PWM_PWR_SAVE); - - /* turn on all leds */ - ret |= lp5523_write(client, LP5523_REG_ENABLE_LEDS_MSB, 0x01); - ret |= lp5523_write(client, LP5523_REG_ENABLE_LEDS_LSB, 0xff); - - /* hardcode 32 bytes of memory for each engine from program memory */ - ret |= lp5523_write(client, LP5523_REG_CH1_PROG_START, 0x00); - ret |= lp5523_write(client, LP5523_REG_CH2_PROG_START, 0x10); - ret |= lp5523_write(client, LP5523_REG_CH3_PROG_START, 0x20); - - /* write led mux address space for each channel */ - ret |= lp5523_load_program(&chip->engines[0], pattern[0]); - ret |= lp5523_load_program(&chip->engines[1], pattern[1]); - ret |= lp5523_load_program(&chip->engines[2], pattern[2]); - - if (ret) { - dev_err(&client->dev, "could not load mux programs\n"); - return -1; - } - - /* set all engines exec state and mode to run 00101010 */ - ret |= lp5523_write(client, LP5523_REG_ENABLE, - (LP5523_CMD_RUN | LP5523_ENABLE)); - - ret |= lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_RUN); - - if (ret) { - dev_err(&client->dev, "could not start mux programs\n"); - return -1; - } - - /* Wait 3ms and check the engine status */ - usleep_range(3000, 20000); - lp5523_read(client, LP5523_REG_STATUS, &status); - status &= LP5523_ENG_STATUS_MASK; - - if (status == LP5523_ENG_STATUS_MASK) { - dev_dbg(&client->dev, "all engines configured\n"); - } else { - dev_info(&client->dev, "status == %x\n", status); - dev_err(&client->dev, "cound not configure LED engine\n"); - return -1; - } - - dev_info(&client->dev, "disabling engines\n"); - - ret |= lp5523_write(client, LP5523_REG_OP_MODE, LP5523_CMD_DISABLED); - - return ret; -} - -static int lp5523_set_engine_mode(struct lp5523_engine *engine, u8 mode) -{ - struct lp5523_chip *chip = engine_to_lp5523(engine); - struct i2c_client *client = chip->client; - int ret; - u8 engine_state; - - ret = lp5523_read(client, LP5523_REG_OP_MODE, &engine_state); - if (ret) - goto fail; - - engine_state &= ~(engine->engine_mask); - - /* set mode only for this engine */ - mode &= engine->engine_mask; - - engine_state |= mode; - - ret |= lp5523_write(client, LP5523_REG_OP_MODE, engine_state); -fail: - return ret; -} - -static int lp5523_load_mux(struct lp5523_engine *engine, u16 mux) -{ - struct lp5523_chip *chip = engine_to_lp5523(engine); - struct i2c_client *client = chip->client; - int ret = 0; - - ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); - - ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL, engine->mux_page); - ret |= lp5523_write(client, LP5523_REG_PROG_MEM, - (u8)(mux >> 8)); - ret |= lp5523_write(client, LP5523_REG_PROG_MEM + 1, (u8)(mux)); - engine->led_mux = mux; - - return ret; -} - -static int lp5523_load_program(struct lp5523_engine *engine, u8 *pattern) -{ - struct lp5523_chip *chip = engine_to_lp5523(engine); - struct i2c_client *client = chip->client; - - int ret = 0; - - ret |= lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); - - ret |= lp5523_write(client, LP5523_REG_PROG_PAGE_SEL, - engine->prog_page); - ret |= i2c_smbus_write_i2c_block_data(client, LP5523_REG_PROG_MEM, - LP5523_PROGRAM_LENGTH, pattern); - - return ret; -} - -static int lp5523_run_program(struct lp5523_engine *engine) -{ - struct lp5523_chip *chip = engine_to_lp5523(engine); - struct i2c_client *client = chip->client; - int ret; - - ret = lp5523_write(client, LP5523_REG_ENABLE, - LP5523_CMD_RUN | LP5523_ENABLE); - if (ret) - goto fail; - - ret = lp5523_set_engine_mode(engine, LP5523_CMD_RUN); -fail: - return ret; -} - -static int lp5523_mux_parse(const char *buf, u16 *mux, size_t len) -{ - int i; - u16 tmp_mux = 0; - len = len < LP5523_LEDS ? len : LP5523_LEDS; - for (i = 0; i < len; i++) { - switch (buf[i]) { - case '1': - tmp_mux |= (1 << i); - break; - case '0': - break; - case '\n': - i = len; - break; - default: - return -1; - } - } - *mux = tmp_mux; - - return 0; -} - -static void lp5523_mux_to_array(u16 led_mux, char *array) -{ - int i, pos = 0; - for (i = 0; i < LP5523_LEDS; i++) - pos += sprintf(array + pos, "%x", LED_ACTIVE(led_mux, i)); - - array[pos] = '\0'; -} - -/*--------------------------------------------------------------*/ -/* Sysfs interface */ -/*--------------------------------------------------------------*/ - -static ssize_t show_engine_leds(struct device *dev, - struct device_attribute *attr, - char *buf, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lp5523_chip *chip = i2c_get_clientdata(client); - char mux[LP5523_LEDS + 1]; - - lp5523_mux_to_array(chip->engines[nr - 1].led_mux, mux); - - return sprintf(buf, "%s\n", mux); -} - -#define show_leds(nr) \ -static ssize_t show_engine##nr##_leds(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_engine_leds(dev, attr, buf, nr); \ -} -show_leds(1) -show_leds(2) -show_leds(3) - -static ssize_t store_engine_leds(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lp5523_chip *chip = i2c_get_clientdata(client); - u16 mux = 0; - - if (lp5523_mux_parse(buf, &mux, len)) - return -EINVAL; - - if (lp5523_load_mux(&chip->engines[nr - 1], mux)) - return -EINVAL; - - return len; -} - -#define store_leds(nr) \ -static ssize_t store_engine##nr##_leds(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t len) \ -{ \ - return store_engine_leds(dev, attr, buf, len, nr); \ -} -store_leds(1) -store_leds(2) -store_leds(3) - -static ssize_t lp5523_selftest(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lp5523_chip *chip = i2c_get_clientdata(client); - int i, ret, pos = 0; - int led = 0; - u8 status, adc, vdd; - - mutex_lock(&chip->lock); - - ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status); - if (ret < 0) - goto fail; - - /* Check that ext clock is really in use if requested */ - if ((chip->pdata) && (chip->pdata->clock_mode == LP5523_CLOCK_EXT)) - if ((status & LP5523_EXT_CLK_USED) == 0) - goto fail; - - /* Measure VDD (i.e. VBAT) first (channel 16 corresponds to VDD) */ - lp5523_write(chip->client, LP5523_REG_LED_TEST_CTRL, - LP5523_EN_LEDTEST | 16); - usleep_range(3000, 10000); - ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status); - if (!(status & LP5523_LEDTEST_DONE)) - usleep_range(3000, 10000); - - ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &vdd); - vdd--; /* There may be some fluctuation in measurement */ - - for (i = 0; i < LP5523_LEDS; i++) { - /* Skip non-existing channels */ - if (chip->pdata->led_config[i].led_current == 0) - continue; - - /* Set default current */ - lp5523_write(chip->client, - LP5523_REG_LED_CURRENT_BASE + i, - chip->pdata->led_config[i].led_current); - - lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0xff); - /* let current stabilize 2ms before measurements start */ - usleep_range(2000, 10000); - lp5523_write(chip->client, - LP5523_REG_LED_TEST_CTRL, - LP5523_EN_LEDTEST | i); - /* ledtest takes 2.7ms */ - usleep_range(3000, 10000); - ret = lp5523_read(chip->client, LP5523_REG_STATUS, &status); - if (!(status & LP5523_LEDTEST_DONE)) - usleep_range(3000, 10000); - ret |= lp5523_read(chip->client, LP5523_REG_LED_TEST_ADC, &adc); - - if (adc >= vdd || adc < LP5523_ADC_SHORTCIRC_LIM) - pos += sprintf(buf + pos, "LED %d FAIL\n", i); - - lp5523_write(chip->client, LP5523_REG_LED_PWM_BASE + i, 0x00); - - /* Restore current */ - lp5523_write(chip->client, - LP5523_REG_LED_CURRENT_BASE + i, - chip->leds[led].led_current); - led++; - } - if (pos == 0) - pos = sprintf(buf, "OK\n"); - goto release_lock; -fail: - pos = sprintf(buf, "FAIL\n"); - -release_lock: - mutex_unlock(&chip->lock); - - return pos; -} - -static void lp5523_set_brightness(struct led_classdev *cdev, - enum led_brightness brightness) -{ - struct lp5523_led *led = cdev_to_led(cdev); - - led->brightness = (u8)brightness; - - schedule_work(&led->brightness_work); -} - -static void lp5523_led_brightness_work(struct work_struct *work) -{ - struct lp5523_led *led = container_of(work, - struct lp5523_led, - brightness_work); - struct lp5523_chip *chip = led_to_lp5523(led); - struct i2c_client *client = chip->client; - - mutex_lock(&chip->lock); - - lp5523_write(client, LP5523_REG_LED_PWM_BASE + led->chan_nr, - led->brightness); - - mutex_unlock(&chip->lock); -} - -static int lp5523_do_store_load(struct lp5523_engine *engine, - const char *buf, size_t len) -{ - struct lp5523_chip *chip = engine_to_lp5523(engine); - struct i2c_client *client = chip->client; - int ret, nrchars, offset = 0, i = 0; - char c[3]; - unsigned cmd; - u8 pattern[LP5523_PROGRAM_LENGTH] = {0}; - - while ((offset < len - 1) && (i < LP5523_PROGRAM_LENGTH)) { - /* separate sscanfs because length is working only for %s */ - ret = sscanf(buf + offset, "%2s%n ", c, &nrchars); - ret = sscanf(c, "%2x", &cmd); - if (ret != 1) - goto fail; - pattern[i] = (u8)cmd; - - offset += nrchars; - i++; - } - - /* Each instruction is 16bit long. Check that length is even */ - if (i % 2) - goto fail; - - mutex_lock(&chip->lock); - - ret = lp5523_load_program(engine, pattern); - mutex_unlock(&chip->lock); - - if (ret) { - dev_err(&client->dev, "failed loading pattern\n"); - return ret; - } - - return len; -fail: - dev_err(&client->dev, "wrong pattern format\n"); - return -EINVAL; -} - -static ssize_t store_engine_load(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lp5523_chip *chip = i2c_get_clientdata(client); - return lp5523_do_store_load(&chip->engines[nr - 1], buf, len); -} - -#define store_load(nr) \ -static ssize_t store_engine##nr##_load(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t len) \ -{ \ - return store_engine_load(dev, attr, buf, len, nr); \ -} -store_load(1) -store_load(2) -store_load(3) - -static ssize_t show_engine_mode(struct device *dev, - struct device_attribute *attr, - char *buf, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lp5523_chip *chip = i2c_get_clientdata(client); - switch (chip->engines[nr - 1].mode) { - case LP5523_CMD_RUN: - return sprintf(buf, "run\n"); - case LP5523_CMD_LOAD: - return sprintf(buf, "load\n"); - case LP5523_CMD_DISABLED: - return sprintf(buf, "disabled\n"); - default: - return sprintf(buf, "disabled\n"); - } -} - -#define show_mode(nr) \ -static ssize_t show_engine##nr##_mode(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return show_engine_mode(dev, attr, buf, nr); \ -} -show_mode(1) -show_mode(2) -show_mode(3) - -static ssize_t store_engine_mode(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len, int nr) -{ - struct i2c_client *client = to_i2c_client(dev); - struct lp5523_chip *chip = i2c_get_clientdata(client); - struct lp5523_engine *engine = &chip->engines[nr - 1]; - mutex_lock(&chip->lock); - - if (!strncmp(buf, "run", 3)) - lp5523_set_mode(engine, LP5523_CMD_RUN); - else if (!strncmp(buf, "load", 4)) - lp5523_set_mode(engine, LP5523_CMD_LOAD); - else if (!strncmp(buf, "disabled", 8)) - lp5523_set_mode(engine, LP5523_CMD_DISABLED); - - mutex_unlock(&chip->lock); - return len; -} - -#define store_mode(nr) \ -static ssize_t store_engine##nr##_mode(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t len) \ -{ \ - return store_engine_mode(dev, attr, buf, len, nr); \ -} -store_mode(1) -store_mode(2) -store_mode(3) - -static ssize_t show_max_current(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct lp5523_led *led = cdev_to_led(led_cdev); - - return sprintf(buf, "%d\n", led->max_current); -} - -static ssize_t show_current(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct lp5523_led *led = cdev_to_led(led_cdev); - - return sprintf(buf, "%d\n", led->led_current); -} - -static ssize_t store_current(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct led_classdev *led_cdev = dev_get_drvdata(dev); - struct lp5523_led *led = cdev_to_led(led_cdev); - struct lp5523_chip *chip = led_to_lp5523(led); - ssize_t ret; - unsigned long curr; - - if (strict_strtoul(buf, 0, &curr)) - return -EINVAL; - - if (curr > led->max_current) - return -EINVAL; - - mutex_lock(&chip->lock); - ret = lp5523_write(chip->client, - LP5523_REG_LED_CURRENT_BASE + led->chan_nr, - (u8)curr); - mutex_unlock(&chip->lock); - - if (ret < 0) - return ret; - - led->led_current = (u8)curr; - - return len; -} - -/* led class device attributes */ -static DEVICE_ATTR(led_current, S_IRUGO | S_IWUGO, show_current, store_current); -static DEVICE_ATTR(max_current, S_IRUGO , show_max_current, NULL); - -static struct attribute *lp5523_led_attributes[] = { - &dev_attr_led_current.attr, - &dev_attr_max_current.attr, - NULL, -}; - -static struct attribute_group lp5523_led_attribute_group = { - .attrs = lp5523_led_attributes -}; - -/* device attributes */ -static DEVICE_ATTR(engine1_mode, S_IRUGO | S_IWUGO, - show_engine1_mode, store_engine1_mode); -static DEVICE_ATTR(engine2_mode, S_IRUGO | S_IWUGO, - show_engine2_mode, store_engine2_mode); -static DEVICE_ATTR(engine3_mode, S_IRUGO | S_IWUGO, - show_engine3_mode, store_engine3_mode); -static DEVICE_ATTR(engine1_leds, S_IRUGO | S_IWUGO, - show_engine1_leds, store_engine1_leds); -static DEVICE_ATTR(engine2_leds, S_IRUGO | S_IWUGO, - show_engine2_leds, store_engine2_leds); -static DEVICE_ATTR(engine3_leds, S_IRUGO | S_IWUGO, - show_engine3_leds, store_engine3_leds); -static DEVICE_ATTR(engine1_load, S_IWUGO, NULL, store_engine1_load); -static DEVICE_ATTR(engine2_load, S_IWUGO, NULL, store_engine2_load); -static DEVICE_ATTR(engine3_load, S_IWUGO, NULL, store_engine3_load); -static DEVICE_ATTR(selftest, S_IRUGO, lp5523_selftest, NULL); - -static struct attribute *lp5523_attributes[] = { - &dev_attr_engine1_mode.attr, - &dev_attr_engine2_mode.attr, - &dev_attr_engine3_mode.attr, - &dev_attr_selftest.attr, - NULL -}; - -static struct attribute *lp5523_engine1_attributes[] = { - &dev_attr_engine1_load.attr, - &dev_attr_engine1_leds.attr, - NULL -}; - -static struct attribute *lp5523_engine2_attributes[] = { - &dev_attr_engine2_load.attr, - &dev_attr_engine2_leds.attr, - NULL -}; - -static struct attribute *lp5523_engine3_attributes[] = { - &dev_attr_engine3_load.attr, - &dev_attr_engine3_leds.attr, - NULL -}; - -static const struct attribute_group lp5523_group = { - .attrs = lp5523_attributes, -}; - -static const struct attribute_group lp5523_engine_group[] = { - {.attrs = lp5523_engine1_attributes }, - {.attrs = lp5523_engine2_attributes }, - {.attrs = lp5523_engine3_attributes }, -}; - -static int lp5523_register_sysfs(struct i2c_client *client) -{ - struct device *dev = &client->dev; - int ret; - - ret = sysfs_create_group(&dev->kobj, &lp5523_group); - if (ret < 0) - return ret; - - return 0; -} - -static void lp5523_unregister_sysfs(struct i2c_client *client) -{ - struct lp5523_chip *chip = i2c_get_clientdata(client); - struct device *dev = &client->dev; - int i; - - sysfs_remove_group(&dev->kobj, &lp5523_group); - - for (i = 0; i < ARRAY_SIZE(chip->engines); i++) - if (chip->engines[i].mode == LP5523_CMD_LOAD) - sysfs_remove_group(&dev->kobj, &lp5523_engine_group[i]); - - for (i = 0; i < chip->num_leds; i++) - sysfs_remove_group(&chip->leds[i].cdev.dev->kobj, - &lp5523_led_attribute_group); -} - -/*--------------------------------------------------------------*/ -/* Set chip operating mode */ -/*--------------------------------------------------------------*/ -static int lp5523_set_mode(struct lp5523_engine *engine, u8 mode) -{ - /* engine to chip */ - struct lp5523_chip *chip = engine_to_lp5523(engine); - struct i2c_client *client = chip->client; - struct device *dev = &client->dev; - int ret = 0; - - /* if in that mode already do nothing, except for run */ - if (mode == engine->mode && mode != LP5523_CMD_RUN) - return 0; - - if (mode == LP5523_CMD_RUN) { - ret = lp5523_run_program(engine); - } else if (mode == LP5523_CMD_LOAD) { - lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); - lp5523_set_engine_mode(engine, LP5523_CMD_LOAD); - - ret = sysfs_create_group(&dev->kobj, engine->attributes); - if (ret) - return ret; - } else if (mode == LP5523_CMD_DISABLED) { - lp5523_set_engine_mode(engine, LP5523_CMD_DISABLED); - } - - /* remove load attribute from sysfs if not in load mode */ - if (engine->mode == LP5523_CMD_LOAD && mode != LP5523_CMD_LOAD) - sysfs_remove_group(&dev->kobj, engine->attributes); - - engine->mode = mode; - - return ret; -} - -/*--------------------------------------------------------------*/ -/* Probe, Attach, Remove */ -/*--------------------------------------------------------------*/ -static int __init lp5523_init_engine(struct lp5523_engine *engine, int id) -{ - if (id < 1 || id > LP5523_ENGINES) - return -1; - engine->id = id; - engine->engine_mask = LP5523_ENG_MASK_BASE >> SHIFT_MASK(id); - engine->prog_page = id - 1; - engine->mux_page = id + 2; - engine->attributes = &lp5523_engine_group[id - 1]; - - return 0; -} - -static int __init lp5523_init_led(struct lp5523_led *led, struct device *dev, - int chan, struct lp5523_platform_data *pdata) -{ - char name[32]; - int res; - - if (chan >= LP5523_LEDS) - return -EINVAL; - - if (pdata->led_config[chan].led_current) { - led->led_current = pdata->led_config[chan].led_current; - led->max_current = pdata->led_config[chan].max_current; - led->chan_nr = pdata->led_config[chan].chan_nr; - - if (led->chan_nr >= LP5523_LEDS) { - dev_err(dev, "Use channel numbers between 0 and %d\n", - LP5523_LEDS - 1); - return -EINVAL; - } - - snprintf(name, 32, "lp5523:channel%d", chan); - - led->cdev.name = name; - led->cdev.brightness_set = lp5523_set_brightness; - res = led_classdev_register(dev, &led->cdev); - if (res < 0) { - dev_err(dev, "couldn't register led on channel %d\n", - chan); - return res; - } - res = sysfs_create_group(&led->cdev.dev->kobj, - &lp5523_led_attribute_group); - if (res < 0) { - dev_err(dev, "couldn't register current attribute\n"); - led_classdev_unregister(&led->cdev); - return res; - } - } else { - led->led_current = 0; - } - return 0; -} - -static struct i2c_driver lp5523_driver; - -static int lp5523_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct lp5523_chip *chip; - struct lp5523_platform_data *pdata; - int ret, i, led; - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - i2c_set_clientdata(client, chip); - chip->client = client; - - pdata = client->dev.platform_data; - - if (!pdata) { - dev_err(&client->dev, "no platform data\n"); - ret = -EINVAL; - goto fail1; - } - - mutex_init(&chip->lock); - - chip->pdata = pdata; - - if (pdata->setup_resources) { - ret = pdata->setup_resources(); - if (ret < 0) - goto fail1; - } - - if (pdata->enable) { - pdata->enable(0); - usleep_range(1000, 10000); - pdata->enable(1); - usleep_range(1000, 10000); /* Spec says min 500us */ - } - - ret = lp5523_detect(client); - if (ret) - goto fail2; - - dev_info(&client->dev, "LP5523 Programmable led chip found\n"); - - /* Initialize engines */ - for (i = 0; i < ARRAY_SIZE(chip->engines); i++) { - ret = lp5523_init_engine(&chip->engines[i], i + 1); - if (ret) { - dev_err(&client->dev, "error initializing engine\n"); - goto fail2; - } - } - ret = lp5523_configure(client); - if (ret < 0) { - dev_err(&client->dev, "error configuring chip\n"); - goto fail2; - } - - /* Initialize leds */ - chip->num_channels = pdata->num_channels; - chip->num_leds = 0; - led = 0; - for (i = 0; i < pdata->num_channels; i++) { - /* Do not initialize channels that are not connected */ - if (pdata->led_config[i].led_current == 0) - continue; - - ret = lp5523_init_led(&chip->leds[led], &client->dev, i, pdata); - if (ret) { - dev_err(&client->dev, "error initializing leds\n"); - goto fail3; - } - chip->num_leds++; - - chip->leds[led].id = led; - /* Set LED current */ - lp5523_write(client, - LP5523_REG_LED_CURRENT_BASE + chip->leds[led].chan_nr, - chip->leds[led].led_current); - - INIT_WORK(&(chip->leds[led].brightness_work), - lp5523_led_brightness_work); - - led++; - } - - ret = lp5523_register_sysfs(client); - if (ret) { - dev_err(&client->dev, "registering sysfs failed\n"); - goto fail3; - } - return ret; -fail3: - for (i = 0; i < chip->num_leds; i++) { - led_classdev_unregister(&chip->leds[i].cdev); - cancel_work_sync(&chip->leds[i].brightness_work); - } -fail2: - if (pdata->enable) - pdata->enable(0); - if (pdata->release_resources) - pdata->release_resources(); -fail1: - kfree(chip); - return ret; -} - -static int lp5523_remove(struct i2c_client *client) -{ - struct lp5523_chip *chip = i2c_get_clientdata(client); - int i; - - lp5523_unregister_sysfs(client); - - for (i = 0; i < chip->num_leds; i++) { - led_classdev_unregister(&chip->leds[i].cdev); - cancel_work_sync(&chip->leds[i].brightness_work); - } - - if (chip->pdata->enable) - chip->pdata->enable(0); - if (chip->pdata->release_resources) - chip->pdata->release_resources(); - kfree(chip); - return 0; -} - -static const struct i2c_device_id lp5523_id[] = { - { "lp5523", 0 }, - { } -}; - -MODULE_DEVICE_TABLE(i2c, lp5523_id); - -static struct i2c_driver lp5523_driver = { - .driver = { - .name = "lp5523", - }, - .probe = lp5523_probe, - .remove = lp5523_remove, - .id_table = lp5523_id, -}; - -static int __init lp5523_init(void) -{ - int ret; - - ret = i2c_add_driver(&lp5523_driver); - - if (ret < 0) - printk(KERN_ALERT "Adding lp5523 driver failed\n"); - - return ret; -} - -static void __exit lp5523_exit(void) -{ - i2c_del_driver(&lp5523_driver); -} - -module_init(lp5523_init); -module_exit(lp5523_exit); - -MODULE_AUTHOR("Mathias Nyman "); -MODULE_DESCRIPTION("LP5523 LED engine"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/leds/ledtrig-timer.c b/trunk/drivers/leds/ledtrig-timer.c index b09bcbeade9c..82b77bd482ff 100644 --- a/trunk/drivers/leds/ledtrig-timer.c +++ b/trunk/drivers/leds/ledtrig-timer.c @@ -12,25 +12,73 @@ */ #include +#include #include #include +#include +#include #include +#include +#include #include #include +#include #include "leds.h" +struct timer_trig_data { + int brightness_on; /* LED brightness during "on" period. + * (LED_OFF < brightness_on <= LED_FULL) + */ + unsigned long delay_on; /* milliseconds on */ + unsigned long delay_off; /* milliseconds off */ + struct timer_list timer; +}; + +static void led_timer_function(unsigned long data) +{ + struct led_classdev *led_cdev = (struct led_classdev *) data; + struct timer_trig_data *timer_data = led_cdev->trigger_data; + unsigned long brightness; + unsigned long delay; + + if (!timer_data->delay_on || !timer_data->delay_off) { + led_set_brightness(led_cdev, LED_OFF); + return; + } + + brightness = led_get_brightness(led_cdev); + if (!brightness) { + /* Time to switch the LED on. */ + brightness = timer_data->brightness_on; + delay = timer_data->delay_on; + } else { + /* Store the current brightness value to be able + * to restore it when the delay_off period is over. + */ + timer_data->brightness_on = brightness; + brightness = LED_OFF; + delay = timer_data->delay_off; + } + + led_set_brightness(led_cdev, brightness); + + mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay)); +} + static ssize_t led_delay_on_show(struct device *dev, struct device_attribute *attr, char *buf) { struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct timer_trig_data *timer_data = led_cdev->trigger_data; - return sprintf(buf, "%lu\n", led_cdev->blink_delay_on); + return sprintf(buf, "%lu\n", timer_data->delay_on); } static ssize_t led_delay_on_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct timer_trig_data *timer_data = led_cdev->trigger_data; int ret = -EINVAL; char *after; unsigned long state = simple_strtoul(buf, &after, 10); @@ -40,7 +88,21 @@ static ssize_t led_delay_on_store(struct device *dev, count++; if (count == size) { - led_blink_set(led_cdev, &state, &led_cdev->blink_delay_off); + if (timer_data->delay_on != state) { + /* the new value differs from the previous */ + timer_data->delay_on = state; + + /* deactivate previous settings */ + del_timer_sync(&timer_data->timer); + + /* try to activate hardware acceleration, if any */ + if (!led_cdev->blink_set || + led_cdev->blink_set(led_cdev, + &timer_data->delay_on, &timer_data->delay_off)) { + /* no hardware acceleration, blink via timer */ + mod_timer(&timer_data->timer, jiffies + 1); + } + } ret = count; } @@ -51,14 +113,16 @@ static ssize_t led_delay_off_show(struct device *dev, struct device_attribute *attr, char *buf) { struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct timer_trig_data *timer_data = led_cdev->trigger_data; - return sprintf(buf, "%lu\n", led_cdev->blink_delay_off); + return sprintf(buf, "%lu\n", timer_data->delay_off); } static ssize_t led_delay_off_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct timer_trig_data *timer_data = led_cdev->trigger_data; int ret = -EINVAL; char *after; unsigned long state = simple_strtoul(buf, &after, 10); @@ -68,7 +132,21 @@ static ssize_t led_delay_off_store(struct device *dev, count++; if (count == size) { - led_blink_set(led_cdev, &led_cdev->blink_delay_on, &state); + if (timer_data->delay_off != state) { + /* the new value differs from the previous */ + timer_data->delay_off = state; + + /* deactivate previous settings */ + del_timer_sync(&timer_data->timer); + + /* try to activate hardware acceleration, if any */ + if (!led_cdev->blink_set || + led_cdev->blink_set(led_cdev, + &timer_data->delay_on, &timer_data->delay_off)) { + /* no hardware acceleration, blink via timer */ + mod_timer(&timer_data->timer, jiffies + 1); + } + } ret = count; } @@ -80,34 +158,60 @@ static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store); static void timer_trig_activate(struct led_classdev *led_cdev) { + struct timer_trig_data *timer_data; int rc; - led_cdev->trigger_data = NULL; + timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL); + if (!timer_data) + return; + + timer_data->brightness_on = led_get_brightness(led_cdev); + if (timer_data->brightness_on == LED_OFF) + timer_data->brightness_on = led_cdev->max_brightness; + led_cdev->trigger_data = timer_data; + + init_timer(&timer_data->timer); + timer_data->timer.function = led_timer_function; + timer_data->timer.data = (unsigned long) led_cdev; rc = device_create_file(led_cdev->dev, &dev_attr_delay_on); if (rc) - return; + goto err_out; rc = device_create_file(led_cdev->dev, &dev_attr_delay_off); if (rc) goto err_out_delayon; - led_cdev->trigger_data = (void *)1; + /* If there is hardware support for blinking, start one + * user friendly blink rate chosen by the driver. + */ + if (led_cdev->blink_set) + led_cdev->blink_set(led_cdev, + &timer_data->delay_on, &timer_data->delay_off); return; err_out_delayon: device_remove_file(led_cdev->dev, &dev_attr_delay_on); +err_out: + led_cdev->trigger_data = NULL; + kfree(timer_data); } static void timer_trig_deactivate(struct led_classdev *led_cdev) { - if (led_cdev->trigger_data) { + struct timer_trig_data *timer_data = led_cdev->trigger_data; + unsigned long on = 0, off = 0; + + if (timer_data) { device_remove_file(led_cdev->dev, &dev_attr_delay_on); device_remove_file(led_cdev->dev, &dev_attr_delay_off); + del_timer_sync(&timer_data->timer); + kfree(timer_data); } - /* Stop blinking */ - led_brightness_set(led_cdev, LED_OFF); + /* If there is hardware support for blinking, stop it */ + if (led_cdev->blink_set) + led_cdev->blink_set(led_cdev, &on, &off); } static struct led_trigger timer_led_trigger = { diff --git a/trunk/drivers/macintosh/adb-iop.c b/trunk/drivers/macintosh/adb-iop.c index f5f4da3d0b67..444696625171 100644 --- a/trunk/drivers/macintosh/adb-iop.c +++ b/trunk/drivers/macintosh/adb-iop.c @@ -80,7 +80,7 @@ static void adb_iop_end_req(struct adb_request *req, int state) static void adb_iop_complete(struct iop_msg *msg) { struct adb_request *req; - unsigned long flags; + uint flags; local_irq_save(flags); @@ -103,7 +103,7 @@ static void adb_iop_listen(struct iop_msg *msg) { struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message; struct adb_request *req; - unsigned long flags; + uint flags; #ifdef DEBUG_ADB_IOP int i; #endif diff --git a/trunk/drivers/misc/apds9802als.c b/trunk/drivers/misc/apds9802als.c index 0ed09358027e..f9b91ba8900c 100644 --- a/trunk/drivers/misc/apds9802als.c +++ b/trunk/drivers/misc/apds9802als.c @@ -123,7 +123,7 @@ static ssize_t als_sensing_range_store(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct als_data *data = i2c_get_clientdata(client); - int ret_val; + unsigned int ret_val; unsigned long val; if (strict_strtoul(buf, 10, &val)) diff --git a/trunk/drivers/misc/bh1770glc.c b/trunk/drivers/misc/bh1770glc.c index d79a972f2c79..cee632e645e1 100644 --- a/trunk/drivers/misc/bh1770glc.c +++ b/trunk/drivers/misc/bh1770glc.c @@ -649,7 +649,7 @@ static ssize_t bh1770_power_state_store(struct device *dev, { struct bh1770_chip *chip = dev_get_drvdata(dev); unsigned long value; - ssize_t ret; + size_t ret; if (strict_strtoul(buf, 0, &value)) return -EINVAL; @@ -659,12 +659,8 @@ static ssize_t bh1770_power_state_store(struct device *dev, pm_runtime_get_sync(dev); ret = bh1770_lux_rate(chip, chip->lux_rate_index); - if (ret < 0) { - pm_runtime_put(dev); - goto leave; - } + ret |= bh1770_lux_interrupt_control(chip, BH1770_ENABLE); - ret = bh1770_lux_interrupt_control(chip, BH1770_ENABLE); if (ret < 0) { pm_runtime_put(dev); goto leave; diff --git a/trunk/drivers/misc/isl29020.c b/trunk/drivers/misc/isl29020.c index ca47e6285075..34fe835921c4 100644 --- a/trunk/drivers/misc/isl29020.c +++ b/trunk/drivers/misc/isl29020.c @@ -87,7 +87,7 @@ static ssize_t als_sensing_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); - int ret_val; + unsigned int ret_val; unsigned long val; if (strict_strtoul(buf, 10, &val)) @@ -106,8 +106,6 @@ static ssize_t als_sensing_range_store(struct device *dev, val = 4; ret_val = i2c_smbus_read_byte_data(client, 0x00); - if (ret_val < 0) - return ret_val; ret_val &= 0xFC; /*reset the bit before setting them */ ret_val |= val - 1; diff --git a/trunk/drivers/net/wireless/rt2x00/Kconfig b/trunk/drivers/net/wireless/rt2x00/Kconfig index 4396d4b9bfb9..eea1ef2f502b 100644 --- a/trunk/drivers/net/wireless/rt2x00/Kconfig +++ b/trunk/drivers/net/wireless/rt2x00/Kconfig @@ -221,6 +221,9 @@ config RT2X00_LIB_LEDS boolean default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n) +comment "rt2x00 leds support disabled due to modularized LEDS_CLASS and built-in rt2x00" + depends on RT2X00_LIB=y && LEDS_CLASS=m + config RT2X00_LIB_DEBUGFS bool "Ralink debugfs support" depends on RT2X00_LIB && MAC80211_DEBUGFS diff --git a/trunk/drivers/rapidio/rio.c b/trunk/drivers/rapidio/rio.c index 7b5080c45569..68cf0c99138a 100644 --- a/trunk/drivers/rapidio/rio.c +++ b/trunk/drivers/rapidio/rio.c @@ -1159,11 +1159,11 @@ int __devinit rio_init_mports(void) list_for_each_entry(port, &rio_mports, node) { if (!request_mem_region(port->iores.start, - resource_size(&port->iores), + port->iores.end - port->iores.start, port->name)) { printk(KERN_ERR "RIO: Error requesting master port region 0x%016llx-0x%016llx\n", - (u64)port->iores.start, (u64)port->iores.end); + (u64)port->iores.start, (u64)port->iores.end - 1); rc = -ENOMEM; goto out; } diff --git a/trunk/drivers/video/backlight/adp8860_bl.c b/trunk/drivers/video/backlight/adp8860_bl.c index 734c650a47c4..3ec24609151e 100644 --- a/trunk/drivers/video/backlight/adp8860_bl.c +++ b/trunk/drivers/video/backlight/adp8860_bl.c @@ -502,10 +502,8 @@ static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct adp8860_bl *data = dev_get_drvdata(dev); - int ret = strict_strtoul(buf, 10, &data->cached_daylight_max); - if (ret) - return ret; + strict_strtoul(buf, 10, &data->cached_daylight_max); return adp8860_store(dev, buf, count, ADP8860_BLMX1); } static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show, @@ -616,7 +614,7 @@ static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev, if (val == 0) { /* Enable automatic ambient light sensing */ adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); - } else if ((val > 0) && (val <= 3)) { + } else if ((val > 0) && (val < 6)) { /* Disable automatic ambient light sensing */ adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN); @@ -624,7 +622,7 @@ static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev, mutex_lock(&data->lock); adp8860_read(data->client, ADP8860_CFGR, ®_val); reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT); - reg_val |= (val - 1) << CFGR_BLV_SHIFT; + reg_val |= val << CFGR_BLV_SHIFT; adp8860_write(data->client, ADP8860_CFGR, reg_val); mutex_unlock(&data->lock); } diff --git a/trunk/drivers/video/backlight/l4f00242t03.c b/trunk/drivers/video/backlight/l4f00242t03.c index c67801e57aaf..9093ef0fa869 100644 --- a/trunk/drivers/video/backlight/l4f00242t03.c +++ b/trunk/drivers/video/backlight/l4f00242t03.c @@ -78,7 +78,7 @@ static int l4f00242t03_lcd_power_set(struct lcd_device *ld, int power) const u16 slpin = 0x10; const u16 disoff = 0x28; - if (power <= FB_BLANK_NORMAL) { + if (power) { if (priv->lcd_on) return 0; diff --git a/trunk/drivers/video/backlight/lms283gf05.c b/trunk/drivers/video/backlight/lms283gf05.c index 5d3cf33953ac..abc43a0eb97d 100644 --- a/trunk/drivers/video/backlight/lms283gf05.c +++ b/trunk/drivers/video/backlight/lms283gf05.c @@ -129,7 +129,7 @@ static int lms283gf05_power_set(struct lcd_device *ld, int power) struct spi_device *spi = st->spi; struct lms283gf05_pdata *pdata = spi->dev.platform_data; - if (power <= FB_BLANK_NORMAL) { + if (power) { if (pdata) lms283gf05_reset(pdata->reset_gpio, pdata->reset_inverted); diff --git a/trunk/drivers/video/backlight/mbp_nvidia_bl.c b/trunk/drivers/video/backlight/mbp_nvidia_bl.c index 1485f7345f49..9fb533f6373e 100644 --- a/trunk/drivers/video/backlight/mbp_nvidia_bl.c +++ b/trunk/drivers/video/backlight/mbp_nvidia_bl.c @@ -335,24 +335,6 @@ static const struct dmi_system_id __initdata mbp_device_table[] = { }, .driver_data = (void *)&nvidia_chipset_data, }, - { - .callback = mbp_dmi_match, - .ident = "MacBookAir 3,1", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,1"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, - { - .callback = mbp_dmi_match, - .ident = "MacBookAir 3,2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "MacBookAir3,2"), - }, - .driver_data = (void *)&nvidia_chipset_data, - }, { } }; diff --git a/trunk/drivers/video/backlight/pwm_bl.c b/trunk/drivers/video/backlight/pwm_bl.c index 21866ec69656..550443518891 100644 --- a/trunk/drivers/video/backlight/pwm_bl.c +++ b/trunk/drivers/video/backlight/pwm_bl.c @@ -25,7 +25,6 @@ struct pwm_bl_data { struct pwm_device *pwm; struct device *dev; unsigned int period; - unsigned int lth_brightness; int (*notify)(struct device *, int brightness); }; @@ -49,9 +48,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl) pwm_config(pb->pwm, 0, pb->period); pwm_disable(pb->pwm); } else { - brightness = pb->lth_brightness + - (brightness * (pb->period - pb->lth_brightness) / max); - pwm_config(pb->pwm, brightness, pb->period); + pwm_config(pb->pwm, brightness * pb->period / max, pb->period); pwm_enable(pb->pwm); } return 0; @@ -95,8 +92,6 @@ static int pwm_backlight_probe(struct platform_device *pdev) pb->period = data->pwm_period_ns; pb->notify = data->notify; - pb->lth_brightness = data->lth_brightness * - (data->pwm_period_ns / data->max_brightness); pb->dev = &pdev->dev; pb->pwm = pwm_request(data->pwm_id, "backlight"); diff --git a/trunk/drivers/video/backlight/s6e63m0.c b/trunk/drivers/video/backlight/s6e63m0.c index 5927db0da999..a3128c9cb7ad 100644 --- a/trunk/drivers/video/backlight/s6e63m0.c +++ b/trunk/drivers/video/backlight/s6e63m0.c @@ -729,10 +729,10 @@ static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev, return strlen(buf); } -static DEVICE_ATTR(gamma_table, 0444, +static DEVICE_ATTR(gamma_table, 0644, s6e63m0_sysfs_show_gamma_table, NULL); -static int __devinit s6e63m0_probe(struct spi_device *spi) +static int __init s6e63m0_probe(struct spi_device *spi) { int ret = 0; struct s6e63m0 *lcd = NULL; @@ -829,9 +829,6 @@ static int __devexit s6e63m0_remove(struct spi_device *spi) struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); s6e63m0_power(lcd, FB_BLANK_POWERDOWN); - device_remove_file(&spi->dev, &dev_attr_gamma_table); - device_remove_file(&spi->dev, &dev_attr_gamma_mode); - backlight_device_unregister(lcd->bd); lcd_device_unregister(lcd->ld); kfree(lcd); diff --git a/trunk/fs/hugetlbfs/inode.c b/trunk/fs/hugetlbfs/inode.c index a5fe68189eed..d6cfac1f0a40 100644 --- a/trunk/fs/hugetlbfs/inode.c +++ b/trunk/fs/hugetlbfs/inode.c @@ -932,7 +932,8 @@ struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag, if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) { *user = current_user(); if (user_shm_lock(size, *user)) { - printk_once(KERN_WARNING "Using mlock ulimits for SHM_HUGETLB is deprecated\n"); + WARN_ONCE(1, + "Using mlock ulimits for SHM_HUGETLB deprecated\n"); } else { *user = NULL; return ERR_PTR(-EPERM); diff --git a/trunk/fs/locks.c b/trunk/fs/locks.c index 0e62dd35d088..65765cb6afed 100644 --- a/trunk/fs/locks.c +++ b/trunk/fs/locks.c @@ -1504,8 +1504,9 @@ static int do_fcntl_delete_lease(struct file *filp) static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) { - struct file_lock *fl, *ret; + struct file_lock *fl; struct fasync_struct *new; + struct inode *inode = filp->f_path.dentry->d_inode; int error; fl = lease_alloc(filp, arg); @@ -1517,16 +1518,13 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) locks_free_lock(fl); return -ENOMEM; } - ret = fl; lock_flocks(); - error = __vfs_setlease(filp, arg, &ret); + error = __vfs_setlease(filp, arg, &fl); if (error) { unlock_flocks(); locks_free_lock(fl); goto out_free_fasync; } - if (ret != fl) - locks_free_lock(fl); /* * fasync_insert_entry() returns the old entry if any. @@ -1534,10 +1532,17 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg) * inserted it into the fasync list. Clear new so that * we don't release it here. */ - if (!fasync_insert_entry(fd, filp, &ret->fl_fasync, new)) + if (!fasync_insert_entry(fd, filp, &fl->fl_fasync, new)) new = NULL; - error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); + if (error < 0) { + /* remove lease just inserted by setlease */ + fl->fl_type = F_UNLCK | F_INPROGRESS; + fl->fl_break_time = jiffies - 10; + time_out_leases(inode); + } else { + error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); + } unlock_flocks(); out_free_fasync: diff --git a/trunk/fs/nfsd/nfs4state.c b/trunk/fs/nfsd/nfs4state.c index ad2bfa68d534..f1e5ec6b5105 100644 --- a/trunk/fs/nfsd/nfs4state.c +++ b/trunk/fs/nfsd/nfs4state.c @@ -673,17 +673,16 @@ static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) spin_unlock(&clp->cl_lock); } -static int nfsd4_register_conn(struct nfsd4_conn *conn) +static void nfsd4_register_conn(struct nfsd4_conn *conn) { conn->cn_xpt_user.callback = nfsd4_conn_lost; - return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); + register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); } static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) { struct nfsd4_conn *conn; u32 flags = NFS4_CDFC4_FORE; - int ret; if (ses->se_flags & SESSION4_BACK_CHAN) flags |= NFS4_CDFC4_BACK; @@ -691,10 +690,7 @@ static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses) if (!conn) return nfserr_jukebox; nfsd4_hash_conn(conn, ses); - ret = nfsd4_register_conn(conn); - if (ret) - /* oops; xprt is already down: */ - nfsd4_conn_lost(&conn->cn_xpt_user); + nfsd4_register_conn(conn); return nfs_ok; } @@ -1648,7 +1644,6 @@ static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_sessi { struct nfs4_client *clp = ses->se_client; struct nfsd4_conn *c; - int ret; spin_lock(&clp->cl_lock); c = __nfsd4_find_conn(new->cn_xprt, ses); @@ -1659,10 +1654,7 @@ static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_sessi } __nfsd4_hash_conn(new, ses); spin_unlock(&clp->cl_lock); - ret = nfsd4_register_conn(new); - if (ret) - /* oops; xprt is already down: */ - nfsd4_conn_lost(&new->cn_xpt_user); + nfsd4_register_conn(new); return; } diff --git a/trunk/fs/xfs/linux-2.6/xfs_super.c b/trunk/fs/xfs/linux-2.6/xfs_super.c index 9f3a78fe6ae4..064f964d4f3c 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_super.c +++ b/trunk/fs/xfs/linux-2.6/xfs_super.c @@ -353,9 +353,6 @@ xfs_parseargs( mp->m_qflags &= ~XFS_OQUOTA_ENFD; } else if (!strcmp(this_char, MNTOPT_DELAYLOG)) { mp->m_flags |= XFS_MOUNT_DELAYLOG; - cmn_err(CE_WARN, - "Enabling EXPERIMENTAL delayed logging feature " - "- use at your own risk.\n"); } else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) { mp->m_flags &= ~XFS_MOUNT_DELAYLOG; } else if (!strcmp(this_char, "ihashsize")) { diff --git a/trunk/include/linux/atomic.h b/trunk/include/linux/atomic.h deleted file mode 100644 index 96c038e43d66..000000000000 --- a/trunk/include/linux/atomic.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _LINUX_ATOMIC_H -#define _LINUX_ATOMIC_H -#include - -/** - * atomic_inc_not_zero_hint - increment if not null - * @v: pointer of type atomic_t - * @hint: probable value of the atomic before the increment - * - * This version of atomic_inc_not_zero() gives a hint of probable - * value of the atomic. This helps processor to not read the memory - * before doing the atomic read/modify/write cycle, lowering - * number of bus transactions on some arches. - * - * Returns: 0 if increment was not done, 1 otherwise. - */ -#ifndef atomic_inc_not_zero_hint -static inline int atomic_inc_not_zero_hint(atomic_t *v, int hint) -{ - int val, c = hint; - - /* sanity test, should be removed by compiler if hint is a constant */ - if (!hint) - return atomic_inc_not_zero(v); - - do { - val = atomic_cmpxchg(v, c, c + 1); - if (val == c) - return 1; - c = val; - } while (c); - - return 0; -} -#endif - -#endif /* _LINUX_ATOMIC_H */ diff --git a/trunk/include/linux/highmem.h b/trunk/include/linux/highmem.h index b676c585574e..e9138198e823 100644 --- a/trunk/include/linux/highmem.h +++ b/trunk/include/linux/highmem.h @@ -5,7 +5,6 @@ #include #include #include -#include #include diff --git a/trunk/include/linux/kernel.h b/trunk/include/linux/kernel.h index fc3da9e4da19..b526947bdf48 100644 --- a/trunk/include/linux/kernel.h +++ b/trunk/include/linux/kernel.h @@ -293,7 +293,6 @@ extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, unsigned int interval_msec); extern int printk_delay_msec; -extern int dmesg_restrict; /* * Print a one-time message (analogous to WARN_ONCE() et al): diff --git a/trunk/include/linux/leds-lp5521.h b/trunk/include/linux/leds-lp5521.h deleted file mode 100644 index 38368d785f08..000000000000 --- a/trunk/include/linux/leds-lp5521.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * LP5521 LED chip driver. - * - * Copyright (C) 2010 Nokia Corporation - * - * Contact: Samu Onkalo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef __LINUX_LP5521_H -#define __LINUX_LP5521_H - -/* See Documentation/leds/leds-lp5521.txt */ - -struct lp5521_led_config { - u8 chan_nr; - u8 led_current; /* mA x10, 0 if led is not connected */ - u8 max_current; -}; - -#define LP5521_CLOCK_AUTO 0 -#define LP5521_CLOCK_INT 1 -#define LP5521_CLOCK_EXT 2 - -struct lp5521_platform_data { - struct lp5521_led_config *led_config; - u8 num_channels; - u8 clock_mode; - int (*setup_resources)(void); - void (*release_resources)(void); - void (*enable)(bool state); -}; - -#endif /* __LINUX_LP5521_H */ diff --git a/trunk/include/linux/leds-lp5523.h b/trunk/include/linux/leds-lp5523.h deleted file mode 100644 index 796747637b80..000000000000 --- a/trunk/include/linux/leds-lp5523.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * LP5523 LED Driver - * - * Copyright (C) 2010 Nokia Corporation - * - * Contact: Samu Onkalo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#ifndef __LINUX_LP5523_H -#define __LINUX_LP5523_H - -/* See Documentation/leds/leds-lp5523.txt */ - -struct lp5523_led_config { - u8 chan_nr; - u8 led_current; /* mA x10, 0 if led is not connected */ - u8 max_current; -}; - -#define LP5523_CLOCK_AUTO 0 -#define LP5523_CLOCK_INT 1 -#define LP5523_CLOCK_EXT 2 - -struct lp5523_platform_data { - struct lp5523_led_config *led_config; - u8 num_channels; - u8 clock_mode; - int (*setup_resources)(void); - void (*release_resources)(void); - void (*enable)(bool state); -}; - -#endif /* __LINUX_LP5523_H */ diff --git a/trunk/include/linux/leds.h b/trunk/include/linux/leds.h index 0f19df9e37b0..ba6986a11663 100644 --- a/trunk/include/linux/leds.h +++ b/trunk/include/linux/leds.h @@ -15,7 +15,6 @@ #include #include #include -#include struct device; /* @@ -46,14 +45,10 @@ struct led_classdev { /* Get LED brightness level */ enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); - /* - * Activate hardware accelerated blink, delays are in milliseconds - * and if both are zero then a sensible default should be chosen. - * The call should adjust the timings in that case and if it can't - * match the values specified exactly. - * Deactivate blinking again when the brightness is set to a fixed - * value via the brightness_set() callback. - */ + /* Activate hardware accelerated blink, delays are in + * miliseconds and if none is provided then a sensible default + * should be chosen. The call can adjust the timings if it can't + * match the values specified exactly. */ int (*blink_set)(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off); @@ -62,10 +57,6 @@ struct led_classdev { struct list_head node; /* LED Device list */ const char *default_trigger; /* Trigger to use */ - unsigned long blink_delay_on, blink_delay_off; - struct timer_list blink_timer; - int blink_brightness; - #ifdef CONFIG_LEDS_TRIGGERS /* Protects the trigger data below */ struct rw_semaphore trigger_lock; @@ -82,36 +73,6 @@ extern void led_classdev_unregister(struct led_classdev *led_cdev); extern void led_classdev_suspend(struct led_classdev *led_cdev); extern void led_classdev_resume(struct led_classdev *led_cdev); -/** - * led_blink_set - set blinking with software fallback - * @led_cdev: the LED to start blinking - * @delay_on: the time it should be on (in ms) - * @delay_off: the time it should ble off (in ms) - * - * This function makes the LED blink, attempting to use the - * hardware acceleration if possible, but falling back to - * software blinking if there is no hardware blinking or if - * the LED refuses the passed values. - * - * Note that if software blinking is active, simply calling - * led_cdev->brightness_set() will not stop the blinking, - * use led_classdev_brightness_set() instead. - */ -extern void led_blink_set(struct led_classdev *led_cdev, - unsigned long *delay_on, - unsigned long *delay_off); -/** - * led_brightness_set - set LED brightness - * @led_cdev: the LED to set - * @brightness: the brightness to set it to - * - * Set an LED's brightness, and, if necessary, cancel the - * software blink timer that implements blinking when the - * hardware doesn't. - */ -extern void led_brightness_set(struct led_classdev *led_cdev, - enum led_brightness brightness); - /* * LED Triggers */ diff --git a/trunk/include/linux/pwm_backlight.h b/trunk/include/linux/pwm_backlight.h index e031e1a486d9..01b3d759f1fc 100644 --- a/trunk/include/linux/pwm_backlight.h +++ b/trunk/include/linux/pwm_backlight.h @@ -8,7 +8,6 @@ struct platform_pwm_backlight_data { int pwm_id; unsigned int max_brightness; unsigned int dft_brightness; - unsigned int lth_brightness; unsigned int pwm_period_ns; int (*init)(struct device *dev); int (*notify)(struct device *dev, int brightness); diff --git a/trunk/include/linux/radix-tree.h b/trunk/include/linux/radix-tree.h index ab2baa5c4884..a39cbed9ee17 100644 --- a/trunk/include/linux/radix-tree.h +++ b/trunk/include/linux/radix-tree.h @@ -34,13 +34,19 @@ * needed for RCU lookups (because root->height is unreliable). The only * time callers need worry about this is when doing a lookup_slot under * RCU. - * - * Indirect pointer in fact is also used to tag the last pointer of a node - * when it is shrunk, before we rcu free the node. See shrink code for - * details. */ #define RADIX_TREE_INDIRECT_PTR 1 +#define RADIX_TREE_RETRY ((void *)-1UL) + +static inline void *radix_tree_ptr_to_indirect(void *ptr) +{ + return (void *)((unsigned long)ptr | RADIX_TREE_INDIRECT_PTR); +} +static inline void *radix_tree_indirect_to_ptr(void *ptr) +{ + return (void *)((unsigned long)ptr & ~RADIX_TREE_INDIRECT_PTR); +} #define radix_tree_indirect_to_ptr(ptr) \ radix_tree_indirect_to_ptr((void __force *)(ptr)) @@ -134,29 +140,16 @@ do { \ * removed. * * For use with radix_tree_lookup_slot(). Caller must hold tree at least read - * locked across slot lookup and dereference. Not required if write lock is - * held (ie. items cannot be concurrently inserted). - * - * radix_tree_deref_retry must be used to confirm validity of the pointer if - * only the read lock is held. + * locked across slot lookup and dereference. More likely, will be used with + * radix_tree_replace_slot(), as well, so caller will hold tree write locked. */ static inline void *radix_tree_deref_slot(void **pslot) { - return rcu_dereference(*pslot); + void *ret = rcu_dereference(*pslot); + if (unlikely(radix_tree_is_indirect_ptr(ret))) + ret = RADIX_TREE_RETRY; + return ret; } - -/** - * radix_tree_deref_retry - check radix_tree_deref_slot - * @arg: pointer returned by radix_tree_deref_slot - * Returns: 0 if retry is not required, otherwise retry is required - * - * radix_tree_deref_retry must be used with radix_tree_deref_slot. - */ -static inline int radix_tree_deref_retry(void *arg) -{ - return unlikely((unsigned long)arg & RADIX_TREE_INDIRECT_PTR); -} - /** * radix_tree_replace_slot - replace item in a slot * @pslot: pointer to slot, returned by radix_tree_lookup_slot diff --git a/trunk/include/linux/resource.h b/trunk/include/linux/resource.h index d01c96c1966e..88d36f9145ba 100644 --- a/trunk/include/linux/resource.h +++ b/trunk/include/linux/resource.h @@ -2,7 +2,6 @@ #define _LINUX_RESOURCE_H #include -#include /* * Resource control/accounting header file for linux diff --git a/trunk/include/linux/sunrpc/svc_xprt.h b/trunk/include/linux/sunrpc/svc_xprt.h index aea0d438e3c7..bbdb680ffbe9 100644 --- a/trunk/include/linux/sunrpc/svc_xprt.h +++ b/trunk/include/linux/sunrpc/svc_xprt.h @@ -82,28 +82,18 @@ struct svc_xprt { struct net *xpt_net; }; -static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) +static inline void register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) { spin_lock(&xpt->xpt_lock); - list_del_init(&u->list); + list_add(&u->list, &xpt->xpt_users); spin_unlock(&xpt->xpt_lock); } -static inline int register_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) +static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u) { spin_lock(&xpt->xpt_lock); - if (test_bit(XPT_CLOSE, &xpt->xpt_flags)) { - /* - * The connection is about to be deleted soon (or, - * worse, may already be deleted--in which case we've - * already notified the xpt_users). - */ - spin_unlock(&xpt->xpt_lock); - return -ENOTCONN; - } - list_add(&u->list, &xpt->xpt_users); + list_del_init(&u->list); spin_unlock(&xpt->xpt_lock); - return 0; } int svc_reg_xprt_class(struct svc_xprt_class *); diff --git a/trunk/kernel/latencytop.c b/trunk/kernel/latencytop.c index 17110a4a4fc2..877fb306d415 100644 --- a/trunk/kernel/latencytop.c +++ b/trunk/kernel/latencytop.c @@ -194,7 +194,14 @@ __account_scheduler_latency(struct task_struct *tsk, int usecs, int inter) account_global_scheduler_latency(tsk, &lat); - for (i = 0; i < tsk->latency_record_count; i++) { + /* + * short term hack; if we're > 32 we stop; future we recycle: + */ + tsk->latency_record_count++; + if (tsk->latency_record_count >= LT_SAVECOUNT) + goto out_unlock; + + for (i = 0; i < LT_SAVECOUNT; i++) { struct latency_record *mylat; int same = 1; @@ -220,14 +227,8 @@ __account_scheduler_latency(struct task_struct *tsk, int usecs, int inter) } } - /* - * short term hack; if we're > 32 we stop; future we recycle: - */ - if (tsk->latency_record_count >= LT_SAVECOUNT) - goto out_unlock; - /* Allocated a new one: */ - i = tsk->latency_record_count++; + i = tsk->latency_record_count; memcpy(&tsk->latency_record[i], &lat, sizeof(struct latency_record)); out_unlock: diff --git a/trunk/kernel/printk.c b/trunk/kernel/printk.c index 38e7d5868d60..b2ebaee8c377 100644 --- a/trunk/kernel/printk.c +++ b/trunk/kernel/printk.c @@ -261,12 +261,6 @@ static inline void boot_delay_msec(void) } #endif -#ifdef CONFIG_SECURITY_DMESG_RESTRICT -int dmesg_restrict = 1; -#else -int dmesg_restrict; -#endif - int do_syslog(int type, char __user *buf, int len, bool from_file) { unsigned i, j, limit, count; diff --git a/trunk/kernel/range.c b/trunk/kernel/range.c index 37fa9b99ad58..471b66acabb5 100644 --- a/trunk/kernel/range.c +++ b/trunk/kernel/range.c @@ -119,7 +119,7 @@ static int cmp_range(const void *x1, const void *x2) int clean_sort_range(struct range *range, int az) { - int i, j, k = az - 1, nr_range = az; + int i, j, k = az - 1, nr_range = 0; for (i = 0; i < k; i++) { if (range[i].end) diff --git a/trunk/kernel/sysctl.c b/trunk/kernel/sysctl.c index b65bf634035e..c33a1edb799f 100644 --- a/trunk/kernel/sysctl.c +++ b/trunk/kernel/sysctl.c @@ -703,15 +703,6 @@ static struct ctl_table kern_table[] = { .extra2 = &ten_thousand, }, #endif - { - .procname = "dmesg_restrict", - .data = &dmesg_restrict, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, { .procname = "ngroups_max", .data = &ngroups_max, diff --git a/trunk/lib/radix-tree.c b/trunk/lib/radix-tree.c index 5086bb962b4d..6f412ab4c24f 100644 --- a/trunk/lib/radix-tree.c +++ b/trunk/lib/radix-tree.c @@ -82,16 +82,6 @@ struct radix_tree_preload { }; static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; -static inline void *ptr_to_indirect(void *ptr) -{ - return (void *)((unsigned long)ptr | RADIX_TREE_INDIRECT_PTR); -} - -static inline void *indirect_to_ptr(void *ptr) -{ - return (void *)((unsigned long)ptr & ~RADIX_TREE_INDIRECT_PTR); -} - static inline gfp_t root_gfp_mask(struct radix_tree_root *root) { return root->gfp_mask & __GFP_BITS_MASK; @@ -275,7 +265,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) return -ENOMEM; /* Increase the height. */ - node->slots[0] = indirect_to_ptr(root->rnode); + node->slots[0] = radix_tree_indirect_to_ptr(root->rnode); /* Propagate the aggregated tag info into the new root */ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { @@ -286,7 +276,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) newheight = root->height+1; node->height = newheight; node->count = 1; - node = ptr_to_indirect(node); + node = radix_tree_ptr_to_indirect(node); rcu_assign_pointer(root->rnode, node); root->height = newheight; } while (height > root->height); @@ -319,7 +309,7 @@ int radix_tree_insert(struct radix_tree_root *root, return error; } - slot = indirect_to_ptr(root->rnode); + slot = radix_tree_indirect_to_ptr(root->rnode); height = root->height; shift = (height-1) * RADIX_TREE_MAP_SHIFT; @@ -335,7 +325,8 @@ int radix_tree_insert(struct radix_tree_root *root, rcu_assign_pointer(node->slots[offset], slot); node->count++; } else - rcu_assign_pointer(root->rnode, ptr_to_indirect(slot)); + rcu_assign_pointer(root->rnode, + radix_tree_ptr_to_indirect(slot)); } /* Go a level down */ @@ -383,7 +374,7 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root, return NULL; return is_slot ? (void *)&root->rnode : node; } - node = indirect_to_ptr(node); + node = radix_tree_indirect_to_ptr(node); height = node->height; if (index > radix_tree_maxindex(height)) @@ -402,7 +393,7 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root, height--; } while (height > 0); - return is_slot ? (void *)slot : indirect_to_ptr(node); + return is_slot ? (void *)slot:node; } /** @@ -464,7 +455,7 @@ void *radix_tree_tag_set(struct radix_tree_root *root, height = root->height; BUG_ON(index > radix_tree_maxindex(height)); - slot = indirect_to_ptr(root->rnode); + slot = radix_tree_indirect_to_ptr(root->rnode); shift = (height - 1) * RADIX_TREE_MAP_SHIFT; while (height > 0) { @@ -518,7 +509,7 @@ void *radix_tree_tag_clear(struct radix_tree_root *root, shift = (height - 1) * RADIX_TREE_MAP_SHIFT; pathp->node = NULL; - slot = indirect_to_ptr(root->rnode); + slot = radix_tree_indirect_to_ptr(root->rnode); while (height > 0) { int offset; @@ -588,7 +579,7 @@ int radix_tree_tag_get(struct radix_tree_root *root, if (!radix_tree_is_indirect_ptr(node)) return (index == 0); - node = indirect_to_ptr(node); + node = radix_tree_indirect_to_ptr(node); height = node->height; if (index > radix_tree_maxindex(height)) @@ -675,7 +666,7 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, } shift = (height - 1) * RADIX_TREE_MAP_SHIFT; - slot = indirect_to_ptr(root->rnode); + slot = radix_tree_indirect_to_ptr(root->rnode); /* * we fill the path from (root->height - 2) to 0, leaving the index at @@ -906,7 +897,7 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results, results[0] = node; return 1; } - node = indirect_to_ptr(node); + node = radix_tree_indirect_to_ptr(node); max_index = radix_tree_maxindex(node->height); @@ -925,8 +916,7 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results, slot = *(((void ***)results)[ret + i]); if (!slot) continue; - results[ret + nr_found] = - indirect_to_ptr(rcu_dereference_raw(slot)); + results[ret + nr_found] = rcu_dereference_raw(slot); nr_found++; } ret += nr_found; @@ -975,7 +965,7 @@ radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results, results[0] = (void **)&root->rnode; return 1; } - node = indirect_to_ptr(node); + node = radix_tree_indirect_to_ptr(node); max_index = radix_tree_maxindex(node->height); @@ -1100,7 +1090,7 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, results[0] = node; return 1; } - node = indirect_to_ptr(node); + node = radix_tree_indirect_to_ptr(node); max_index = radix_tree_maxindex(node->height); @@ -1119,8 +1109,7 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, slot = *(((void ***)results)[ret + i]); if (!slot) continue; - results[ret + nr_found] = - indirect_to_ptr(rcu_dereference_raw(slot)); + results[ret + nr_found] = rcu_dereference_raw(slot); nr_found++; } ret += nr_found; @@ -1170,7 +1159,7 @@ radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results, results[0] = (void **)&root->rnode; return 1; } - node = indirect_to_ptr(node); + node = radix_tree_indirect_to_ptr(node); max_index = radix_tree_maxindex(node->height); @@ -1206,7 +1195,7 @@ static inline void radix_tree_shrink(struct radix_tree_root *root) void *newptr; BUG_ON(!radix_tree_is_indirect_ptr(to_free)); - to_free = indirect_to_ptr(to_free); + to_free = radix_tree_indirect_to_ptr(to_free); /* * The candidate node has more than one child, or its child @@ -1219,39 +1208,16 @@ static inline void radix_tree_shrink(struct radix_tree_root *root) /* * We don't need rcu_assign_pointer(), since we are simply - * moving the node from one part of the tree to another: if it - * was safe to dereference the old pointer to it + * moving the node from one part of the tree to another. If + * it was safe to dereference the old pointer to it * (to_free->slots[0]), it will be safe to dereference the new - * one (root->rnode) as far as dependent read barriers go. + * one (root->rnode). */ newptr = to_free->slots[0]; if (root->height > 1) - newptr = ptr_to_indirect(newptr); + newptr = radix_tree_ptr_to_indirect(newptr); root->rnode = newptr; root->height--; - - /* - * We have a dilemma here. The node's slot[0] must not be - * NULLed in case there are concurrent lookups expecting to - * find the item. However if this was a bottom-level node, - * then it may be subject to the slot pointer being visible - * to callers dereferencing it. If item corresponding to - * slot[0] is subsequently deleted, these callers would expect - * their slot to become empty sooner or later. - * - * For example, lockless pagecache will look up a slot, deref - * the page pointer, and if the page is 0 refcount it means it - * was concurrently deleted from pagecache so try the deref - * again. Fortunately there is already a requirement for logic - * to retry the entire slot lookup -- the indirect pointer - * problem (replacing direct root node with an indirect pointer - * also results in a stale slot). So tag the slot as indirect - * to force callers to retry. - */ - if (root->height == 0) - *((unsigned long *)&to_free->slots[0]) |= - RADIX_TREE_INDIRECT_PTR; - radix_tree_node_free(to_free); } } @@ -1288,7 +1254,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) root->rnode = NULL; goto out; } - slot = indirect_to_ptr(slot); + slot = radix_tree_indirect_to_ptr(slot); shift = (height - 1) * RADIX_TREE_MAP_SHIFT; pathp->node = NULL; @@ -1330,7 +1296,8 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) radix_tree_node_free(to_free); if (pathp->node->count) { - if (pathp->node == indirect_to_ptr(root->rnode)) + if (pathp->node == + radix_tree_indirect_to_ptr(root->rnode)) radix_tree_shrink(root); goto out; } diff --git a/trunk/mm/filemap.c b/trunk/mm/filemap.c index ea89840fc65f..61ba5e405791 100644 --- a/trunk/mm/filemap.c +++ b/trunk/mm/filemap.c @@ -644,9 +644,7 @@ struct page *find_get_page(struct address_space *mapping, pgoff_t offset) pagep = radix_tree_lookup_slot(&mapping->page_tree, offset); if (pagep) { page = radix_tree_deref_slot(pagep); - if (unlikely(!page)) - goto out; - if (radix_tree_deref_retry(page)) + if (unlikely(!page || page == RADIX_TREE_RETRY)) goto repeat; if (!page_cache_get_speculative(page)) @@ -662,7 +660,6 @@ struct page *find_get_page(struct address_space *mapping, pgoff_t offset) goto repeat; } } -out: rcu_read_unlock(); return page; @@ -780,11 +777,12 @@ unsigned find_get_pages(struct address_space *mapping, pgoff_t start, page = radix_tree_deref_slot((void **)pages[i]); if (unlikely(!page)) continue; - if (radix_tree_deref_retry(page)) { - if (ret) - start = pages[ret-1]->index; + /* + * this can only trigger if nr_found == 1, making livelock + * a non issue. + */ + if (unlikely(page == RADIX_TREE_RETRY)) goto restart; - } if (!page_cache_get_speculative(page)) goto repeat; @@ -832,7 +830,11 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index, page = radix_tree_deref_slot((void **)pages[i]); if (unlikely(!page)) continue; - if (radix_tree_deref_retry(page)) + /* + * this can only trigger if nr_found == 1, making livelock + * a non issue. + */ + if (unlikely(page == RADIX_TREE_RETRY)) goto restart; if (page->mapping == NULL || page->index != index) @@ -885,7 +887,11 @@ unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index, page = radix_tree_deref_slot((void **)pages[i]); if (unlikely(!page)) continue; - if (radix_tree_deref_retry(page)) + /* + * this can only trigger if nr_found == 1, making livelock + * a non issue. + */ + if (unlikely(page == RADIX_TREE_RETRY)) goto restart; if (!page_cache_get_speculative(page)) @@ -1023,9 +1029,6 @@ static void do_generic_file_read(struct file *filp, loff_t *ppos, goto page_not_up_to_date; if (!trylock_page(page)) goto page_not_up_to_date; - /* Did it get truncated before we got the lock? */ - if (!page->mapping) - goto page_not_up_to_date_locked; if (!mapping->a_ops->is_partially_uptodate(page, desc, offset)) goto page_not_up_to_date_locked; diff --git a/trunk/mm/memcontrol.c b/trunk/mm/memcontrol.c index 2efa8ea07ff7..9a99cfaf0a19 100644 --- a/trunk/mm/memcontrol.c +++ b/trunk/mm/memcontrol.c @@ -4208,17 +4208,15 @@ static struct mem_cgroup *mem_cgroup_alloc(void) memset(mem, 0, size); mem->stat = alloc_percpu(struct mem_cgroup_stat_cpu); - if (!mem->stat) - goto out_free; + if (!mem->stat) { + if (size < PAGE_SIZE) + kfree(mem); + else + vfree(mem); + mem = NULL; + } spin_lock_init(&mem->pcp_counter_lock); return mem; - -out_free: - if (size < PAGE_SIZE) - kfree(mem); - else - vfree(mem); - return NULL; } /* diff --git a/trunk/mm/vmscan.c b/trunk/mm/vmscan.c index d31d7ce52c0e..b8a6fdc21312 100644 --- a/trunk/mm/vmscan.c +++ b/trunk/mm/vmscan.c @@ -913,7 +913,7 @@ static unsigned long shrink_page_list(struct list_head *page_list, * back off and wait for congestion to clear because further reclaim * will encounter the same problem */ - if (nr_dirty == nr_congested && nr_dirty != 0) + if (nr_dirty == nr_congested) zone_set_flag(zone, ZONE_CONGESTED); free_page_list(&free_pages); diff --git a/trunk/security/Kconfig b/trunk/security/Kconfig index e80da955e687..bd72ae623494 100644 --- a/trunk/security/Kconfig +++ b/trunk/security/Kconfig @@ -39,18 +39,6 @@ config KEYS_DEBUG_PROC_KEYS If you are unsure as to whether this is required, answer N. -config SECURITY_DMESG_RESTRICT - bool "Restrict unprivileged access to the kernel syslog" - default n - help - This enforces restrictions on unprivileged users reading the kernel - syslog via dmesg(8). - - If this option is not selected, no restrictions will be enforced - unless the dmesg_restrict sysctl is explicitly set to (1). - - If you are unsure how to answer this question, answer N. - config SECURITY bool "Enable different security models" depends on SYSFS diff --git a/trunk/security/apparmor/lsm.c b/trunk/security/apparmor/lsm.c index b7106f192b75..cf1de4462ccd 100644 --- a/trunk/security/apparmor/lsm.c +++ b/trunk/security/apparmor/lsm.c @@ -922,7 +922,7 @@ static int __init apparmor_init(void) error = register_security(&apparmor_ops); if (error) { AA_ERROR("Unable to register AppArmor\n"); - goto set_init_cxt_out; + goto register_security_out; } /* Report that AppArmor successfully initialized */ @@ -936,9 +936,6 @@ static int __init apparmor_init(void) return error; -set_init_cxt_out: - aa_free_task_context(current->real_cred->security); - register_security_out: aa_free_root_ns(); @@ -947,6 +944,7 @@ static int __init apparmor_init(void) apparmor_enabled = 0; return error; + } security_initcall(apparmor_init); diff --git a/trunk/security/apparmor/policy.c b/trunk/security/apparmor/policy.c index 4f0eadee78b8..52cc865f1464 100644 --- a/trunk/security/apparmor/policy.c +++ b/trunk/security/apparmor/policy.c @@ -306,7 +306,7 @@ static struct aa_namespace *alloc_namespace(const char *prefix, return ns; fail_unconfined: - kzfree(ns->base.hname); + kzfree(ns->base.name); fail_ns: kzfree(ns); return NULL; diff --git a/trunk/security/commoncap.c b/trunk/security/commoncap.c index 04b80f9912bf..5e632b4857e4 100644 --- a/trunk/security/commoncap.c +++ b/trunk/security/commoncap.c @@ -895,8 +895,6 @@ int cap_syslog(int type, bool from_file) { if (type != SYSLOG_ACTION_OPEN && from_file) return 0; - if (dmesg_restrict && !capable(CAP_SYS_ADMIN)) - return -EPERM; if ((type != SYSLOG_ACTION_READ_ALL && type != SYSLOG_ACTION_SIZE_BUFFER) && !capable(CAP_SYS_ADMIN)) return -EPERM;