Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
63c949ea
Commit
63c949ea
authored
Aug 14, 2009
by
Ben Dooks
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'next-s3c-hwmon' into next-s3c
parents
9b71de49
bff78650
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
558 additions
and
14 deletions
+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
No files found.
arch/arm/mach-s3c2410/mach-bast.c
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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
View file @
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"
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment