Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
63c949ea
K
Kernel
项目概览
openeuler
/
Kernel
1 年多 前同步成功
通知
8
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
63c949ea
编写于
8月 14, 2009
作者:
B
Ben Dooks
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'next-s3c-hwmon' into next-s3c
上级
9b71de49
bff78650
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
558 addition
and
14 deletion
+558
-14
arch/arm/mach-s3c2410/mach-bast.c
arch/arm/mach-s3c2410/mach-bast.c
+32
-0
arch/arm/plat-s3c/include/plat/adc.h
arch/arm/plat-s3c/include/plat/adc.h
+6
-2
arch/arm/plat-s3c/include/plat/devs.h
arch/arm/plat-s3c/include/plat/devs.h
+2
-0
arch/arm/plat-s3c/include/plat/hwmon.h
arch/arm/plat-s3c/include/plat/hwmon.h
+41
-0
arch/arm/plat-s3c24xx/adc.c
arch/arm/plat-s3c24xx/adc.c
+53
-11
arch/arm/plat-s3c24xx/devs.c
arch/arm/plat-s3c24xx/devs.c
+1
-1
drivers/hwmon/Kconfig
drivers/hwmon/Kconfig
+17
-0
drivers/hwmon/Makefile
drivers/hwmon/Makefile
+1
-0
drivers/hwmon/s3c-hwmon.c
drivers/hwmon/s3c-hwmon.c
+405
-0
未找到文件。
arch/arm/mach-s3c2410/mach-bast.c
浏览文件 @
63c949ea
...
...
@@ -45,6 +45,7 @@
#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <plat/hwmon.h>
#include <plat/nand.h>
#include <plat/iic.h>
#include <mach/fb.h>
...
...
@@ -547,7 +548,35 @@ 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
,
...
...
@@ -556,6 +585,8 @@ 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
,
...
...
@@ -588,6 +619,7 @@ 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
);
...
...
arch/arm/plat-s3c/include/plat/adc.h
浏览文件 @
63c949ea
...
...
@@ -19,10 +19,14 @@ 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
)(
unsigned
selected
),
void
(
*
conv
)(
unsigned
d0
,
unsigned
d1
,
void
(
*
select
)(
struct
s3c_adc_client
*
client
,
unsigned
selected
),
void
(
*
conv
)(
struct
s3c_adc_client
*
client
,
unsigned
d0
,
unsigned
d1
,
unsigned
*
samples_left
),
unsigned
int
is_ts
);
...
...
arch/arm/plat-s3c/include/plat/devs.h
浏览文件 @
63c949ea
...
...
@@ -46,6 +46,8 @@ 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
;
...
...
arch/arm/plat-s3c/include/plat/hwmon.h
0 → 100644
浏览文件 @
63c949ea
/* linux/arch/arm/plat-s3c/include/plat/hwmon.h
*
* Copyright 2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
* 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 */
arch/arm/plat-s3c24xx/adc.c
浏览文件 @
63c949ea
...
...
@@ -39,13 +39,16 @@
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
)(
unsigned
selected
);
void
(
*
convert_cb
)(
unsigned
val1
,
unsigned
val2
,
void
(
*
select_cb
)(
struct
s3c_adc_client
*
c
,
unsigned
selected
);
void
(
*
convert_cb
)(
struct
s3c_adc_client
*
c
,
unsigned
val1
,
unsigned
val2
,
unsigned
*
samples_left
);
};
...
...
@@ -81,7 +84,7 @@ static inline void s3c_adc_select(struct adc_device *adc,
{
unsigned
con
=
readl
(
adc
->
regs
+
S3C2410_ADCCON
);
client
->
select_cb
(
1
);
client
->
select_cb
(
client
,
1
);
con
&=
~
S3C2410_ADCCON_MUXMASK
;
con
&=
~
S3C2410_ADCCON_STDBM
;
...
...
@@ -153,25 +156,61 @@ int s3c_adc_start(struct s3c_adc_client *client,
}
EXPORT_SYMBOL_GPL
(
s3c_adc_start
);
static
void
s3c_adc_default_select
(
unsigned
select
)
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
)
{
}
struct
s3c_adc_client
*
s3c_adc_register
(
struct
platform_device
*
pdev
,
void
(
*
select
)(
unsigned
int
selected
),
void
(
*
conv
)(
unsigned
d0
,
unsigned
d1
,
void
(
*
select
)(
struct
s3c_adc_client
*
client
,
unsigned
int
selected
),
void
(
*
conv
)(
struct
s3c_adc_client
*
client
,
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
(
!
conv
||
!
pdev
)
if
(
!
pdev
)
return
ERR_PTR
(
-
EINVAL
);
client
=
kzalloc
(
sizeof
(
struct
s3c_adc_client
),
GFP_KERNEL
);
...
...
@@ -230,16 +269,19 @@ 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
--
;
(
client
->
convert_cb
)(
data0
&
0x3ff
,
data1
&
0x3ff
,
&
client
->
nr_samples
);
if
(
client
->
convert_cb
)
(
client
->
convert_cb
)(
client
,
data0
&
0x3ff
,
data1
&
0x3ff
,
&
client
->
nr_samples
);
if
(
client
->
nr_samples
>
0
)
{
/* fire another conversion for this */
client
->
select_cb
(
1
);
client
->
select_cb
(
client
,
1
);
s3c_adc_convert
(
adc
);
}
else
{
local_irq_save
(
flags
);
(
client
->
select_cb
)(
0
);
(
client
->
select_cb
)(
client
,
0
);
adc
->
cur
=
NULL
;
s3c_adc_try
(
adc
);
...
...
arch/arm/plat-s3c24xx/devs.c
浏览文件 @
63c949ea
...
...
@@ -348,7 +348,7 @@ struct platform_device s3c_device_adc = {
/* HWMON */
struct
platform_device
s3c_device_hwmon
=
{
.
name
=
"s3c
24xx
-hwmon"
,
.
name
=
"s3c-hwmon"
,
.
id
=
-
1
,
.
dev
.
parent
=
&
s3c_device_adc
.
dev
,
};
...
...
drivers/hwmon/Kconfig
浏览文件 @
63c949ea
...
...
@@ -702,6 +702,23 @@ 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
...
...
drivers/hwmon/Makefile
浏览文件 @
63c949ea
...
...
@@ -76,6 +76,7 @@ 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
...
...
drivers/hwmon/s3c-hwmon.c
0 → 100644
浏览文件 @
63c949ea
/* linux/drivers/hwmon/s3c-hwmon.c
*
* Copyright (C) 2005, 2008, 2009 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* 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 <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <plat/adc.h>
#include <plat/hwmon.h>
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 <ben@simtec.co.uk>"
);
MODULE_DESCRIPTION
(
"S3C ADC HWMon driver"
);
MODULE_LICENSE
(
"GPL v2"
);
MODULE_ALIAS
(
"platform:s3c-hwmon"
);
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录