diff --git a/[refs] b/[refs] index 17d2810b2be4..3b2ca679bb6e 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 69e372896791c2e43949b32d4cbe8a714961d3d7 +refs/heads/master: 229fd8ffba57dfaea59078b9144371369ffdb0a3 diff --git a/trunk/arch/arm/mach-s3c2410/mach-bast.c b/trunk/arch/arm/mach-s3c2410/mach-bast.c index 06670bb89cab..ce3baba2cd7f 100644 --- a/trunk/arch/arm/mach-s3c2410/mach-bast.c +++ b/trunk/arch/arm/mach-s3c2410/mach-bast.c @@ -45,7 +45,6 @@ #include #include -#include #include #include #include @@ -548,35 +547,7 @@ static struct i2c_board_info bast_i2c_devs[] __initdata = { }, }; -static struct s3c_hwmon_pdata bast_hwmon_info = { - /* LCD contrast (0-6.6V) */ - .in[0] = &(struct s3c_hwmon_chcfg) { - .name = "lcd-contrast", - .mult = 3300, - .div = 512, - }, - /* LED current feedback */ - .in[1] = &(struct s3c_hwmon_chcfg) { - .name = "led-feedback", - .mult = 3300, - .div = 1024, - }, - /* LCD feedback (0-6.6V) */ - .in[2] = &(struct s3c_hwmon_chcfg) { - .name = "lcd-feedback", - .mult = 3300, - .div = 512, - }, - /* Vcore (1.8-2.0V), Vref 3.3V */ - .in[3] = &(struct s3c_hwmon_chcfg) { - .name = "vcore", - .mult = 3300, - .div = 1024, - }, -}; - /* Standard BAST devices */ -// cat /sys/devices/platform/s3c24xx-adc/s3c-hwmon/in_0 static struct platform_device *bast_devices[] __initdata = { &s3c_device_usb, @@ -585,8 +556,6 @@ static struct platform_device *bast_devices[] __initdata = { &s3c_device_i2c0, &s3c_device_rtc, &s3c_device_nand, - &s3c_device_adc, - &s3c_device_hwmon, &bast_device_dm9k, &bast_device_asix, &bast_device_axpp, @@ -619,7 +588,6 @@ static void __init bast_map_io(void) s3c24xx_register_clocks(bast_clocks, ARRAY_SIZE(bast_clocks)); s3c_device_nand.dev.platform_data = &bast_nand_info; - s3c_device_hwmon.dev.platform_data = &bast_hwmon_info; s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc)); s3c24xx_init_clocks(0); diff --git a/trunk/arch/arm/mach-s3c6410/Kconfig b/trunk/arch/arm/mach-s3c6410/Kconfig index f9d0f09f9761..e63aac7f4e5a 100644 --- a/trunk/arch/arm/mach-s3c6410/Kconfig +++ b/trunk/arch/arm/mach-s3c6410/Kconfig @@ -97,13 +97,3 @@ config MACH_NCP select S3C64XX_SETUP_I2C1 help Machine support for the Samsung NCP - -config MACH_HMT - bool "Airgoo HMT" - select CPU_S3C6410 - select S3C_DEV_FB - select S3C_DEV_USB_HOST - select S3C64XX_SETUP_FB_24BPP - select HAVE_PWM - help - Machine support for the Airgoo HMT diff --git a/trunk/arch/arm/mach-s3c6410/Makefile b/trunk/arch/arm/mach-s3c6410/Makefile index 3e48c3dbf973..6f9deac88612 100644 --- a/trunk/arch/arm/mach-s3c6410/Makefile +++ b/trunk/arch/arm/mach-s3c6410/Makefile @@ -23,4 +23,5 @@ obj-$(CONFIG_S3C6410_SETUP_SDHCI) += setup-sdhci.o obj-$(CONFIG_MACH_ANW6410) += mach-anw6410.o obj-$(CONFIG_MACH_SMDK6410) += mach-smdk6410.o obj-$(CONFIG_MACH_NCP) += mach-ncp.o -obj-$(CONFIG_MACH_HMT) += mach-hmt.o + + diff --git a/trunk/arch/arm/mach-s3c6410/mach-hmt.c b/trunk/arch/arm/mach-s3c6410/mach-hmt.c deleted file mode 100644 index c5741056193f..000000000000 --- a/trunk/arch/arm/mach-s3c6410/mach-hmt.c +++ /dev/null @@ -1,276 +0,0 @@ -/* mach-hmt.c - Platform code for Airgoo HMT - * - * Copyright 2009 Peter Korsgaard - * - * 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. - * -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#define UCON S3C2410_UCON_DEFAULT -#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE) -#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE) - -static struct s3c2410_uartcfg hmt_uartcfgs[] __initdata = { - [0] = { - .hwport = 0, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - }, - [1] = { - .hwport = 1, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - }, - [2] = { - .hwport = 2, - .flags = 0, - .ucon = UCON, - .ulcon = ULCON, - .ufcon = UFCON, - }, -}; - -static int hmt_bl_init(struct device *dev) -{ - int ret; - - ret = gpio_request(S3C64XX_GPB(4), "lcd backlight enable"); - if (!ret) - ret = gpio_direction_output(S3C64XX_GPB(4), 0); - - return ret; -} - -static int hmt_bl_notify(int brightness) -{ - /* - * translate from CIELUV/CIELAB L*->brightness, E.G. from - * perceived luminance to light output. Assumes range 0..25600 - */ - if (brightness < 0x800) { - /* Y = Yn * L / 903.3 */ - brightness = (100*256 * brightness + 231245/2) / 231245; - } else { - /* Y = Yn * ((L + 16) / 116 )^3 */ - int t = (brightness*4 + 16*1024 + 58)/116; - brightness = 25 * ((t * t * t + 0x100000/2) / 0x100000); - } - - gpio_set_value(S3C64XX_GPB(4), brightness); - - return brightness; -} - -static void hmt_bl_exit(struct device *dev) -{ - gpio_free(S3C64XX_GPB(4)); -} - -static struct platform_pwm_backlight_data hmt_backlight_data = { - .pwm_id = 1, - .max_brightness = 100 * 256, - .dft_brightness = 40 * 256, - .pwm_period_ns = 1000000000 / (100 * 256 * 20), - .init = hmt_bl_init, - .notify = hmt_bl_notify, - .exit = hmt_bl_exit, - -}; - -static struct platform_device hmt_backlight_device = { - .name = "pwm-backlight", - .dev = { - .parent = &s3c_device_timer[1].dev, - .platform_data = &hmt_backlight_data, - }, -}; - -static struct s3c_fb_pd_win hmt_fb_win0 = { - .win_mode = { - .pixclock = 41094, - .left_margin = 8, - .right_margin = 13, - .upper_margin = 7, - .lower_margin = 5, - .hsync_len = 3, - .vsync_len = 1, - .xres = 800, - .yres = 480, - }, - .max_bpp = 32, - .default_bpp = 16, -}; - -/* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */ -static struct s3c_fb_platdata hmt_lcd_pdata __initdata = { - .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, - .win[0] = &hmt_fb_win0, - .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, - .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, -}; - -static struct mtd_partition hmt_nand_part[] = { - [0] = { - .name = "uboot", - .size = SZ_512K, - .offset = 0, - }, - [1] = { - .name = "uboot-env1", - .size = SZ_256K, - .offset = SZ_512K, - }, - [2] = { - .name = "uboot-env2", - .size = SZ_256K, - .offset = SZ_512K + SZ_256K, - }, - [3] = { - .name = "kernel", - .size = SZ_2M, - .offset = SZ_1M, - }, - [4] = { - .name = "rootfs", - .size = MTDPART_SIZ_FULL, - .offset = SZ_1M + SZ_2M, - }, -}; - -static struct s3c2410_nand_set hmt_nand_sets[] = { - [0] = { - .name = "nand", - .nr_chips = 1, - .nr_partitions = ARRAY_SIZE(hmt_nand_part), - .partitions = hmt_nand_part, - }, -}; - -static struct s3c2410_platform_nand hmt_nand_info = { - .tacls = 25, - .twrph0 = 55, - .twrph1 = 40, - .nr_sets = ARRAY_SIZE(hmt_nand_sets), - .sets = hmt_nand_sets, -}; - -static struct gpio_led hmt_leds[] = { - { /* left function keys */ - .name = "left:blue", - .gpio = S3C64XX_GPO(12), - .default_trigger = "default-on", - }, - { /* right function keys - red */ - .name = "right:red", - .gpio = S3C64XX_GPO(13), - }, - { /* right function keys - green */ - .name = "right:green", - .gpio = S3C64XX_GPO(14), - }, - { /* right function keys - blue */ - .name = "right:blue", - .gpio = S3C64XX_GPO(15), - .default_trigger = "default-on", - }, -}; - -static struct gpio_led_platform_data hmt_led_data = { - .num_leds = ARRAY_SIZE(hmt_leds), - .leds = hmt_leds, -}; - -static struct platform_device hmt_leds_device = { - .name = "leds-gpio", - .id = -1, - .dev.platform_data = &hmt_led_data, -}; - -static struct map_desc hmt_iodesc[] = {}; - -static struct platform_device *hmt_devices[] __initdata = { - &s3c_device_i2c0, - &s3c_device_nand, - &s3c_device_fb, - &s3c_device_usb, - &s3c_device_timer[1], - &hmt_backlight_device, - &hmt_leds_device, -}; - -static void __init hmt_map_io(void) -{ - s3c64xx_init_io(hmt_iodesc, ARRAY_SIZE(hmt_iodesc)); - s3c24xx_init_clocks(12000000); - s3c24xx_init_uarts(hmt_uartcfgs, ARRAY_SIZE(hmt_uartcfgs)); -} - -static void __init hmt_machine_init(void) -{ - s3c_i2c0_set_platdata(NULL); - s3c_fb_set_platdata(&hmt_lcd_pdata); - s3c_device_nand.dev.platform_data = &hmt_nand_info; - - gpio_request(S3C64XX_GPC(7), "usb power"); - gpio_direction_output(S3C64XX_GPC(7), 0); - gpio_request(S3C64XX_GPM(0), "usb power"); - gpio_direction_output(S3C64XX_GPM(0), 1); - gpio_request(S3C64XX_GPK(7), "usb power"); - gpio_direction_output(S3C64XX_GPK(7), 1); - gpio_request(S3C64XX_GPF(13), "usb power"); - gpio_direction_output(S3C64XX_GPF(13), 1); - - platform_add_devices(hmt_devices, ARRAY_SIZE(hmt_devices)); -} - -MACHINE_START(HMT, "Airgoo-HMT") - /* Maintainer: Peter Korsgaard */ - .phys_io = S3C_PA_UART & 0xfff00000, - .io_pg_offst = (((u32)S3C_VA_UART) >> 18) & 0xfffc, - .boot_params = S3C64XX_PA_SDRAM + 0x100, - .init_irq = s3c6410_init_irq, - .map_io = hmt_map_io, - .init_machine = hmt_machine_init, - .timer = &s3c24xx_timer, -MACHINE_END diff --git a/trunk/arch/arm/plat-s3c/include/plat/adc.h b/trunk/arch/arm/plat-s3c/include/plat/adc.h index 5f3b1cd53b90..d847bd476b6c 100644 --- a/trunk/arch/arm/plat-s3c/include/plat/adc.h +++ b/trunk/arch/arm/plat-s3c/include/plat/adc.h @@ -19,14 +19,10 @@ struct s3c_adc_client; extern int s3c_adc_start(struct s3c_adc_client *client, unsigned int channel, unsigned int nr_samples); -extern int s3c_adc_read(struct s3c_adc_client *client, unsigned int ch); - extern struct s3c_adc_client * s3c_adc_register(struct platform_device *pdev, - void (*select)(struct s3c_adc_client *client, - unsigned selected), - void (*conv)(struct s3c_adc_client *client, - unsigned d0, unsigned d1, + void (*select)(unsigned selected), + void (*conv)(unsigned d0, unsigned d1, unsigned *samples_left), unsigned int is_ts); diff --git a/trunk/arch/arm/plat-s3c/include/plat/devs.h b/trunk/arch/arm/plat-s3c/include/plat/devs.h index 1989ca1bb2b1..2e170827e0b0 100644 --- a/trunk/arch/arm/plat-s3c/include/plat/devs.h +++ b/trunk/arch/arm/plat-s3c/include/plat/devs.h @@ -46,8 +46,6 @@ extern struct platform_device s3c_device_hsmmc2; extern struct platform_device s3c_device_spi0; extern struct platform_device s3c_device_spi1; -extern struct platform_device s3c_device_hwmon; - extern struct platform_device s3c_device_nand; extern struct platform_device s3c_device_usbgadget; diff --git a/trunk/arch/arm/plat-s3c/include/plat/hwmon.h b/trunk/arch/arm/plat-s3c/include/plat/hwmon.h deleted file mode 100644 index 1ba88ea0aa31..000000000000 --- a/trunk/arch/arm/plat-s3c/include/plat/hwmon.h +++ /dev/null @@ -1,41 +0,0 @@ -/* linux/arch/arm/plat-s3c/include/plat/hwmon.h - * - * Copyright 2005 Simtec Electronics - * Ben Dooks - * http://armlinux.simtec.co.uk/ - * - * S3C - HWMon interface for ADC - * - * 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. -*/ - -#ifndef __ASM_ARCH_ADC_HWMON_H -#define __ASM_ARCH_ADC_HWMON_H __FILE__ - -/** - * s3c_hwmon_chcfg - channel configuration - * @name: The name to give this channel. - * @mult: Multiply the ADC value read by this. - * @div: Divide the value from the ADC by this. - * - * The value read from the ADC is converted to a value that - * hwmon expects (mV) by result = (value_read * @mult) / @div. - */ -struct s3c_hwmon_chcfg { - const char *name; - unsigned int mult; - unsigned int div; -}; - -/** - * s3c_hwmon_pdata - HWMON platform data - * @in: One configuration for each possible channel used. - */ -struct s3c_hwmon_pdata { - struct s3c_hwmon_chcfg *in[8]; -}; - -#endif /* __ASM_ARCH_ADC_HWMON_H */ - diff --git a/trunk/arch/arm/plat-s3c24xx/adc.c b/trunk/arch/arm/plat-s3c24xx/adc.c index 11117a7ba911..ee1baf11ad9e 100644 --- a/trunk/arch/arm/plat-s3c24xx/adc.c +++ b/trunk/arch/arm/plat-s3c24xx/adc.c @@ -39,16 +39,13 @@ struct s3c_adc_client { struct platform_device *pdev; struct list_head pend; - wait_queue_head_t *wait; unsigned int nr_samples; - int result; unsigned char is_ts; unsigned char channel; - void (*select_cb)(struct s3c_adc_client *c, unsigned selected); - void (*convert_cb)(struct s3c_adc_client *c, - unsigned val1, unsigned val2, + void (*select_cb)(unsigned selected); + void (*convert_cb)(unsigned val1, unsigned val2, unsigned *samples_left); }; @@ -84,7 +81,7 @@ static inline void s3c_adc_select(struct adc_device *adc, { unsigned con = readl(adc->regs + S3C2410_ADCCON); - client->select_cb(client, 1); + client->select_cb(1); con &= ~S3C2410_ADCCON_MUXMASK; con &= ~S3C2410_ADCCON_STDBM; @@ -156,61 +153,25 @@ int s3c_adc_start(struct s3c_adc_client *client, } EXPORT_SYMBOL_GPL(s3c_adc_start); -static void s3c_convert_done(struct s3c_adc_client *client, - unsigned v, unsigned u, unsigned *left) -{ - client->result = v; - wake_up(client->wait); -} - -int s3c_adc_read(struct s3c_adc_client *client, unsigned int ch) -{ - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake); - int ret; - - client->convert_cb = s3c_convert_done; - client->wait = &wake; - client->result = -1; - - ret = s3c_adc_start(client, ch, 1); - if (ret < 0) - goto err; - - ret = wait_event_timeout(wake, client->result >= 0, HZ / 2); - if (client->result < 0) { - ret = -ETIMEDOUT; - goto err; - } - - client->convert_cb = NULL; - return client->result; - -err: - return ret; -} -EXPORT_SYMBOL_GPL(s3c_adc_convert); - -static void s3c_adc_default_select(struct s3c_adc_client *client, - unsigned select) +static void s3c_adc_default_select(unsigned select) { } struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev, - void (*select)(struct s3c_adc_client *client, - unsigned int selected), - void (*conv)(struct s3c_adc_client *client, - unsigned d0, unsigned d1, + void (*select)(unsigned int selected), + void (*conv)(unsigned d0, unsigned d1, unsigned *samples_left), unsigned int is_ts) { struct s3c_adc_client *client; WARN_ON(!pdev); + WARN_ON(!conv); if (!select) select = s3c_adc_default_select; - if (!pdev) + if (!conv || !pdev) return ERR_PTR(-EINVAL); client = kzalloc(sizeof(struct s3c_adc_client), GFP_KERNEL); @@ -269,19 +230,16 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw) adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1); client->nr_samples--; - - if (client->convert_cb) - (client->convert_cb)(client, data0 & 0x3ff, data1 & 0x3ff, - &client->nr_samples); + (client->convert_cb)(data0 & 0x3ff, data1 & 0x3ff, &client->nr_samples); if (client->nr_samples > 0) { /* fire another conversion for this */ - client->select_cb(client, 1); + client->select_cb(1); s3c_adc_convert(adc); } else { local_irq_save(flags); - (client->select_cb)(client, 0); + (client->select_cb)(0); adc->cur = NULL; s3c_adc_try(adc); diff --git a/trunk/arch/arm/plat-s3c24xx/devs.c b/trunk/arch/arm/plat-s3c24xx/devs.c index 3489019b5374..4eb378c89a39 100644 --- a/trunk/arch/arm/plat-s3c24xx/devs.c +++ b/trunk/arch/arm/plat-s3c24xx/devs.c @@ -348,7 +348,7 @@ struct platform_device s3c_device_adc = { /* HWMON */ struct platform_device s3c_device_hwmon = { - .name = "s3c-hwmon", + .name = "s3c24xx-hwmon", .id = -1, .dev.parent = &s3c_device_adc.dev, }; diff --git a/trunk/arch/arm/plat-s3c24xx/include/plat/fiq.h b/trunk/arch/arm/plat-s3c24xx/include/plat/fiq.h new file mode 100644 index 000000000000..8521b8372c5f --- /dev/null +++ b/trunk/arch/arm/plat-s3c24xx/include/plat/fiq.h @@ -0,0 +1,13 @@ +/* linux/include/asm-arm/plat-s3c24xx/fiq.h + * + * Copyright (c) 2009 Simtec Electronics + * Ben Dooks + * + * Header file for S3C24XX CPU FIQ support + * + * 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. +*/ + +extern int s3c24xx_set_fiq(unsigned int irq, bool on); diff --git a/trunk/arch/arm/plat-s3c24xx/irq.c b/trunk/arch/arm/plat-s3c24xx/irq.c index 958737775ad2..d02f5f02045e 100644 --- a/trunk/arch/arm/plat-s3c24xx/irq.c +++ b/trunk/arch/arm/plat-s3c24xx/irq.c @@ -493,6 +493,38 @@ s3c_irq_demux_extint4t7(unsigned int irq, } } +#ifdef CONFIG_FIQ +/** + * s3c24xx_set_fiq - set the FIQ routing + * @irq: IRQ number to route to FIQ on processor. + * @on: Whether to route @irq to the FIQ, or to remove the FIQ routing. + * + * Change the state of the IRQ to FIQ routing depending on @irq and @on. If + * @on is true, the @irq is checked to see if it can be routed and the + * interrupt controller updated to route the IRQ. If @on is false, the FIQ + * routing is cleared, regardless of which @irq is specified. + */ +int s3c24xx_set_fiq(unsigned int irq, bool on) +{ + u32 intmod; + unsigned offs; + + if (on) { + offs = irq - FIQ_START; + if (offs > 31) + return -EINVAL; + + intmod = 1 << offs; + } else { + intmod = 0; + } + + __raw_writel(intmod, S3C2410_INTMOD); + return 0; +} +#endif + + /* s3c24xx_init_irq * * Initialise S3C2410 IRQ system @@ -505,6 +537,10 @@ void __init s3c24xx_init_irq(void) int irqno; int i; +#ifdef CONFIG_FIQ + init_FIQ(); +#endif + irqdbf("s3c2410_init_irq: clearing interrupt status flags\n"); /* first, clear all interrupts pending... */ diff --git a/trunk/drivers/hwmon/Kconfig b/trunk/drivers/hwmon/Kconfig index 2e25b7a827d3..2d5016691d40 100644 --- a/trunk/drivers/hwmon/Kconfig +++ b/trunk/drivers/hwmon/Kconfig @@ -702,23 +702,6 @@ config SENSORS_SHT15 This driver can also be built as a module. If so, the module will be called sht15. -config SENSORS_S3C - tristate "S3C24XX/S3C64XX Inbuilt ADC" - depends on ARCH_S3C2410 || ARCH_S3C64XX - help - If you say yes here you get support for the on-board ADCs of - the Samsung S3C24XX or S3C64XX series of SoC - - This driver can also be built as a module. If so, the module - will be called s3c-hwmo. - -config SENSORS_S3C_RAW - bool "Include raw channel attributes in sysfs" - depends on SENSORS_S3C - help - Say Y here if you want to include raw copies of all the ADC - channels in sysfs. - config SENSORS_SIS5595 tristate "Silicon Integrated Systems Corp. SiS5595" depends on PCI diff --git a/trunk/drivers/hwmon/Makefile b/trunk/drivers/hwmon/Makefile index 7f239a247c33..b793dce6bed5 100644 --- a/trunk/drivers/hwmon/Makefile +++ b/trunk/drivers/hwmon/Makefile @@ -76,7 +76,6 @@ obj-$(CONFIG_SENSORS_MAX6650) += max6650.o obj-$(CONFIG_SENSORS_PC87360) += pc87360.o obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o -obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o obj-$(CONFIG_SENSORS_SHT15) += sht15.o obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o diff --git a/trunk/drivers/hwmon/s3c-hwmon.c b/trunk/drivers/hwmon/s3c-hwmon.c deleted file mode 100644 index 3a524f2fe493..000000000000 --- a/trunk/drivers/hwmon/s3c-hwmon.c +++ /dev/null @@ -1,405 +0,0 @@ -/* linux/drivers/hwmon/s3c-hwmon.c - * - * Copyright (C) 2005, 2008, 2009 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * S3C24XX/S3C64XX ADC hwmon support - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -struct s3c_hwmon_attr { - struct sensor_device_attribute in; - struct sensor_device_attribute label; - char in_name[12]; - char label_name[12]; -}; - -/** - * struct s3c_hwmon - ADC hwmon client information - * @lock: Access lock to serialise the conversions. - * @client: The client we registered with the S3C ADC core. - * @hwmon_dev: The hwmon device we created. - * @attr: The holders for the channel attributes. -*/ -struct s3c_hwmon { - struct semaphore lock; - struct s3c_adc_client *client; - struct device *hwmon_dev; - - struct s3c_hwmon_attr attrs[8]; -}; - -/** - * s3c_hwmon_read_ch - read a value from a given adc channel. - * @dev: The device. - * @hwmon: Our state. - * @channel: The channel we're reading from. - * - * Read a value from the @channel with the proper locking and sleep until - * either the read completes or we timeout awaiting the ADC core to get - * back to us. - */ -static int s3c_hwmon_read_ch(struct device *dev, - struct s3c_hwmon *hwmon, int channel) -{ - int ret; - - ret = down_interruptible(&hwmon->lock); - if (ret < 0) - return ret; - - dev_dbg(dev, "reading channel %d\n", channel); - - ret = s3c_adc_read(hwmon->client, channel); - up(&hwmon->lock); - - return ret; -} - -#ifdef CONFIG_SENSORS_S3C_RAW -/** - * s3c_hwmon_show_raw - show a conversion from the raw channel number. - * @dev: The device that the attribute belongs to. - * @attr: The attribute being read. - * @buf: The result buffer. - * - * This show deals with the raw attribute, registered for each possible - * ADC channel. This does a conversion and returns the raw (un-scaled) - * value returned from the hardware. - */ -static ssize_t s3c_hwmon_show_raw(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct s3c_hwmon *adc = platform_get_drvdata(to_platform_device(dev)); - struct sensor_device_attribute *sa = to_sensor_dev_attr(attr); - int ret; - - ret = s3c_hwmon_read_ch(dev, adc, sa->index); - - return (ret < 0) ? ret : snprintf(buf, PAGE_SIZE, "%d\n", ret); -} - -#define DEF_ADC_ATTR(x) \ - static SENSOR_DEVICE_ATTR(adc##x##_raw, S_IRUGO, s3c_hwmon_show_raw, NULL, x) - -DEF_ADC_ATTR(0); -DEF_ADC_ATTR(1); -DEF_ADC_ATTR(2); -DEF_ADC_ATTR(3); -DEF_ADC_ATTR(4); -DEF_ADC_ATTR(5); -DEF_ADC_ATTR(6); -DEF_ADC_ATTR(7); - -static struct attribute *s3c_hwmon_attrs[9] = { - &sensor_dev_attr_adc0_raw.dev_attr.attr, - &sensor_dev_attr_adc1_raw.dev_attr.attr, - &sensor_dev_attr_adc2_raw.dev_attr.attr, - &sensor_dev_attr_adc3_raw.dev_attr.attr, - &sensor_dev_attr_adc4_raw.dev_attr.attr, - &sensor_dev_attr_adc5_raw.dev_attr.attr, - &sensor_dev_attr_adc6_raw.dev_attr.attr, - &sensor_dev_attr_adc7_raw.dev_attr.attr, - NULL, -}; - -static struct attribute_group s3c_hwmon_attrgroup = { - .attrs = s3c_hwmon_attrs, -}; - -static inline int s3c_hwmon_add_raw(struct device *dev) -{ - return sysfs_create_group(&dev->kobj, &s3c_hwmon_attrgroup); -} - -static inline void s3c_hwmon_remove_raw(struct device *dev) -{ - sysfs_remove_group(&dev->kobj, &s3c_hwmon_attrgroup); -} - -#else - -static inline int s3c_hwmon_add_raw(struct device *dev) { return 0; } -static inline void s3c_hwmon_remove_raw(struct device *dev) { } - -#endif /* CONFIG_SENSORS_S3C_RAW */ - -/** - * s3c_hwmon_ch_show - show value of a given channel - * @dev: The device that the attribute belongs to. - * @attr: The attribute being read. - * @buf: The result buffer. - * - * Read a value from the ADC and scale it before returning it to the - * caller. The scale factor is gained from the channel configuration - * passed via the platform data when the device was registered. - */ -static ssize_t s3c_hwmon_ch_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr); - struct s3c_hwmon *hwmon = platform_get_drvdata(to_platform_device(dev)); - struct s3c_hwmon_pdata *pdata = dev->platform_data; - struct s3c_hwmon_chcfg *cfg; - int ret; - - cfg = pdata->in[sen_attr->index]; - - ret = s3c_hwmon_read_ch(dev, hwmon, sen_attr->index); - if (ret < 0) - return ret; - - ret *= cfg->mult; - ret = DIV_ROUND_CLOSEST(ret, cfg->div); - - return snprintf(buf, PAGE_SIZE, "%d\n", ret); -} - -/** - * s3c_hwmon_label_show - show label name of the given channel. - * @dev: The device that the attribute belongs to. - * @attr: The attribute being read. - * @buf: The result buffer. - * - * Return the label name of a given channel - */ -static ssize_t s3c_hwmon_label_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sen_attr = to_sensor_dev_attr(attr); - struct s3c_hwmon_pdata *pdata = dev->platform_data; - struct s3c_hwmon_chcfg *cfg; - - cfg = pdata->in[sen_attr->index]; - - return snprintf(buf, PAGE_SIZE, "%s\n", cfg->name); -} - -/** - * s3c_hwmon_create_attr - create hwmon attribute for given channel. - * @dev: The device to create the attribute on. - * @cfg: The channel configuration passed from the platform data. - * @channel: The ADC channel number to process. - * - * Create the scaled attribute for use with hwmon from the specified - * platform data in @pdata. The sysfs entry is handled by the routine - * s3c_hwmon_ch_show(). - * - * The attribute name is taken from the configuration data if present - * otherwise the name is taken by concatenating in_ with the channel - * number. - */ -static int s3c_hwmon_create_attr(struct device *dev, - struct s3c_hwmon_chcfg *cfg, - struct s3c_hwmon_attr *attrs, - int channel) -{ - struct sensor_device_attribute *attr; - int ret; - - snprintf(attrs->in_name, sizeof(attrs->in_name), "in%d_input", channel); - - attr = &attrs->in; - attr->index = channel; - attr->dev_attr.attr.name = attrs->in_name; - attr->dev_attr.attr.mode = S_IRUGO; - attr->dev_attr.attr.owner = THIS_MODULE; - attr->dev_attr.show = s3c_hwmon_ch_show; - - ret = device_create_file(dev, &attr->dev_attr); - if (ret < 0) { - dev_err(dev, "failed to create input attribute\n"); - return ret; - } - - /* if this has a name, add a label */ - if (cfg->name) { - snprintf(attrs->label_name, sizeof(attrs->label_name), - "in%d_label", channel); - - attr = &attrs->label; - attr->index = channel; - attr->dev_attr.attr.name = attrs->label_name; - attr->dev_attr.attr.mode = S_IRUGO; - attr->dev_attr.attr.owner = THIS_MODULE; - attr->dev_attr.show = s3c_hwmon_label_show; - - ret = device_create_file(dev, &attr->dev_attr); - if (ret < 0) { - device_remove_file(dev, &attrs->in.dev_attr); - dev_err(dev, "failed to create label attribute\n"); - } - } - - return ret; -} - -static void s3c_hwmon_remove_attr(struct device *dev, - struct s3c_hwmon_attr *attrs) -{ - device_remove_file(dev, &attrs->in.dev_attr); - device_remove_file(dev, &attrs->label.dev_attr); -} - -/** - * s3c_hwmon_probe - device probe entry. - * @dev: The device being probed. -*/ -static int __devinit s3c_hwmon_probe(struct platform_device *dev) -{ - struct s3c_hwmon_pdata *pdata = dev->dev.platform_data; - struct s3c_hwmon *hwmon; - int ret = 0; - int i; - - if (!pdata) { - dev_err(&dev->dev, "no platform data supplied\n"); - return -EINVAL; - } - - hwmon = kzalloc(sizeof(struct s3c_hwmon), GFP_KERNEL); - if (hwmon == NULL) { - dev_err(&dev->dev, "no memory\n"); - return -ENOMEM; - } - - platform_set_drvdata(dev, hwmon); - - init_MUTEX(&hwmon->lock); - - /* Register with the core ADC driver. */ - - hwmon->client = s3c_adc_register(dev, NULL, NULL, 0); - if (IS_ERR(hwmon->client)) { - dev_err(&dev->dev, "cannot register adc\n"); - ret = PTR_ERR(hwmon->client); - goto err_mem; - } - - /* add attributes for our adc devices. */ - - ret = s3c_hwmon_add_raw(&dev->dev); - if (ret) - goto err_registered; - - /* register with the hwmon core */ - - hwmon->hwmon_dev = hwmon_device_register(&dev->dev); - if (IS_ERR(hwmon->hwmon_dev)) { - dev_err(&dev->dev, "error registering with hwmon\n"); - ret = PTR_ERR(hwmon->hwmon_dev); - goto err_raw_attribute; - } - - for (i = 0; i < ARRAY_SIZE(pdata->in); i++) { - if (!pdata->in[i]) - continue; - - if (pdata->in[i]->mult >= 0x10000) - dev_warn(&dev->dev, - "channel %d multiplier too large\n", - i); - - ret = s3c_hwmon_create_attr(&dev->dev, pdata->in[i], - &hwmon->attrs[i], i); - if (ret) { - dev_err(&dev->dev, - "error creating channel %d\n", i); - - for (i--; i >= 0; i--) - s3c_hwmon_remove_attr(&dev->dev, - &hwmon->attrs[i]); - - goto err_hwmon_register; - } - } - - return 0; - - err_hwmon_register: - hwmon_device_unregister(hwmon->hwmon_dev); - - err_raw_attribute: - s3c_hwmon_remove_raw(&dev->dev); - - err_registered: - s3c_adc_release(hwmon->client); - - err_mem: - kfree(hwmon); - return ret; -} - -static int __devexit s3c_hwmon_remove(struct platform_device *dev) -{ - struct s3c_hwmon *hwmon = platform_get_drvdata(dev); - int i; - - s3c_hwmon_remove_raw(&dev->dev); - - for (i = 0; i < ARRAY_SIZE(hwmon->attrs); i++) - s3c_hwmon_remove_attr(&dev->dev, &hwmon->attrs[i]); - - hwmon_device_unregister(hwmon->hwmon_dev); - s3c_adc_release(hwmon->client); - - return 0; -} - -static struct platform_driver s3c_hwmon_driver = { - .driver = { - .name = "s3c-hwmon", - .owner = THIS_MODULE, - }, - .probe = s3c_hwmon_probe, - .remove = __devexit_p(s3c_hwmon_remove), -}; - -static int __init s3c_hwmon_init(void) -{ - return platform_driver_register(&s3c_hwmon_driver); -} - -static void __exit s3c_hwmon_exit(void) -{ - platform_driver_unregister(&s3c_hwmon_driver); -} - -module_init(s3c_hwmon_init); -module_exit(s3c_hwmon_exit); - -MODULE_AUTHOR("Ben Dooks "); -MODULE_DESCRIPTION("S3C ADC HWMon driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:s3c-hwmon");