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
Kirill Smelkov
linux
Commits
6ceaf58a
Commit
6ceaf58a
authored
Oct 17, 2014
by
Zhang Rui
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'int340x-thermal' of .git into next
parents
9ceaa81e
d8054749
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
1867 additions
and
112 deletions
+1867
-112
drivers/acpi/Kconfig
drivers/acpi/Kconfig
+1
-1
drivers/acpi/Makefile
drivers/acpi/Makefile
+1
-0
drivers/acpi/acpi_platform.c
drivers/acpi/acpi_platform.c
+1
-0
drivers/acpi/device_pm.c
drivers/acpi/device_pm.c
+1
-0
drivers/acpi/fan.c
drivers/acpi/fan.c
+265
-76
drivers/acpi/int340x_thermal.c
drivers/acpi/int340x_thermal.c
+51
-0
drivers/acpi/internal.h
drivers/acpi/internal.h
+1
-9
drivers/acpi/scan.c
drivers/acpi/scan.c
+1
-0
drivers/acpi/thermal.c
drivers/acpi/thermal.c
+9
-9
drivers/acpi/utils.c
drivers/acpi/utils.c
+27
-1
drivers/thermal/Kconfig
drivers/thermal/Kconfig
+24
-15
drivers/thermal/Makefile
drivers/thermal/Makefile
+1
-1
drivers/thermal/int340x_thermal/Makefile
drivers/thermal/int340x_thermal/Makefile
+4
-0
drivers/thermal/int340x_thermal/acpi_thermal_rel.c
drivers/thermal/int340x_thermal/acpi_thermal_rel.c
+400
-0
drivers/thermal/int340x_thermal/acpi_thermal_rel.h
drivers/thermal/int340x_thermal/acpi_thermal_rel.h
+84
-0
drivers/thermal/int340x_thermal/int3400_thermal.c
drivers/thermal/int340x_thermal/int3400_thermal.c
+271
-0
drivers/thermal/int340x_thermal/int3402_thermal.c
drivers/thermal/int340x_thermal/int3402_thermal.c
+242
-0
drivers/thermal/int340x_thermal/int3403_thermal.c
drivers/thermal/int340x_thermal/int3403_thermal.c
+477
-0
include/acpi/acpi_bus.h
include/acpi/acpi_bus.h
+1
-0
include/linux/acpi.h
include/linux/acpi.h
+1
-0
include/linux/thermal.h
include/linux/thermal.h
+4
-0
No files found.
drivers/acpi/Kconfig
View file @
6ceaf58a
...
...
@@ -144,7 +144,7 @@ config ACPI_VIDEO
config ACPI_FAN
tristate "Fan"
select
THERMAL
depends on
THERMAL
default y
help
This driver supports ACPI fan devices, allowing user-mode
...
...
drivers/acpi/Makefile
View file @
6ceaf58a
...
...
@@ -43,6 +43,7 @@ acpi-y += pci_root.o pci_link.o pci_irq.o
acpi-y
+=
acpi_lpss.o
acpi-y
+=
acpi_platform.o
acpi-y
+=
acpi_pnp.o
acpi-y
+=
int340x_thermal.o
acpi-y
+=
power.o
acpi-y
+=
event.o
acpi-y
+=
sysfs.o
...
...
drivers/acpi/acpi_platform.c
View file @
6ceaf58a
...
...
@@ -113,3 +113,4 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
kfree
(
resources
);
return
pdev
;
}
EXPORT_SYMBOL_GPL
(
acpi_create_platform_device
);
drivers/acpi/device_pm.c
View file @
6ceaf58a
...
...
@@ -343,6 +343,7 @@ int acpi_device_update_power(struct acpi_device *device, int *state_p)
return
0
;
}
EXPORT_SYMBOL_GPL
(
acpi_device_update_power
);
int
acpi_bus_update_power
(
acpi_handle
handle
,
int
*
state_p
)
{
...
...
drivers/acpi/fan.c
View file @
6ceaf58a
...
...
@@ -30,24 +30,19 @@
#include <asm/uaccess.h>
#include <linux/thermal.h>
#include <linux/acpi.h>
#define PREFIX "ACPI: "
#define ACPI_FAN_CLASS "fan"
#define ACPI_FAN_FILE_STATE "state"
#define _COMPONENT ACPI_FAN_COMPONENT
ACPI_MODULE_NAME
(
"fan"
);
#include <linux/platform_device.h>
#include <linux/sort.h>
MODULE_AUTHOR
(
"Paul Diefenbaugh"
);
MODULE_DESCRIPTION
(
"ACPI Fan Driver"
);
MODULE_LICENSE
(
"GPL"
);
static
int
acpi_fan_
add
(
struct
acpi_device
*
device
);
static
int
acpi_fan_remove
(
struct
acpi_device
*
device
);
static
int
acpi_fan_
probe
(
struct
platform_device
*
pdev
);
static
int
acpi_fan_remove
(
struct
platform_device
*
pdev
);
static
const
struct
acpi_device_id
fan_device_ids
[]
=
{
{
"PNP0C0B"
,
0
},
{
"INT3404"
,
0
},
{
""
,
0
},
};
MODULE_DEVICE_TABLE
(
acpi
,
fan_device_ids
);
...
...
@@ -66,37 +61,100 @@ static struct dev_pm_ops acpi_fan_pm = {
#define FAN_PM_OPS_PTR NULL
#endif
static
struct
acpi_driver
acpi_fan_driver
=
{
.
name
=
"fan"
,
.
class
=
ACPI_FAN_CLASS
,
.
ids
=
fan_device_ids
,
.
ops
=
{
.
add
=
acpi_fan_add
,
.
remove
=
acpi_fan_remove
,
},
.
drv
.
pm
=
FAN_PM_OPS_PTR
,
struct
acpi_fan_fps
{
u64
control
;
u64
trip_point
;
u64
speed
;
u64
noise_level
;
u64
power
;
};
struct
acpi_fan_fif
{
u64
revision
;
u64
fine_grain_ctrl
;
u64
step_size
;
u64
low_speed_notification
;
};
struct
acpi_fan
{
bool
acpi4
;
struct
acpi_fan_fif
fif
;
struct
acpi_fan_fps
*
fps
;
int
fps_count
;
struct
thermal_cooling_device
*
cdev
;
};
static
struct
platform_driver
acpi_fan_driver
=
{
.
probe
=
acpi_fan_probe
,
.
remove
=
acpi_fan_remove
,
.
driver
=
{
.
name
=
"acpi-fan"
,
.
acpi_match_table
=
fan_device_ids
,
.
pm
=
FAN_PM_OPS_PTR
,
},
};
/* thermal cooling device callbacks */
static
int
fan_get_max_state
(
struct
thermal_cooling_device
*
cdev
,
unsigned
long
*
state
)
{
/* ACPI fan device only support two states: ON/OFF */
*
state
=
1
;
struct
acpi_device
*
device
=
cdev
->
devdata
;
struct
acpi_fan
*
fan
=
acpi_driver_data
(
device
);
if
(
fan
->
acpi4
)
*
state
=
fan
->
fps_count
-
1
;
else
*
state
=
1
;
return
0
;
}
static
int
fan_get_cur_state
(
struct
thermal_cooling_device
*
cdev
,
unsigned
long
*
state
)
static
int
fan_get_state_acpi4
(
struct
acpi_device
*
device
,
unsigned
long
*
state
)
{
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
struct
acpi_fan
*
fan
=
acpi_driver_data
(
device
);
union
acpi_object
*
obj
;
acpi_status
status
;
int
control
,
i
;
status
=
acpi_evaluate_object
(
device
->
handle
,
"_FST"
,
NULL
,
&
buffer
);
if
(
ACPI_FAILURE
(
status
))
{
dev_err
(
&
device
->
dev
,
"Get fan state failed
\n
"
);
return
status
;
}
obj
=
buffer
.
pointer
;
if
(
!
obj
||
obj
->
type
!=
ACPI_TYPE_PACKAGE
||
obj
->
package
.
count
!=
3
||
obj
->
package
.
elements
[
1
].
type
!=
ACPI_TYPE_INTEGER
)
{
dev_err
(
&
device
->
dev
,
"Invalid _FST data
\n
"
);
status
=
-
EINVAL
;
goto
err
;
}
control
=
obj
->
package
.
elements
[
1
].
integer
.
value
;
for
(
i
=
0
;
i
<
fan
->
fps_count
;
i
++
)
{
if
(
control
==
fan
->
fps
[
i
].
control
)
break
;
}
if
(
i
==
fan
->
fps_count
)
{
dev_dbg
(
&
device
->
dev
,
"Invalid control value returned
\n
"
);
status
=
-
EINVAL
;
goto
err
;
}
*
state
=
i
;
err:
kfree
(
obj
);
return
status
;
}
static
int
fan_get_state
(
struct
acpi_device
*
device
,
unsigned
long
*
state
)
{
struct
acpi_device
*
device
=
cdev
->
devdata
;
int
result
;
int
acpi_state
=
ACPI_STATE_D0
;
if
(
!
device
)
return
-
EINVAL
;
result
=
acpi_bus_update_power
(
device
->
handle
,
&
acpi_state
);
result
=
acpi_device_update_power
(
device
,
&
acpi_state
);
if
(
result
)
return
result
;
...
...
@@ -105,21 +163,57 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
return
0
;
}
static
int
fan_set_cur_state
(
struct
thermal_cooling_device
*
cdev
,
unsigned
long
state
)
static
int
fan_get_cur_state
(
struct
thermal_cooling_device
*
cdev
,
unsigned
long
*
state
)
{
struct
acpi_device
*
device
=
cdev
->
devdata
;
int
result
;
struct
acpi_fan
*
fan
=
acpi_driver_data
(
device
)
;
if
(
!
device
||
(
state
!=
0
&&
state
!=
1
))
if
(
fan
->
acpi4
)
return
fan_get_state_acpi4
(
device
,
state
);
else
return
fan_get_state
(
device
,
state
);
}
static
int
fan_set_state
(
struct
acpi_device
*
device
,
unsigned
long
state
)
{
if
(
state
!=
0
&&
state
!=
1
)
return
-
EINVAL
;
result
=
acpi_bus_set_power
(
device
->
handle
,
state
?
ACPI_STATE_D0
:
ACPI_STATE_D3_COLD
);
return
acpi_device_set_power
(
device
,
state
?
ACPI_STATE_D0
:
ACPI_STATE_D3_COLD
);
}
return
result
;
static
int
fan_set_state_acpi4
(
struct
acpi_device
*
device
,
unsigned
long
state
)
{
struct
acpi_fan
*
fan
=
acpi_driver_data
(
device
);
acpi_status
status
;
if
(
state
>=
fan
->
fps_count
)
return
-
EINVAL
;
status
=
acpi_execute_simple_method
(
device
->
handle
,
"_FSL"
,
fan
->
fps
[
state
].
control
);
if
(
ACPI_FAILURE
(
status
))
{
dev_dbg
(
&
device
->
dev
,
"Failed to set state by _FSL
\n
"
);
return
status
;
}
return
0
;
}
static
int
fan_set_cur_state
(
struct
thermal_cooling_device
*
cdev
,
unsigned
long
state
)
{
struct
acpi_device
*
device
=
cdev
->
devdata
;
struct
acpi_fan
*
fan
=
acpi_driver_data
(
device
);
if
(
fan
->
acpi4
)
return
fan_set_state_acpi4
(
device
,
state
);
else
return
fan_set_state
(
device
,
state
);
}
static
const
struct
thermal_cooling_device_ops
fan_cooling_ops
=
{
.
get_max_state
=
fan_get_max_state
,
.
get_cur_state
=
fan_get_cur_state
,
...
...
@@ -130,21 +224,125 @@ static const struct thermal_cooling_device_ops fan_cooling_ops = {
Driver Interface
-------------------------------------------------------------------------- */
static
int
acpi_fan_add
(
struct
acpi_device
*
device
)
static
bool
acpi_fan_is_acpi4
(
struct
acpi_device
*
device
)
{
int
result
=
0
;
struct
thermal_cooling_device
*
cdev
;
return
acpi_has_method
(
device
->
handle
,
"_FIF"
)
&&
acpi_has_method
(
device
->
handle
,
"_FPS"
)
&&
acpi_has_method
(
device
->
handle
,
"_FSL"
)
&&
acpi_has_method
(
device
->
handle
,
"_FST"
);
}
if
(
!
device
)
return
-
EINVAL
;
static
int
acpi_fan_get_fif
(
struct
acpi_device
*
device
)
{
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
struct
acpi_fan
*
fan
=
acpi_driver_data
(
device
);
struct
acpi_buffer
format
=
{
sizeof
(
"NNNN"
),
"NNNN"
};
struct
acpi_buffer
fif
=
{
sizeof
(
fan
->
fif
),
&
fan
->
fif
};
union
acpi_object
*
obj
;
acpi_status
status
;
status
=
acpi_evaluate_object
(
device
->
handle
,
"_FIF"
,
NULL
,
&
buffer
);
if
(
ACPI_FAILURE
(
status
))
return
status
;
obj
=
buffer
.
pointer
;
if
(
!
obj
||
obj
->
type
!=
ACPI_TYPE_PACKAGE
)
{
dev_err
(
&
device
->
dev
,
"Invalid _FIF data
\n
"
);
status
=
-
EINVAL
;
goto
err
;
}
strcpy
(
acpi_device_name
(
device
),
"Fan"
);
strcpy
(
acpi_device_class
(
device
),
ACPI_FAN_CLASS
);
status
=
acpi_extract_package
(
obj
,
&
format
,
&
fif
);
if
(
ACPI_FAILURE
(
status
))
{
dev_err
(
&
device
->
dev
,
"Invalid _FIF element
\n
"
);
status
=
-
EINVAL
;
}
result
=
acpi_bus_update_power
(
device
->
handle
,
NULL
);
if
(
result
)
{
printk
(
KERN_ERR
PREFIX
"Setting initial power state
\n
"
);
goto
end
;
err:
kfree
(
obj
);
return
status
;
}
static
int
acpi_fan_speed_cmp
(
const
void
*
a
,
const
void
*
b
)
{
const
struct
acpi_fan_fps
*
fps1
=
a
;
const
struct
acpi_fan_fps
*
fps2
=
b
;
return
fps1
->
speed
-
fps2
->
speed
;
}
static
int
acpi_fan_get_fps
(
struct
acpi_device
*
device
)
{
struct
acpi_fan
*
fan
=
acpi_driver_data
(
device
);
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
obj
;
acpi_status
status
;
int
i
;
status
=
acpi_evaluate_object
(
device
->
handle
,
"_FPS"
,
NULL
,
&
buffer
);
if
(
ACPI_FAILURE
(
status
))
return
status
;
obj
=
buffer
.
pointer
;
if
(
!
obj
||
obj
->
type
!=
ACPI_TYPE_PACKAGE
||
obj
->
package
.
count
<
2
)
{
dev_err
(
&
device
->
dev
,
"Invalid _FPS data
\n
"
);
status
=
-
EINVAL
;
goto
err
;
}
fan
->
fps_count
=
obj
->
package
.
count
-
1
;
/* minus revision field */
fan
->
fps
=
devm_kzalloc
(
&
device
->
dev
,
fan
->
fps_count
*
sizeof
(
struct
acpi_fan_fps
),
GFP_KERNEL
);
if
(
!
fan
->
fps
)
{
dev_err
(
&
device
->
dev
,
"Not enough memory
\n
"
);
status
=
-
ENOMEM
;
goto
err
;
}
for
(
i
=
0
;
i
<
fan
->
fps_count
;
i
++
)
{
struct
acpi_buffer
format
=
{
sizeof
(
"NNNNN"
),
"NNNNN"
};
struct
acpi_buffer
fps
=
{
sizeof
(
fan
->
fps
[
i
]),
&
fan
->
fps
[
i
]
};
status
=
acpi_extract_package
(
&
obj
->
package
.
elements
[
i
+
1
],
&
format
,
&
fps
);
if
(
ACPI_FAILURE
(
status
))
{
dev_err
(
&
device
->
dev
,
"Invalid _FPS element
\n
"
);
break
;
}
}
/* sort the state array according to fan speed in increase order */
sort
(
fan
->
fps
,
fan
->
fps_count
,
sizeof
(
*
fan
->
fps
),
acpi_fan_speed_cmp
,
NULL
);
err:
kfree
(
obj
);
return
status
;
}
static
int
acpi_fan_probe
(
struct
platform_device
*
pdev
)
{
int
result
=
0
;
struct
thermal_cooling_device
*
cdev
;
struct
acpi_fan
*
fan
;
struct
acpi_device
*
device
=
ACPI_COMPANION
(
&
pdev
->
dev
);
fan
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
fan
),
GFP_KERNEL
);
if
(
!
fan
)
{
dev_err
(
&
device
->
dev
,
"No memory for fan
\n
"
);
return
-
ENOMEM
;
}
device
->
driver_data
=
fan
;
platform_set_drvdata
(
pdev
,
fan
);
if
(
acpi_fan_is_acpi4
(
device
))
{
if
(
acpi_fan_get_fif
(
device
)
||
acpi_fan_get_fps
(
device
))
goto
end
;
fan
->
acpi4
=
true
;
}
else
{
result
=
acpi_device_update_power
(
device
,
NULL
);
if
(
result
)
{
dev_err
(
&
device
->
dev
,
"Setting initial power state
\n
"
);
goto
end
;
}
}
cdev
=
thermal_cooling_device_register
(
"Fan"
,
device
,
...
...
@@ -154,45 +352,34 @@ static int acpi_fan_add(struct acpi_device *device)
goto
end
;
}
dev_dbg
(
&
device
->
dev
,
"registered as cooling_device%d
\n
"
,
cdev
->
id
);
dev_dbg
(
&
pdev
->
dev
,
"registered as cooling_device%d
\n
"
,
cdev
->
id
);
device
->
driver_data
=
cdev
;
result
=
sysfs_create_link
(
&
device
->
dev
.
kobj
,
fan
->
cdev
=
cdev
;
result
=
sysfs_create_link
(
&
pdev
->
dev
.
kobj
,
&
cdev
->
device
.
kobj
,
"thermal_cooling"
);
if
(
result
)
dev_err
(
&
device
->
dev
,
"Failed to create sysfs link "
dev_err
(
&
pdev
->
dev
,
"Failed to create sysfs link "
"'thermal_cooling'
\n
"
);
result
=
sysfs_create_link
(
&
cdev
->
device
.
kobj
,
&
device
->
dev
.
kobj
,
&
pdev
->
dev
.
kobj
,
"device"
);
if
(
result
)
dev_err
(
&
device
->
dev
,
"Failed to create sysfs link "
dev_err
(
&
pdev
->
dev
,
"Failed to create sysfs link "
"'device'
\n
"
);
printk
(
KERN_INFO
PREFIX
"%s [%s] (%s)
\n
"
,
acpi_device_name
(
device
),
acpi_device_bid
(
device
),
!
device
->
power
.
state
?
"on"
:
"off"
);
end:
return
result
;
}
static
int
acpi_fan_remove
(
struct
acpi_device
*
device
)
static
int
acpi_fan_remove
(
struct
platform_device
*
pdev
)
{
struct
thermal_cooling_device
*
cdev
;
if
(
!
device
)
return
-
EINVAL
;
cdev
=
acpi_driver_data
(
device
);
if
(
!
cdev
)
return
-
EINVAL
;
struct
acpi_fan
*
fan
=
platform_get_drvdata
(
pdev
);
sysfs_remove_link
(
&
device
->
dev
.
kobj
,
"thermal_cooling"
);
sysfs_remove_link
(
&
cdev
->
device
.
kobj
,
"device"
);
thermal_cooling_device_unregister
(
cdev
);
sysfs_remove_link
(
&
pdev
->
dev
.
kobj
,
"thermal_cooling"
);
sysfs_remove_link
(
&
fan
->
cdev
->
device
.
kobj
,
"device"
);
thermal_cooling_device_unregister
(
fan
->
cdev
);
return
0
;
}
...
...
@@ -200,10 +387,11 @@ static int acpi_fan_remove(struct acpi_device *device)
#ifdef CONFIG_PM_SLEEP
static
int
acpi_fan_suspend
(
struct
device
*
dev
)
{
if
(
!
dev
)
return
-
EINVAL
;
struct
acpi_fan
*
fan
=
dev_get_drvdata
(
dev
);
if
(
fan
->
acpi4
)
return
0
;
acpi_
bus_set_power
(
to_acpi_device
(
dev
)
->
handle
,
ACPI_STATE_D0
);
acpi_
device_set_power
(
ACPI_COMPANION
(
dev
)
,
ACPI_STATE_D0
);
return
AE_OK
;
}
...
...
@@ -211,16 +399,17 @@ static int acpi_fan_suspend(struct device *dev)
static
int
acpi_fan_resume
(
struct
device
*
dev
)
{
int
result
;
struct
acpi_fan
*
fan
=
dev_get_drvdata
(
dev
);
if
(
!
dev
)
return
-
EINVAL
;
if
(
fan
->
acpi4
)
return
0
;
result
=
acpi_
bus_update_power
(
to_acpi_device
(
dev
)
->
handle
,
NULL
);
result
=
acpi_
device_update_power
(
ACPI_COMPANION
(
dev
)
,
NULL
);
if
(
result
)
printk
(
KERN_ERR
PREFIX
"Error updating fan power state
\n
"
);
dev_err
(
dev
,
"Error updating fan power state
\n
"
);
return
result
;
}
#endif
module_
acpi
_driver
(
acpi_fan_driver
);
module_
platform
_driver
(
acpi_fan_driver
);
drivers/acpi/int340x_thermal.c
0 → 100644
View file @
6ceaf58a
/*
* ACPI support for int340x thermal drivers
*
* Copyright (C) 2014, Intel Corporation
* Authors: Zhang Rui <rui.zhang@intel.com>
*
* 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 <linux/acpi.h>
#include <linux/module.h>
#include "internal.h"
#define DO_ENUMERATION 0x01
static
const
struct
acpi_device_id
int340x_thermal_device_ids
[]
=
{
{
"INT3400"
,
DO_ENUMERATION
},
{
"INT3401"
},
{
"INT3402"
},
{
"INT3403"
},
{
"INT3404"
},
{
"INT3406"
},
{
"INT3407"
},
{
"INT3408"
},
{
"INT3409"
},
{
"INT340A"
},
{
"INT340B"
},
{
""
},
};
static
int
int340x_thermal_handler_attach
(
struct
acpi_device
*
adev
,
const
struct
acpi_device_id
*
id
)
{
#if defined(CONFIG_INT340X_THERMAL) || defined(CONFIG_INT340X_THERMAL_MODULE)
if
(
id
->
driver_data
==
DO_ENUMERATION
)
acpi_create_platform_device
(
adev
);
#endif
return
1
;
}
static
struct
acpi_scan_handler
int340x_thermal_handler
=
{
.
ids
=
int340x_thermal_device_ids
,
.
attach
=
int340x_thermal_handler_attach
,
};
void
__init
acpi_int340x_thermal_init
(
void
)
{
acpi_scan_add_handler
(
&
int340x_thermal_handler
);
}
drivers/acpi/internal.h
View file @
6ceaf58a
...
...
@@ -31,6 +31,7 @@ void acpi_pci_link_init(void);
void
acpi_processor_init
(
void
);
void
acpi_platform_init
(
void
);
void
acpi_pnp_init
(
void
);
void
acpi_int340x_thermal_init
(
void
);
int
acpi_sysfs_init
(
void
);
void
acpi_container_init
(
void
);
void
acpi_memory_hotplug_init
(
void
);
...
...
@@ -103,8 +104,6 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
int
acpi_power_on_resources
(
struct
acpi_device
*
device
,
int
state
);
int
acpi_power_transition
(
struct
acpi_device
*
device
,
int
state
);
int
acpi_device_update_power
(
struct
acpi_device
*
device
,
int
*
state_p
);
int
acpi_wakeup_device_init
(
void
);
#ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC
...
...
@@ -167,13 +166,6 @@ static inline int suspend_nvs_save(void) { return 0; }
static
inline
void
suspend_nvs_restore
(
void
)
{}
#endif
/*--------------------------------------------------------------------------
Platform bus support
-------------------------------------------------------------------------- */
struct
platform_device
;
struct
platform_device
*
acpi_create_platform_device
(
struct
acpi_device
*
adev
);
/*--------------------------------------------------------------------------
Video
-------------------------------------------------------------------------- */
...
...
drivers/acpi/scan.c
View file @
6ceaf58a
...
...
@@ -2306,6 +2306,7 @@ int __init acpi_scan_init(void)
acpi_container_init
();
acpi_memory_hotplug_init
();
acpi_pnp_init
();
acpi_int340x_thermal_init
();
mutex_lock
(
&
acpi_scan_lock
);
/*
...
...
drivers/acpi/thermal.c
View file @
6ceaf58a
...
...
@@ -528,7 +528,6 @@ static void acpi_thermal_check(void *data)
}
/* sys I/F for generic thermal sysfs support */
#define KELVIN_TO_MILLICELSIUS(t, off) (((t) - (off)) * 100)
static
int
thermal_get_temp
(
struct
thermal_zone_device
*
thermal
,
unsigned
long
*
temp
)
...
...
@@ -543,7 +542,8 @@ static int thermal_get_temp(struct thermal_zone_device *thermal,
if
(
result
)
return
result
;
*
temp
=
KELVIN_TO_MILLICELSIUS
(
tz
->
temperature
,
tz
->
kelvin_offset
);
*
temp
=
DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET
(
tz
->
temperature
,
tz
->
kelvin_offset
);
return
0
;
}
...
...
@@ -647,7 +647,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
if
(
tz
->
trips
.
critical
.
flags
.
valid
)
{
if
(
!
trip
)
{
*
temp
=
KELVIN_TO_MILLICELSIUS
(
*
temp
=
DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET
(
tz
->
trips
.
critical
.
temperature
,
tz
->
kelvin_offset
);
return
0
;
...
...
@@ -657,7 +657,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
if
(
tz
->
trips
.
hot
.
flags
.
valid
)
{
if
(
!
trip
)
{
*
temp
=
KELVIN_TO_MILLICELSIUS
(
*
temp
=
DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET
(
tz
->
trips
.
hot
.
temperature
,
tz
->
kelvin_offset
);
return
0
;
...
...
@@ -667,7 +667,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
if
(
tz
->
trips
.
passive
.
flags
.
valid
)
{
if
(
!
trip
)
{
*
temp
=
KELVIN_TO_MILLICELSIUS
(
*
temp
=
DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET
(
tz
->
trips
.
passive
.
temperature
,
tz
->
kelvin_offset
);
return
0
;
...
...
@@ -678,7 +678,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
for
(
i
=
0
;
i
<
ACPI_THERMAL_MAX_ACTIVE
&&
tz
->
trips
.
active
[
i
].
flags
.
valid
;
i
++
)
{
if
(
!
trip
)
{
*
temp
=
KELVIN_TO_MILLICELSIUS
(
*
temp
=
DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET
(
tz
->
trips
.
active
[
i
].
temperature
,
tz
->
kelvin_offset
);
return
0
;
...
...
@@ -694,7 +694,7 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
struct
acpi_thermal
*
tz
=
thermal
->
devdata
;
if
(
tz
->
trips
.
critical
.
flags
.
valid
)
{
*
temperature
=
KELVIN_TO_MILLICELSIUS
(
*
temperature
=
DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET
(
tz
->
trips
.
critical
.
temperature
,
tz
->
kelvin_offset
);
return
0
;
...
...
@@ -714,8 +714,8 @@ static int thermal_get_trend(struct thermal_zone_device *thermal,
if
(
type
==
THERMAL_TRIP_ACTIVE
)
{
unsigned
long
trip_temp
;
unsigned
long
temp
=
KELVIN_TO_MILLICELSIUS
(
tz
->
temperature
,
tz
->
kelvin_offset
);
unsigned
long
temp
=
DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET
(
tz
->
temperature
,
tz
->
kelvin_offset
);
if
(
thermal_get_trip_temp
(
thermal
,
trip
,
&
trip_temp
))
return
-
EINVAL
;
...
...
drivers/acpi/utils.c
View file @
6ceaf58a
...
...
@@ -149,6 +149,21 @@ acpi_extract_package(union acpi_object *package,
break
;
}
break
;
case
ACPI_TYPE_LOCAL_REFERENCE
:
switch
(
format_string
[
i
])
{
case
'R'
:
size_required
+=
sizeof
(
void
*
);
tail_offset
+=
sizeof
(
void
*
);
break
;
default:
printk
(
KERN_WARNING
PREFIX
"Invalid package element"
" [%d] got reference,"
" expecting [%c]
\n
"
,
i
,
format_string
[
i
]);
return
AE_BAD_DATA
;
break
;
}
break
;
case
ACPI_TYPE_PACKAGE
:
default:
...
...
@@ -247,7 +262,18 @@ acpi_extract_package(union acpi_object *package,
break
;
}
break
;
case
ACPI_TYPE_LOCAL_REFERENCE
:
switch
(
format_string
[
i
])
{
case
'R'
:
*
(
void
**
)
head
=
(
void
*
)
element
->
reference
.
handle
;
head
+=
sizeof
(
void
*
);
break
;
default:
/* Should never get here */
break
;
}
break
;
case
ACPI_TYPE_PACKAGE
:
/* TBD: handle nested packages... */
default:
...
...
drivers/thermal/Kconfig
View file @
6ceaf58a
...
...
@@ -217,21 +217,6 @@ config X86_PKG_TEMP_THERMAL
two trip points which can be set by user to get notifications via thermal
notification methods.
config ACPI_INT3403_THERMAL
tristate "ACPI INT3403 thermal driver"
depends on X86 && ACPI
help
Newer laptops and tablets that use ACPI may have thermal sensors
outside the core CPU/SOC for thermal safety reasons. These
temperature sensors are also exposed for the OS to use via the so
called INT3403 ACPI object. This driver will, on devices that have
such sensors, expose the temperature information from these sensors
to userspace via the normal thermal framework. This means that a wide
range of applications and GUI widgets can show this information to
the user or use this information for making decisions. For example,
the Intel Thermal Daemon can use this information to allow the user
to select his laptop to run without turning on the fans.
config INTEL_SOC_DTS_THERMAL
tristate "Intel SoCs DTS thermal driver"
depends on X86 && IOSF_MBI
...
...
@@ -244,6 +229,30 @@ config INTEL_SOC_DTS_THERMAL
notification methods.The other trip is a critical trip point, which
was set by the driver based on the TJ MAX temperature.
config INT340X_THERMAL
tristate "ACPI INT340X thermal drivers"
depends on X86 && ACPI
select THERMAL_GOV_USER_SPACE
select ACPI_THERMAL_REL
select ACPI_FAN
help
Newer laptops and tablets that use ACPI may have thermal sensors and
other devices with thermal control capabilities outside the core
CPU/SOC, for thermal safety reasons.
They are exposed for the OS to use via the INT3400 ACPI device object
as the master, and INT3401~INT340B ACPI device objects as the slaves.
Enable this to expose the temperature information and cooling ability
from these objects to userspace via the normal thermal framework.
This means that a wide range of applications and GUI widgets can show
the information to the user or use this information for making
decisions. For example, the Intel Thermal Daemon can use this
information to allow the user to select his laptop to run without
turning on the fans.
config ACPI_THERMAL_REL
tristate
depends on ACPI
menu "Texas Instruments thermal drivers"
source "drivers/thermal/ti-soc-thermal/Kconfig"
endmenu
...
...
drivers/thermal/Makefile
View file @
6ceaf58a
...
...
@@ -32,5 +32,5 @@ obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
obj-$(CONFIG_X86_PKG_TEMP_THERMAL)
+=
x86_pkg_temp_thermal.o
obj-$(CONFIG_INTEL_SOC_DTS_THERMAL)
+=
intel_soc_dts_thermal.o
obj-$(CONFIG_TI_SOC_THERMAL)
+=
ti-soc-thermal/
obj-$(CONFIG_
ACPI_INT3403_THERMAL)
+=
int3403_thermal.o
obj-$(CONFIG_
INT340X_THERMAL)
+=
int340x_thermal/
obj-$(CONFIG_ST_THERMAL)
+=
st/
drivers/thermal/int340x_thermal/Makefile
0 → 100644
View file @
6ceaf58a
obj-$(CONFIG_INT340X_THERMAL)
+=
int3400_thermal.o
obj-$(CONFIG_INT340X_THERMAL)
+=
int3402_thermal.o
obj-$(CONFIG_INT340X_THERMAL)
+=
int3403_thermal.o
obj-$(CONFIG_ACPI_THERMAL_REL)
+=
acpi_thermal_rel.o
drivers/thermal/int340x_thermal/acpi_thermal_rel.c
0 → 100644
View file @
6ceaf58a
/* acpi_thermal_rel.c driver for exporting ACPI thermal relationship
*
* Copyright (c) 2014 Intel Corp
*
* 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.
*
*/
/*
* Two functionalities included:
* 1. Export _TRT, _ART, via misc device interface to the userspace.
* 2. Provide parsing result to kernel drivers
*
*/
#include <linux/init.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/acpi.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include "acpi_thermal_rel.h"
static
acpi_handle
acpi_thermal_rel_handle
;
static
DEFINE_SPINLOCK
(
acpi_thermal_rel_chrdev_lock
);
static
int
acpi_thermal_rel_chrdev_count
;
/* #times opened */
static
int
acpi_thermal_rel_chrdev_exclu
;
/* already open exclusive? */
static
int
acpi_thermal_rel_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
spin_lock
(
&
acpi_thermal_rel_chrdev_lock
);
if
(
acpi_thermal_rel_chrdev_exclu
||
(
acpi_thermal_rel_chrdev_count
&&
(
file
->
f_flags
&
O_EXCL
)))
{
spin_unlock
(
&
acpi_thermal_rel_chrdev_lock
);
return
-
EBUSY
;
}
if
(
file
->
f_flags
&
O_EXCL
)
acpi_thermal_rel_chrdev_exclu
=
1
;
acpi_thermal_rel_chrdev_count
++
;
spin_unlock
(
&
acpi_thermal_rel_chrdev_lock
);
return
nonseekable_open
(
inode
,
file
);
}
static
int
acpi_thermal_rel_release
(
struct
inode
*
inode
,
struct
file
*
file
)
{
spin_lock
(
&
acpi_thermal_rel_chrdev_lock
);
acpi_thermal_rel_chrdev_count
--
;
acpi_thermal_rel_chrdev_exclu
=
0
;
spin_unlock
(
&
acpi_thermal_rel_chrdev_lock
);
return
0
;
}
/**
* acpi_parse_trt - Thermal Relationship Table _TRT for passive cooling
*
* @handle: ACPI handle of the device contains _TRT
* @art_count: the number of valid entries resulted from parsing _TRT
* @artp: pointer to pointer of array of art entries in parsing result
* @create_dev: whether to create platform devices for target and source
*
*/
int
acpi_parse_trt
(
acpi_handle
handle
,
int
*
trt_count
,
struct
trt
**
trtp
,
bool
create_dev
)
{
acpi_status
status
;
int
result
=
0
;
int
i
;
int
nr_bad_entries
=
0
;
struct
trt
*
trts
;
struct
acpi_device
*
adev
;
union
acpi_object
*
p
;
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
struct
acpi_buffer
element
=
{
0
,
NULL
};
struct
acpi_buffer
trt_format
=
{
sizeof
(
"RRNNNNNN"
),
"RRNNNNNN"
};
if
(
!
acpi_has_method
(
handle
,
"_TRT"
))
return
0
;
status
=
acpi_evaluate_object
(
handle
,
"_TRT"
,
NULL
,
&
buffer
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
p
=
buffer
.
pointer
;
if
(
!
p
||
(
p
->
type
!=
ACPI_TYPE_PACKAGE
))
{
pr_err
(
"Invalid _TRT data
\n
"
);
result
=
-
EFAULT
;
goto
end
;
}
*
trt_count
=
p
->
package
.
count
;
trts
=
kzalloc
(
*
trt_count
*
sizeof
(
struct
trt
),
GFP_KERNEL
);
if
(
!
trts
)
{
result
=
-
ENOMEM
;
goto
end
;
}
for
(
i
=
0
;
i
<
*
trt_count
;
i
++
)
{
struct
trt
*
trt
=
&
trts
[
i
-
nr_bad_entries
];
element
.
length
=
sizeof
(
struct
trt
);
element
.
pointer
=
trt
;
status
=
acpi_extract_package
(
&
(
p
->
package
.
elements
[
i
]),
&
trt_format
,
&
element
);
if
(
ACPI_FAILURE
(
status
))
{
nr_bad_entries
++
;
pr_warn
(
"_TRT package %d is invalid, ignored
\n
"
,
i
);
continue
;
}
if
(
!
create_dev
)
continue
;
result
=
acpi_bus_get_device
(
trt
->
source
,
&
adev
);
if
(
!
result
)
acpi_create_platform_device
(
adev
);
else
pr_warn
(
"Failed to get source ACPI device
\n
"
);
result
=
acpi_bus_get_device
(
trt
->
target
,
&
adev
);
if
(
!
result
)
acpi_create_platform_device
(
adev
);
else
pr_warn
(
"Failed to get target ACPI device
\n
"
);
}
*
trtp
=
trts
;
/* don't count bad entries */
*
trt_count
-=
nr_bad_entries
;
end:
kfree
(
buffer
.
pointer
);
return
result
;
}
EXPORT_SYMBOL
(
acpi_parse_trt
);
/**
* acpi_parse_art - Parse Active Relationship Table _ART
*
* @handle: ACPI handle of the device contains _ART
* @art_count: the number of valid entries resulted from parsing _ART
* @artp: pointer to pointer of array of art entries in parsing result
* @create_dev: whether to create platform devices for target and source
*
*/
int
acpi_parse_art
(
acpi_handle
handle
,
int
*
art_count
,
struct
art
**
artp
,
bool
create_dev
)
{
acpi_status
status
;
int
result
=
0
;
int
i
;
int
nr_bad_entries
=
0
;
struct
art
*
arts
;
struct
acpi_device
*
adev
;
union
acpi_object
*
p
;
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
struct
acpi_buffer
element
=
{
0
,
NULL
};
struct
acpi_buffer
art_format
=
{
sizeof
(
"RRNNNNNNNNNNN"
),
"RRNNNNNNNNNNN"
};
if
(
!
acpi_has_method
(
handle
,
"_ART"
))
return
0
;
status
=
acpi_evaluate_object
(
handle
,
"_ART"
,
NULL
,
&
buffer
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
p
=
buffer
.
pointer
;
if
(
!
p
||
(
p
->
type
!=
ACPI_TYPE_PACKAGE
))
{
pr_err
(
"Invalid _ART data
\n
"
);
result
=
-
EFAULT
;
goto
end
;
}
/* ignore p->package.elements[0], as this is _ART Revision field */
*
art_count
=
p
->
package
.
count
-
1
;
arts
=
kzalloc
(
*
art_count
*
sizeof
(
struct
art
),
GFP_KERNEL
);
if
(
!
arts
)
{
result
=
-
ENOMEM
;
goto
end
;
}
for
(
i
=
0
;
i
<
*
art_count
;
i
++
)
{
struct
art
*
art
=
&
arts
[
i
-
nr_bad_entries
];
element
.
length
=
sizeof
(
struct
art
);
element
.
pointer
=
art
;
status
=
acpi_extract_package
(
&
(
p
->
package
.
elements
[
i
+
1
]),
&
art_format
,
&
element
);
if
(
ACPI_FAILURE
(
status
))
{
pr_warn
(
"_ART package %d is invalid, ignored"
,
i
);
nr_bad_entries
++
;
continue
;
}
if
(
!
create_dev
)
continue
;
if
(
art
->
source
)
{
result
=
acpi_bus_get_device
(
art
->
source
,
&
adev
);
if
(
!
result
)
acpi_create_platform_device
(
adev
);
else
pr_warn
(
"Failed to get source ACPI device
\n
"
);
}
if
(
art
->
target
)
{
result
=
acpi_bus_get_device
(
art
->
target
,
&
adev
);
if
(
!
result
)
acpi_create_platform_device
(
adev
);
else
pr_warn
(
"Failed to get source ACPI device
\n
"
);
}
}
*
artp
=
arts
;
/* don't count bad entries */
*
art_count
-=
nr_bad_entries
;
end:
kfree
(
buffer
.
pointer
);
return
result
;
}
EXPORT_SYMBOL
(
acpi_parse_art
);
/* get device name from acpi handle */
static
void
get_single_name
(
acpi_handle
handle
,
char
*
name
)
{
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
};
if
(
ACPI_FAILURE
(
acpi_get_name
(
handle
,
ACPI_SINGLE_NAME
,
&
buffer
)))
pr_warn
(
"Failed get name from handle
\n
"
);
else
{
memcpy
(
name
,
buffer
.
pointer
,
ACPI_NAME_SIZE
);
kfree
(
buffer
.
pointer
);
}
}
static
int
fill_art
(
char
__user
*
ubuf
)
{
int
i
;
int
ret
;
int
count
;
int
art_len
;
struct
art
*
arts
=
NULL
;
union
art_object
*
art_user
;
ret
=
acpi_parse_art
(
acpi_thermal_rel_handle
,
&
count
,
&
arts
,
false
);
if
(
ret
)
goto
free_art
;
art_len
=
count
*
sizeof
(
union
art_object
);
art_user
=
kzalloc
(
art_len
,
GFP_KERNEL
);
if
(
!
art_user
)
{
ret
=
-
ENOMEM
;
goto
free_art
;
}
/* now fill in user art data */
for
(
i
=
0
;
i
<
count
;
i
++
)
{
/* userspace art needs device name instead of acpi reference */
get_single_name
(
arts
[
i
].
source
,
art_user
[
i
].
source_device
);
get_single_name
(
arts
[
i
].
target
,
art_user
[
i
].
target_device
);
/* copy the rest int data in addition to source and target */
memcpy
(
&
art_user
[
i
].
weight
,
&
arts
[
i
].
weight
,
sizeof
(
u64
)
*
(
ACPI_NR_ART_ELEMENTS
-
2
));
}
if
(
copy_to_user
(
ubuf
,
art_user
,
art_len
))
ret
=
-
EFAULT
;
kfree
(
art_user
);
free_art:
kfree
(
arts
);
return
ret
;
}
static
int
fill_trt
(
char
__user
*
ubuf
)
{
int
i
;
int
ret
;
int
count
;
int
trt_len
;
struct
trt
*
trts
=
NULL
;
union
trt_object
*
trt_user
;
ret
=
acpi_parse_trt
(
acpi_thermal_rel_handle
,
&
count
,
&
trts
,
false
);
if
(
ret
)
goto
free_trt
;
trt_len
=
count
*
sizeof
(
union
trt_object
);
trt_user
=
kzalloc
(
trt_len
,
GFP_KERNEL
);
if
(
!
trt_user
)
{
ret
=
-
ENOMEM
;
goto
free_trt
;
}
/* now fill in user trt data */
for
(
i
=
0
;
i
<
count
;
i
++
)
{
/* userspace trt needs device name instead of acpi reference */
get_single_name
(
trts
[
i
].
source
,
trt_user
[
i
].
source_device
);
get_single_name
(
trts
[
i
].
target
,
trt_user
[
i
].
target_device
);
trt_user
[
i
].
sample_period
=
trts
[
i
].
sample_period
;
trt_user
[
i
].
influence
=
trts
[
i
].
influence
;
}
if
(
copy_to_user
(
ubuf
,
trt_user
,
trt_len
))
ret
=
-
EFAULT
;
kfree
(
trt_user
);
free_trt:
kfree
(
trts
);
return
ret
;
}
static
long
acpi_thermal_rel_ioctl
(
struct
file
*
f
,
unsigned
int
cmd
,
unsigned
long
__arg
)
{
int
ret
=
0
;
unsigned
long
length
=
0
;
unsigned
long
count
=
0
;
char
__user
*
arg
=
(
void
__user
*
)
__arg
;
struct
trt
*
trts
;
struct
art
*
arts
;
switch
(
cmd
)
{
case
ACPI_THERMAL_GET_TRT_COUNT
:
ret
=
acpi_parse_trt
(
acpi_thermal_rel_handle
,
(
int
*
)
&
count
,
&
trts
,
false
);
kfree
(
trts
);
if
(
!
ret
)
return
put_user
(
count
,
(
unsigned
long
__user
*
)
__arg
);
return
ret
;
case
ACPI_THERMAL_GET_TRT_LEN
:
ret
=
acpi_parse_trt
(
acpi_thermal_rel_handle
,
(
int
*
)
&
count
,
&
trts
,
false
);
kfree
(
trts
);
length
=
count
*
sizeof
(
union
trt_object
);
if
(
!
ret
)
return
put_user
(
length
,
(
unsigned
long
__user
*
)
__arg
);
return
ret
;
case
ACPI_THERMAL_GET_TRT
:
return
fill_trt
(
arg
);
case
ACPI_THERMAL_GET_ART_COUNT
:
ret
=
acpi_parse_art
(
acpi_thermal_rel_handle
,
(
int
*
)
&
count
,
&
arts
,
false
);
kfree
(
arts
);
if
(
!
ret
)
return
put_user
(
count
,
(
unsigned
long
__user
*
)
__arg
);
return
ret
;
case
ACPI_THERMAL_GET_ART_LEN
:
ret
=
acpi_parse_art
(
acpi_thermal_rel_handle
,
(
int
*
)
&
count
,
&
arts
,
false
);
kfree
(
arts
);
length
=
count
*
sizeof
(
union
art_object
);
if
(
!
ret
)
return
put_user
(
length
,
(
unsigned
long
__user
*
)
__arg
);
return
ret
;
case
ACPI_THERMAL_GET_ART
:
return
fill_art
(
arg
);
default:
return
-
ENOTTY
;
}
}
static
const
struct
file_operations
acpi_thermal_rel_fops
=
{
.
owner
=
THIS_MODULE
,
.
open
=
acpi_thermal_rel_open
,
.
release
=
acpi_thermal_rel_release
,
.
unlocked_ioctl
=
acpi_thermal_rel_ioctl
,
.
llseek
=
no_llseek
,
};
static
struct
miscdevice
acpi_thermal_rel_misc_device
=
{
.
minor
=
MISC_DYNAMIC_MINOR
,
"acpi_thermal_rel"
,
&
acpi_thermal_rel_fops
};
int
acpi_thermal_rel_misc_device_add
(
acpi_handle
handle
)
{
acpi_thermal_rel_handle
=
handle
;
return
misc_register
(
&
acpi_thermal_rel_misc_device
);
}
EXPORT_SYMBOL
(
acpi_thermal_rel_misc_device_add
);
int
acpi_thermal_rel_misc_device_remove
(
acpi_handle
handle
)
{
misc_deregister
(
&
acpi_thermal_rel_misc_device
);
return
0
;
}
EXPORT_SYMBOL
(
acpi_thermal_rel_misc_device_remove
);
MODULE_AUTHOR
(
"Zhang Rui <rui.zhang@intel.com>"
);
MODULE_AUTHOR
(
"Jacob Pan <jacob.jun.pan@intel.com"
);
MODULE_DESCRIPTION
(
"Intel acpi thermal rel misc dev driver"
);
MODULE_LICENSE
(
"GPL v2"
);
drivers/thermal/int340x_thermal/acpi_thermal_rel.h
0 → 100644
View file @
6ceaf58a
#ifndef __ACPI_ACPI_THERMAL_H
#define __ACPI_ACPI_THERMAL_H
#include <asm/ioctl.h>
#define ACPI_THERMAL_MAGIC 's'
#define ACPI_THERMAL_GET_TRT_LEN _IOR(ACPI_THERMAL_MAGIC, 1, unsigned long)
#define ACPI_THERMAL_GET_ART_LEN _IOR(ACPI_THERMAL_MAGIC, 2, unsigned long)
#define ACPI_THERMAL_GET_TRT_COUNT _IOR(ACPI_THERMAL_MAGIC, 3, unsigned long)
#define ACPI_THERMAL_GET_ART_COUNT _IOR(ACPI_THERMAL_MAGIC, 4, unsigned long)
#define ACPI_THERMAL_GET_TRT _IOR(ACPI_THERMAL_MAGIC, 5, unsigned long)
#define ACPI_THERMAL_GET_ART _IOR(ACPI_THERMAL_MAGIC, 6, unsigned long)
struct
art
{
acpi_handle
source
;
acpi_handle
target
;
u64
weight
;
u64
ac0_max
;
u64
ac1_max
;
u64
ac2_max
;
u64
ac3_max
;
u64
ac4_max
;
u64
ac5_max
;
u64
ac6_max
;
u64
ac7_max
;
u64
ac8_max
;
u64
ac9_max
;
}
__packed
;
struct
trt
{
acpi_handle
source
;
acpi_handle
target
;
u64
influence
;
u64
sample_period
;
u64
reverved1
;
u64
reverved2
;
u64
reverved3
;
u64
reverved4
;
}
__packed
;
#define ACPI_NR_ART_ELEMENTS 13
/* for usrspace */
union
art_object
{
struct
{
char
source_device
[
8
];
/* ACPI single name */
char
target_device
[
8
];
/* ACPI single name */
u64
weight
;
u64
ac0_max_level
;
u64
ac1_max_level
;
u64
ac2_max_level
;
u64
ac3_max_level
;
u64
ac4_max_level
;
u64
ac5_max_level
;
u64
ac6_max_level
;
u64
ac7_max_level
;
u64
ac8_max_level
;
u64
ac9_max_level
;
};
u64
__data
[
ACPI_NR_ART_ELEMENTS
];
};
union
trt_object
{
struct
{
char
source_device
[
8
];
/* ACPI single name */
char
target_device
[
8
];
/* ACPI single name */
u64
influence
;
u64
sample_period
;
u64
reserved
[
4
];
};
u64
__data
[
8
];
};
#ifdef __KERNEL__
int
acpi_thermal_rel_misc_device_add
(
acpi_handle
handle
);
int
acpi_thermal_rel_misc_device_remove
(
acpi_handle
handle
);
int
acpi_parse_art
(
acpi_handle
handle
,
int
*
art_count
,
struct
art
**
arts
,
bool
create_dev
);
int
acpi_parse_trt
(
acpi_handle
handle
,
int
*
trt_count
,
struct
trt
**
trts
,
bool
create_dev
);
#endif
#endif
/* __ACPI_ACPI_THERMAL_H */
drivers/thermal/int340x_thermal/int3400_thermal.c
0 → 100644
View file @
6ceaf58a
/*
* INT3400 thermal driver
*
* Copyright (C) 2014, Intel Corporation
* Authors: Zhang Rui <rui.zhang@intel.com>
*
* 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 <linux/module.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/thermal.h>
#include "acpi_thermal_rel.h"
enum
int3400_thermal_uuid
{
INT3400_THERMAL_PASSIVE_1
,
INT3400_THERMAL_PASSIVE_2
,
INT3400_THERMAL_ACTIVE
,
INT3400_THERMAL_CRITICAL
,
INT3400_THERMAL_COOLING_MODE
,
INT3400_THERMAL_MAXIMUM_UUID
,
};
static
u8
*
int3400_thermal_uuids
[
INT3400_THERMAL_MAXIMUM_UUID
]
=
{
"42A441D6-AE6A-462b-A84B-4A8CE79027D3"
,
"9E04115A-AE87-4D1C-9500-0F3E340BFE75"
,
"3A95C389-E4B8-4629-A526-C52C88626BAE"
,
"97C68AE7-15FA-499c-B8C9-5DA81D606E0A"
,
"16CAF1B7-DD38-40ed-B1C1-1B8A1913D531"
,
};
struct
int3400_thermal_priv
{
struct
acpi_device
*
adev
;
struct
thermal_zone_device
*
thermal
;
int
mode
;
int
art_count
;
struct
art
*
arts
;
int
trt_count
;
struct
trt
*
trts
;
u8
uuid_bitmap
;
int
rel_misc_dev_res
;
};
static
int
int3400_thermal_get_uuids
(
struct
int3400_thermal_priv
*
priv
)
{
struct
acpi_buffer
buf
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
obja
,
*
objb
;
int
i
,
j
;
int
result
=
0
;
acpi_status
status
;
status
=
acpi_evaluate_object
(
priv
->
adev
->
handle
,
"IDSP"
,
NULL
,
&
buf
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
obja
=
(
union
acpi_object
*
)
buf
.
pointer
;
if
(
obja
->
type
!=
ACPI_TYPE_PACKAGE
)
{
result
=
-
EINVAL
;
goto
end
;
}
for
(
i
=
0
;
i
<
obja
->
package
.
count
;
i
++
)
{
objb
=
&
obja
->
package
.
elements
[
i
];
if
(
objb
->
type
!=
ACPI_TYPE_BUFFER
)
{
result
=
-
EINVAL
;
goto
end
;
}
/* UUID must be 16 bytes */
if
(
objb
->
buffer
.
length
!=
16
)
{
result
=
-
EINVAL
;
goto
end
;
}
for
(
j
=
0
;
j
<
INT3400_THERMAL_MAXIMUM_UUID
;
j
++
)
{
u8
uuid
[
16
];
acpi_str_to_uuid
(
int3400_thermal_uuids
[
j
],
uuid
);
if
(
!
strncmp
(
uuid
,
objb
->
buffer
.
pointer
,
16
))
{
priv
->
uuid_bitmap
|=
(
1
<<
j
);
break
;
}
}
}
end:
kfree
(
buf
.
pointer
);
return
result
;
}
static
int
int3400_thermal_run_osc
(
acpi_handle
handle
,
enum
int3400_thermal_uuid
uuid
,
bool
enable
)
{
u32
ret
,
buf
[
2
];
acpi_status
status
;
int
result
=
0
;
struct
acpi_osc_context
context
=
{
.
uuid_str
=
int3400_thermal_uuids
[
uuid
],
.
rev
=
1
,
.
cap
.
length
=
8
,
};
buf
[
OSC_QUERY_DWORD
]
=
0
;
buf
[
OSC_SUPPORT_DWORD
]
=
enable
;
context
.
cap
.
pointer
=
buf
;
status
=
acpi_run_osc
(
handle
,
&
context
);
if
(
ACPI_SUCCESS
(
status
))
{
ret
=
*
((
u32
*
)(
context
.
ret
.
pointer
+
4
));
if
(
ret
!=
enable
)
result
=
-
EPERM
;
}
else
result
=
-
EPERM
;
kfree
(
context
.
ret
.
pointer
);
return
result
;
}
static
int
int3400_thermal_get_temp
(
struct
thermal_zone_device
*
thermal
,
unsigned
long
*
temp
)
{
*
temp
=
20
*
1000
;
/* faked temp sensor with 20C */
return
0
;
}
static
int
int3400_thermal_get_mode
(
struct
thermal_zone_device
*
thermal
,
enum
thermal_device_mode
*
mode
)
{
struct
int3400_thermal_priv
*
priv
=
thermal
->
devdata
;
if
(
!
priv
)
return
-
EINVAL
;
*
mode
=
priv
->
mode
;
return
0
;
}
static
int
int3400_thermal_set_mode
(
struct
thermal_zone_device
*
thermal
,
enum
thermal_device_mode
mode
)
{
struct
int3400_thermal_priv
*
priv
=
thermal
->
devdata
;
bool
enable
;
int
result
=
0
;
if
(
!
priv
)
return
-
EINVAL
;
if
(
mode
==
THERMAL_DEVICE_ENABLED
)
enable
=
true
;
else
if
(
mode
==
THERMAL_DEVICE_DISABLED
)
enable
=
false
;
else
return
-
EINVAL
;
if
(
enable
!=
priv
->
mode
)
{
priv
->
mode
=
enable
;
/* currently, only PASSIVE COOLING is supported */
result
=
int3400_thermal_run_osc
(
priv
->
adev
->
handle
,
INT3400_THERMAL_PASSIVE_1
,
enable
);
}
return
result
;
}
static
struct
thermal_zone_device_ops
int3400_thermal_ops
=
{
.
get_temp
=
int3400_thermal_get_temp
,
};
static
struct
thermal_zone_params
int3400_thermal_params
=
{
.
governor_name
=
"user_space"
,
.
no_hwmon
=
true
,
};
static
int
int3400_thermal_probe
(
struct
platform_device
*
pdev
)
{
struct
acpi_device
*
adev
=
ACPI_COMPANION
(
&
pdev
->
dev
);
struct
int3400_thermal_priv
*
priv
;
int
result
;
if
(
!
adev
)
return
-
ENODEV
;
priv
=
kzalloc
(
sizeof
(
struct
int3400_thermal_priv
),
GFP_KERNEL
);
if
(
!
priv
)
return
-
ENOMEM
;
priv
->
adev
=
adev
;
result
=
int3400_thermal_get_uuids
(
priv
);
if
(
result
)
goto
free_priv
;
result
=
acpi_parse_art
(
priv
->
adev
->
handle
,
&
priv
->
art_count
,
&
priv
->
arts
,
true
);
if
(
result
)
goto
free_priv
;
result
=
acpi_parse_trt
(
priv
->
adev
->
handle
,
&
priv
->
trt_count
,
&
priv
->
trts
,
true
);
if
(
result
)
goto
free_art
;
platform_set_drvdata
(
pdev
,
priv
);
if
(
priv
->
uuid_bitmap
&
1
<<
INT3400_THERMAL_PASSIVE_1
)
{
int3400_thermal_ops
.
get_mode
=
int3400_thermal_get_mode
;
int3400_thermal_ops
.
set_mode
=
int3400_thermal_set_mode
;
}
priv
->
thermal
=
thermal_zone_device_register
(
"INT3400 Thermal"
,
0
,
0
,
priv
,
&
int3400_thermal_ops
,
&
int3400_thermal_params
,
0
,
0
);
if
(
IS_ERR
(
priv
->
thermal
))
{
result
=
PTR_ERR
(
priv
->
thermal
);
goto
free_trt
;
}
priv
->
rel_misc_dev_res
=
acpi_thermal_rel_misc_device_add
(
priv
->
adev
->
handle
);
return
0
;
free_trt:
kfree
(
priv
->
trts
);
free_art:
kfree
(
priv
->
arts
);
free_priv:
kfree
(
priv
);
return
result
;
}
static
int
int3400_thermal_remove
(
struct
platform_device
*
pdev
)
{
struct
int3400_thermal_priv
*
priv
=
platform_get_drvdata
(
pdev
);
if
(
!
priv
->
rel_misc_dev_res
)
acpi_thermal_rel_misc_device_remove
(
priv
->
adev
->
handle
);
thermal_zone_device_unregister
(
priv
->
thermal
);
kfree
(
priv
->
trts
);
kfree
(
priv
->
arts
);
kfree
(
priv
);
return
0
;
}
static
const
struct
acpi_device_id
int3400_thermal_match
[]
=
{
{
"INT3400"
,
0
},
{}
};
MODULE_DEVICE_TABLE
(
acpi
,
int3400_thermal_match
);
static
struct
platform_driver
int3400_thermal_driver
=
{
.
probe
=
int3400_thermal_probe
,
.
remove
=
int3400_thermal_remove
,
.
driver
=
{
.
name
=
"int3400 thermal"
,
.
owner
=
THIS_MODULE
,
.
acpi_match_table
=
ACPI_PTR
(
int3400_thermal_match
),
},
};
module_platform_driver
(
int3400_thermal_driver
);
MODULE_DESCRIPTION
(
"INT3400 Thermal driver"
);
MODULE_AUTHOR
(
"Zhang Rui <rui.zhang@intel.com>"
);
MODULE_LICENSE
(
"GPL"
);
drivers/thermal/int340x_thermal/int3402_thermal.c
0 → 100644
View file @
6ceaf58a
/*
* INT3402 thermal driver for memory temperature reporting
*
* Copyright (C) 2014, Intel Corporation
* Authors: Aaron Lu <aaron.lu@intel.com>
*
* 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 <linux/module.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/thermal.h>
#define ACPI_ACTIVE_COOLING_MAX_NR 10
struct
active_trip
{
unsigned
long
temp
;
int
id
;
bool
valid
;
};
struct
int3402_thermal_data
{
unsigned
long
*
aux_trips
;
int
aux_trip_nr
;
unsigned
long
psv_temp
;
int
psv_trip_id
;
unsigned
long
crt_temp
;
int
crt_trip_id
;
unsigned
long
hot_temp
;
int
hot_trip_id
;
struct
active_trip
act_trips
[
ACPI_ACTIVE_COOLING_MAX_NR
];
acpi_handle
*
handle
;
};
static
int
int3402_thermal_get_zone_temp
(
struct
thermal_zone_device
*
zone
,
unsigned
long
*
temp
)
{
struct
int3402_thermal_data
*
d
=
zone
->
devdata
;
unsigned
long
long
tmp
;
acpi_status
status
;
status
=
acpi_evaluate_integer
(
d
->
handle
,
"_TMP"
,
NULL
,
&
tmp
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
/* _TMP returns the temperature in tenths of degrees Kelvin */
*
temp
=
DECI_KELVIN_TO_MILLICELSIUS
(
tmp
);
return
0
;
}
static
int
int3402_thermal_get_trip_temp
(
struct
thermal_zone_device
*
zone
,
int
trip
,
unsigned
long
*
temp
)
{
struct
int3402_thermal_data
*
d
=
zone
->
devdata
;
int
i
;
if
(
trip
<
d
->
aux_trip_nr
)
*
temp
=
d
->
aux_trips
[
trip
];
else
if
(
trip
==
d
->
crt_trip_id
)
*
temp
=
d
->
crt_temp
;
else
if
(
trip
==
d
->
psv_trip_id
)
*
temp
=
d
->
psv_temp
;
else
if
(
trip
==
d
->
hot_trip_id
)
*
temp
=
d
->
hot_temp
;
else
{
for
(
i
=
0
;
i
<
ACPI_ACTIVE_COOLING_MAX_NR
;
i
++
)
{
if
(
d
->
act_trips
[
i
].
valid
&&
d
->
act_trips
[
i
].
id
==
trip
)
{
*
temp
=
d
->
act_trips
[
i
].
temp
;
break
;
}
}
if
(
i
==
ACPI_ACTIVE_COOLING_MAX_NR
)
return
-
EINVAL
;
}
return
0
;
}
static
int
int3402_thermal_get_trip_type
(
struct
thermal_zone_device
*
zone
,
int
trip
,
enum
thermal_trip_type
*
type
)
{
struct
int3402_thermal_data
*
d
=
zone
->
devdata
;
int
i
;
if
(
trip
<
d
->
aux_trip_nr
)
*
type
=
THERMAL_TRIP_PASSIVE
;
else
if
(
trip
==
d
->
crt_trip_id
)
*
type
=
THERMAL_TRIP_CRITICAL
;
else
if
(
trip
==
d
->
hot_trip_id
)
*
type
=
THERMAL_TRIP_HOT
;
else
if
(
trip
==
d
->
psv_trip_id
)
*
type
=
THERMAL_TRIP_PASSIVE
;
else
{
for
(
i
=
0
;
i
<
ACPI_ACTIVE_COOLING_MAX_NR
;
i
++
)
{
if
(
d
->
act_trips
[
i
].
valid
&&
d
->
act_trips
[
i
].
id
==
trip
)
{
*
type
=
THERMAL_TRIP_ACTIVE
;
break
;
}
}
if
(
i
==
ACPI_ACTIVE_COOLING_MAX_NR
)
return
-
EINVAL
;
}
return
0
;
}
static
int
int3402_thermal_set_trip_temp
(
struct
thermal_zone_device
*
zone
,
int
trip
,
unsigned
long
temp
)
{
struct
int3402_thermal_data
*
d
=
zone
->
devdata
;
acpi_status
status
;
char
name
[
10
];
snprintf
(
name
,
sizeof
(
name
),
"PAT%d"
,
trip
);
status
=
acpi_execute_simple_method
(
d
->
handle
,
name
,
MILLICELSIUS_TO_DECI_KELVIN
(
temp
));
if
(
ACPI_FAILURE
(
status
))
return
-
EIO
;
d
->
aux_trips
[
trip
]
=
temp
;
return
0
;
}
static
struct
thermal_zone_device_ops
int3402_thermal_zone_ops
=
{
.
get_temp
=
int3402_thermal_get_zone_temp
,
.
get_trip_temp
=
int3402_thermal_get_trip_temp
,
.
get_trip_type
=
int3402_thermal_get_trip_type
,
.
set_trip_temp
=
int3402_thermal_set_trip_temp
,
};
static
struct
thermal_zone_params
int3402_thermal_params
=
{
.
governor_name
=
"user_space"
,
.
no_hwmon
=
true
,
};
static
int
int3402_thermal_get_temp
(
acpi_handle
handle
,
char
*
name
,
unsigned
long
*
temp
)
{
unsigned
long
long
r
;
acpi_status
status
;
status
=
acpi_evaluate_integer
(
handle
,
name
,
NULL
,
&
r
);
if
(
ACPI_FAILURE
(
status
))
return
-
EIO
;
*
temp
=
DECI_KELVIN_TO_MILLICELSIUS
(
r
);
return
0
;
}
static
int
int3402_thermal_probe
(
struct
platform_device
*
pdev
)
{
struct
acpi_device
*
adev
=
ACPI_COMPANION
(
&
pdev
->
dev
);
struct
int3402_thermal_data
*
d
;
struct
thermal_zone_device
*
zone
;
acpi_status
status
;
unsigned
long
long
trip_cnt
;
int
trip_mask
=
0
,
i
;
if
(
!
acpi_has_method
(
adev
->
handle
,
"_TMP"
))
return
-
ENODEV
;
d
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
d
),
GFP_KERNEL
);
if
(
!
d
)
return
-
ENOMEM
;
status
=
acpi_evaluate_integer
(
adev
->
handle
,
"PATC"
,
NULL
,
&
trip_cnt
);
if
(
ACPI_FAILURE
(
status
))
trip_cnt
=
0
;
else
{
d
->
aux_trips
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
*
d
->
aux_trips
)
*
trip_cnt
,
GFP_KERNEL
);
if
(
!
d
->
aux_trips
)
return
-
ENOMEM
;
trip_mask
=
trip_cnt
-
1
;
d
->
handle
=
adev
->
handle
;
d
->
aux_trip_nr
=
trip_cnt
;
}
d
->
crt_trip_id
=
-
1
;
if
(
!
int3402_thermal_get_temp
(
adev
->
handle
,
"_CRT"
,
&
d
->
crt_temp
))
d
->
crt_trip_id
=
trip_cnt
++
;
d
->
hot_trip_id
=
-
1
;
if
(
!
int3402_thermal_get_temp
(
adev
->
handle
,
"_HOT"
,
&
d
->
hot_temp
))
d
->
hot_trip_id
=
trip_cnt
++
;
d
->
psv_trip_id
=
-
1
;
if
(
!
int3402_thermal_get_temp
(
adev
->
handle
,
"_PSV"
,
&
d
->
psv_temp
))
d
->
psv_trip_id
=
trip_cnt
++
;
for
(
i
=
0
;
i
<
ACPI_ACTIVE_COOLING_MAX_NR
;
i
++
)
{
char
name
[
5
]
=
{
'_'
,
'A'
,
'C'
,
'0'
+
i
,
'\0'
};
if
(
int3402_thermal_get_temp
(
adev
->
handle
,
name
,
&
d
->
act_trips
[
i
].
temp
))
break
;
d
->
act_trips
[
i
].
id
=
trip_cnt
++
;
d
->
act_trips
[
i
].
valid
=
true
;
}
zone
=
thermal_zone_device_register
(
acpi_device_bid
(
adev
),
trip_cnt
,
trip_mask
,
d
,
&
int3402_thermal_zone_ops
,
&
int3402_thermal_params
,
0
,
0
);
if
(
IS_ERR
(
zone
))
return
PTR_ERR
(
zone
);
platform_set_drvdata
(
pdev
,
zone
);
return
0
;
}
static
int
int3402_thermal_remove
(
struct
platform_device
*
pdev
)
{
struct
thermal_zone_device
*
zone
=
platform_get_drvdata
(
pdev
);
thermal_zone_device_unregister
(
zone
);
return
0
;
}
static
const
struct
acpi_device_id
int3402_thermal_match
[]
=
{
{
"INT3402"
,
0
},
{}
};
MODULE_DEVICE_TABLE
(
acpi
,
int3402_thermal_match
);
static
struct
platform_driver
int3402_thermal_driver
=
{
.
probe
=
int3402_thermal_probe
,
.
remove
=
int3402_thermal_remove
,
.
driver
=
{
.
name
=
"int3402 thermal"
,
.
owner
=
THIS_MODULE
,
.
acpi_match_table
=
int3402_thermal_match
,
},
};
module_platform_driver
(
int3402_thermal_driver
);
MODULE_DESCRIPTION
(
"INT3402 Thermal driver"
);
MODULE_LICENSE
(
"GPL"
);
drivers/thermal/int3403_thermal.c
→
drivers/thermal/int340
x_thermal/int340
3_thermal.c
View file @
6ceaf58a
...
...
@@ -18,8 +18,11 @@
#include <linux/types.h>
#include <linux/acpi.h>
#include <linux/thermal.h>
#include <linux/platform_device.h>
#define INT3403_TYPE_SENSOR 0x03
#define INT3403_TYPE_CHARGER 0x0B
#define INT3403_TYPE_BATTERY 0x0C
#define INT3403_PERF_CHANGED_EVENT 0x80
#define INT3403_THERMAL_EVENT 0x90
...
...
@@ -27,9 +30,6 @@
#define KELVIN_OFFSET 2732
#define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off))
#define ACPI_INT3403_CLASS "int3403"
#define ACPI_INT3403_FILE_STATE "state"
struct
int3403_sensor
{
struct
thermal_zone_device
*
tzone
;
unsigned
long
*
thresholds
;
...
...
@@ -37,12 +37,37 @@ struct int3403_sensor {
int
crit_trip_id
;
unsigned
long
psv_temp
;
int
psv_trip_id
;
};
struct
int3403_performance_state
{
u64
performance
;
u64
power
;
u64
latency
;
u64
linear
;
u64
control
;
u64
raw_performace
;
char
*
raw_unit
;
int
reserved
;
};
struct
int3403_cdev
{
struct
thermal_cooling_device
*
cdev
;
unsigned
long
max_state
;
};
struct
int3403_priv
{
struct
platform_device
*
pdev
;
struct
acpi_device
*
adev
;
unsigned
long
long
type
;
void
*
priv
;
};
static
int
sys_get_curr_temp
(
struct
thermal_zone_device
*
tzone
,
unsigned
long
*
temp
)
{
struct
acpi_device
*
device
=
tzone
->
devdata
;
struct
int3403_priv
*
priv
=
tzone
->
devdata
;
struct
acpi_device
*
device
=
priv
->
adev
;
unsigned
long
long
tmp
;
acpi_status
status
;
...
...
@@ -58,7 +83,8 @@ static int sys_get_curr_temp(struct thermal_zone_device *tzone,
static
int
sys_get_trip_hyst
(
struct
thermal_zone_device
*
tzone
,
int
trip
,
unsigned
long
*
temp
)
{
struct
acpi_device
*
device
=
tzone
->
devdata
;
struct
int3403_priv
*
priv
=
tzone
->
devdata
;
struct
acpi_device
*
device
=
priv
->
adev
;
unsigned
long
long
hyst
;
acpi_status
status
;
...
...
@@ -66,13 +92,7 @@ static int sys_get_trip_hyst(struct thermal_zone_device *tzone,
if
(
ACPI_FAILURE
(
status
))
return
-
EIO
;
/*
* Thermal hysteresis represents a temperature difference.
* Kelvin and Celsius have same degree size. So the
* conversion here between tenths of degree Kelvin unit
* and Milli-Celsius unit is just to multiply 100.
*/
*
temp
=
hyst
*
100
;
*
temp
=
DECI_KELVIN_TO_MILLI_CELSIUS
(
hyst
,
KELVIN_OFFSET
);
return
0
;
}
...
...
@@ -80,8 +100,11 @@ static int sys_get_trip_hyst(struct thermal_zone_device *tzone,
static
int
sys_get_trip_temp
(
struct
thermal_zone_device
*
tzone
,
int
trip
,
unsigned
long
*
temp
)
{
struct
acpi_device
*
device
=
tzone
->
devdata
;
struct
int3403_sensor
*
obj
=
acpi_driver_data
(
device
);
struct
int3403_priv
*
priv
=
tzone
->
devdata
;
struct
int3403_sensor
*
obj
=
priv
->
priv
;
if
(
priv
->
type
!=
INT3403_TYPE_SENSOR
||
!
obj
)
return
-
EINVAL
;
if
(
trip
==
obj
->
crit_trip_id
)
*
temp
=
obj
->
crit_temp
;
...
...
@@ -91,7 +114,7 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzone,
/*
* get_trip_temp is a mandatory callback but
* PATx method doesn't return any value, so return
* cached value, which was last set from user space
.
* cached value, which was last set from user space
*/
*
temp
=
obj
->
thresholds
[
trip
];
}
...
...
@@ -102,8 +125,8 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzone,
static
int
sys_get_trip_type
(
struct
thermal_zone_device
*
thermal
,
int
trip
,
enum
thermal_trip_type
*
type
)
{
struct
acpi_device
*
device
=
thermal
->
devdata
;
struct
int3403_sensor
*
obj
=
acpi_driver_data
(
device
)
;
struct
int3403_priv
*
priv
=
thermal
->
devdata
;
struct
int3403_sensor
*
obj
=
priv
->
priv
;
/* Mandatory callback, may not mean much here */
if
(
trip
==
obj
->
crit_trip_id
)
...
...
@@ -117,11 +140,12 @@ static int sys_get_trip_type(struct thermal_zone_device *thermal,
int
sys_set_trip_temp
(
struct
thermal_zone_device
*
tzone
,
int
trip
,
unsigned
long
temp
)
{
struct
acpi_device
*
device
=
tzone
->
devdata
;
struct
int3403_priv
*
priv
=
tzone
->
devdata
;
struct
acpi_device
*
device
=
priv
->
adev
;
struct
int3403_sensor
*
obj
=
priv
->
priv
;
acpi_status
status
;
char
name
[
10
];
int
ret
=
0
;
struct
int3403_sensor
*
obj
=
acpi_driver_data
(
device
);
snprintf
(
name
,
sizeof
(
name
),
"PAT%d"
,
trip
);
if
(
acpi_has_method
(
device
->
handle
,
name
))
{
...
...
@@ -148,15 +172,22 @@ static struct thermal_zone_device_ops tzone_ops = {
.
get_trip_hyst
=
sys_get_trip_hyst
,
};
static
void
acpi_thermal_notify
(
struct
acpi_device
*
device
,
u32
event
)
static
struct
thermal_zone_params
int3403_thermal_params
=
{
.
governor_name
=
"user_space"
,
.
no_hwmon
=
true
,
};
static
void
int3403_notify
(
acpi_handle
handle
,
u32
event
,
void
*
data
)
{
struct
int3403_priv
*
priv
=
data
;
struct
int3403_sensor
*
obj
;
if
(
!
device
)
if
(
!
priv
)
return
;
obj
=
acpi_driver_data
(
device
)
;
if
(
!
obj
)
obj
=
priv
->
priv
;
if
(
priv
->
type
!=
INT3403_TYPE_SENSOR
||
!
obj
)
return
;
switch
(
event
)
{
...
...
@@ -166,7 +197,7 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event)
thermal_zone_device_update
(
obj
->
tzone
);
break
;
default:
dev_err
(
&
device
->
dev
,
"Unsupported event [0x%x]
\n
"
,
event
);
dev_err
(
&
priv
->
pdev
->
dev
,
"Unsupported event [0x%x]
\n
"
,
event
);
break
;
}
}
...
...
@@ -199,97 +230,247 @@ static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp)
return
0
;
}
static
int
acpi_int3403_add
(
struct
acpi_device
*
device
)
static
int
int3403_sensor_add
(
struct
int3403_priv
*
priv
)
{
int
result
=
0
;
unsigned
long
long
ptyp
;
acpi_status
status
;
struct
int3403_sensor
*
obj
;
unsigned
long
long
trip_cnt
;
int
trip_mask
=
0
;
if
(
!
device
)
return
-
EINVAL
;
status
=
acpi_evaluate_integer
(
device
->
handle
,
"PTYP"
,
NULL
,
&
ptyp
);
if
(
ACPI_FAILURE
(
status
))
return
-
EINVAL
;
if
(
ptyp
!=
INT3403_TYPE_SENSOR
)
return
-
EINVAL
;
obj
=
devm_kzalloc
(
&
device
->
dev
,
sizeof
(
*
obj
),
GFP_KERNEL
);
obj
=
devm_kzalloc
(
&
priv
->
pdev
->
dev
,
sizeof
(
*
obj
),
GFP_KERNEL
);
if
(
!
obj
)
return
-
ENOMEM
;
device
->
driver_data
=
obj
;
priv
->
priv
=
obj
;
status
=
acpi_evaluate_integer
(
device
->
handle
,
"PATC"
,
NULL
,
status
=
acpi_evaluate_integer
(
priv
->
adev
->
handle
,
"PATC"
,
NULL
,
&
trip_cnt
);
if
(
ACPI_FAILURE
(
status
))
trip_cnt
=
0
;
if
(
trip_cnt
)
{
/* We have to cache, thresholds can't be readback */
obj
->
thresholds
=
devm_kzalloc
(
&
device
->
dev
,
obj
->
thresholds
=
devm_kzalloc
(
&
priv
->
pdev
->
dev
,
sizeof
(
*
obj
->
thresholds
)
*
trip_cnt
,
GFP_KERNEL
);
if
(
!
obj
->
thresholds
)
return
-
ENOMEM
;
if
(
!
obj
->
thresholds
)
{
result
=
-
ENOMEM
;
goto
err_free_obj
;
}
trip_mask
=
BIT
(
trip_cnt
)
-
1
;
}
obj
->
psv_trip_id
=
-
1
;
if
(
!
sys_get_trip_psv
(
device
,
&
obj
->
psv_temp
))
if
(
!
sys_get_trip_psv
(
priv
->
adev
,
&
obj
->
psv_temp
))
obj
->
psv_trip_id
=
trip_cnt
++
;
obj
->
crit_trip_id
=
-
1
;
if
(
!
sys_get_trip_crt
(
device
,
&
obj
->
crit_temp
))
if
(
!
sys_get_trip_crt
(
priv
->
adev
,
&
obj
->
crit_temp
))
obj
->
crit_trip_id
=
trip_cnt
++
;
obj
->
tzone
=
thermal_zone_device_register
(
acpi_device_bid
(
device
),
trip_cnt
,
trip_mask
,
device
,
&
tzone_ops
,
NULL
,
0
,
0
);
obj
->
tzone
=
thermal_zone_device_register
(
acpi_device_bid
(
priv
->
adev
),
trip_cnt
,
trip_mask
,
priv
,
&
tzone_ops
,
&
int3403_thermal_params
,
0
,
0
);
if
(
IS_ERR
(
obj
->
tzone
))
{
result
=
PTR_ERR
(
obj
->
tzone
);
return
result
;
obj
->
tzone
=
NULL
;
goto
err_free_obj
;
}
strcpy
(
acpi_device_name
(
device
),
"INT3403"
);
strcpy
(
acpi_device_class
(
device
),
ACPI_INT3403_CLASS
);
result
=
acpi_install_notify_handler
(
priv
->
adev
->
handle
,
ACPI_DEVICE_NOTIFY
,
int3403_notify
,
(
void
*
)
priv
);
if
(
result
)
goto
err_free_obj
;
return
0
;
err_free_obj:
if
(
obj
->
tzone
)
thermal_zone_device_unregister
(
obj
->
tzone
);
return
result
;
}
static
int
acpi_int3403_remove
(
struct
acpi_device
*
device
)
static
int
int3403_sensor_remove
(
struct
int3403_priv
*
priv
)
{
struct
int3403_sensor
*
obj
;
struct
int3403_sensor
*
obj
=
priv
->
priv
;
obj
=
acpi_driver_data
(
device
);
thermal_zone_device_unregister
(
obj
->
tzone
);
return
0
;
}
/* INT3403 Cooling devices */
static
int
int3403_get_max_state
(
struct
thermal_cooling_device
*
cdev
,
unsigned
long
*
state
)
{
struct
int3403_priv
*
priv
=
cdev
->
devdata
;
struct
int3403_cdev
*
obj
=
priv
->
priv
;
*
state
=
obj
->
max_state
;
return
0
;
}
static
int
int3403_get_cur_state
(
struct
thermal_cooling_device
*
cdev
,
unsigned
long
*
state
)
{
struct
int3403_priv
*
priv
=
cdev
->
devdata
;
unsigned
long
long
level
;
acpi_status
status
;
status
=
acpi_evaluate_integer
(
priv
->
adev
->
handle
,
"PPPC"
,
NULL
,
&
level
);
if
(
ACPI_SUCCESS
(
status
))
{
*
state
=
level
;
return
0
;
}
else
return
-
EINVAL
;
}
static
int
int3403_set_cur_state
(
struct
thermal_cooling_device
*
cdev
,
unsigned
long
state
)
{
struct
int3403_priv
*
priv
=
cdev
->
devdata
;
acpi_status
status
;
status
=
acpi_execute_simple_method
(
priv
->
adev
->
handle
,
"SPPC"
,
state
);
if
(
ACPI_SUCCESS
(
status
))
return
0
;
else
return
-
EINVAL
;
}
static
const
struct
thermal_cooling_device_ops
int3403_cooling_ops
=
{
.
get_max_state
=
int3403_get_max_state
,
.
get_cur_state
=
int3403_get_cur_state
,
.
set_cur_state
=
int3403_set_cur_state
,
};
static
int
int3403_cdev_add
(
struct
int3403_priv
*
priv
)
{
int
result
=
0
;
acpi_status
status
;
struct
int3403_cdev
*
obj
;
struct
acpi_buffer
buf
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
p
;
obj
=
devm_kzalloc
(
&
priv
->
pdev
->
dev
,
sizeof
(
*
obj
),
GFP_KERNEL
);
if
(
!
obj
)
return
-
ENOMEM
;
status
=
acpi_evaluate_object
(
priv
->
adev
->
handle
,
"PPSS"
,
NULL
,
&
buf
);
if
(
ACPI_FAILURE
(
status
))
return
-
ENODEV
;
p
=
buf
.
pointer
;
if
(
!
p
||
(
p
->
type
!=
ACPI_TYPE_PACKAGE
))
{
printk
(
KERN_WARNING
"Invalid PPSS data
\n
"
);
return
-
EFAULT
;
}
obj
->
max_state
=
p
->
package
.
count
-
1
;
obj
->
cdev
=
thermal_cooling_device_register
(
acpi_device_bid
(
priv
->
adev
),
priv
,
&
int3403_cooling_ops
);
if
(
IS_ERR
(
obj
->
cdev
))
result
=
PTR_ERR
(
obj
->
cdev
);
priv
->
priv
=
obj
;
/* TODO: add ACPI notification support */
return
result
;
}
static
int
int3403_cdev_remove
(
struct
int3403_priv
*
priv
)
{
struct
int3403_cdev
*
obj
=
priv
->
priv
;
thermal_cooling_device_unregister
(
obj
->
cdev
);
return
0
;
}
static
int
int3403_add
(
struct
platform_device
*
pdev
)
{
struct
int3403_priv
*
priv
;
int
result
=
0
;
acpi_status
status
;
priv
=
devm_kzalloc
(
&
pdev
->
dev
,
sizeof
(
struct
int3403_priv
),
GFP_KERNEL
);
if
(
!
priv
)
return
-
ENOMEM
;
priv
->
pdev
=
pdev
;
priv
->
adev
=
ACPI_COMPANION
(
&
(
pdev
->
dev
));
if
(
!
priv
->
adev
)
{
result
=
-
EINVAL
;
goto
err
;
}
status
=
acpi_evaluate_integer
(
priv
->
adev
->
handle
,
"PTYP"
,
NULL
,
&
priv
->
type
);
if
(
ACPI_FAILURE
(
status
))
{
result
=
-
EINVAL
;
goto
err
;
}
platform_set_drvdata
(
pdev
,
priv
);
switch
(
priv
->
type
)
{
case
INT3403_TYPE_SENSOR
:
result
=
int3403_sensor_add
(
priv
);
break
;
case
INT3403_TYPE_CHARGER
:
case
INT3403_TYPE_BATTERY
:
result
=
int3403_cdev_add
(
priv
);
break
;
default:
result
=
-
EINVAL
;
}
if
(
result
)
goto
err
;
return
result
;
err:
return
result
;
}
static
int
int3403_remove
(
struct
platform_device
*
pdev
)
{
struct
int3403_priv
*
priv
=
platform_get_drvdata
(
pdev
);
switch
(
priv
->
type
)
{
case
INT3403_TYPE_SENSOR
:
int3403_sensor_remove
(
priv
);
break
;
case
INT3403_TYPE_CHARGER
:
case
INT3403_TYPE_BATTERY
:
int3403_cdev_remove
(
priv
);
break
;
default:
break
;
}
return
0
;
}
ACPI_MODULE_NAME
(
"int3403"
);
static
const
struct
acpi_device_id
int3403_device_ids
[]
=
{
{
"INT3403"
,
0
},
{
""
,
0
},
};
MODULE_DEVICE_TABLE
(
acpi
,
int3403_device_ids
);
static
struct
acpi_driver
acpi_int3403_driver
=
{
.
name
=
"INT3403"
,
.
class
=
ACPI_INT3403_CLASS
,
.
ids
=
int3403_device_ids
,
.
ops
=
{
.
add
=
acpi_int3403_add
,
.
remove
=
acpi_int3403_remove
,
.
notify
=
acpi_thermal_notify
,
},
static
struct
platform_driver
int3403_driver
=
{
.
probe
=
int3403_add
,
.
remove
=
int3403_remove
,
.
driver
=
{
.
name
=
"int3403 thermal"
,
.
owner
=
THIS_MODULE
,
.
acpi_match_table
=
int3403_device_ids
,
},
};
module_
acpi_driver
(
acpi_
int3403_driver
);
module_
platform_driver
(
int3403_driver
);
MODULE_AUTHOR
(
"Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"
);
MODULE_LICENSE
(
"GPL v2"
);
...
...
include/acpi/acpi_bus.h
View file @
6ceaf58a
...
...
@@ -435,6 +435,7 @@ int acpi_device_set_power(struct acpi_device *device, int state);
int
acpi_bus_init_power
(
struct
acpi_device
*
device
);
int
acpi_device_fix_up_power
(
struct
acpi_device
*
device
);
int
acpi_bus_update_power
(
acpi_handle
handle
,
int
*
state_p
);
int
acpi_device_update_power
(
struct
acpi_device
*
device
,
int
*
state_p
);
bool
acpi_bus_power_manageable
(
acpi_handle
handle
);
#ifdef CONFIG_PM
...
...
include/linux/acpi.h
View file @
6ceaf58a
...
...
@@ -432,6 +432,7 @@ static inline bool acpi_driver_match_device(struct device *dev,
int
acpi_device_uevent_modalias
(
struct
device
*
,
struct
kobj_uevent_env
*
);
int
acpi_device_modalias
(
struct
device
*
,
char
*
,
int
);
struct
platform_device
*
acpi_create_platform_device
(
struct
acpi_device
*
);
#define ACPI_PTR(_ptr) (_ptr)
#else
/* !CONFIG_ACPI */
...
...
include/linux/thermal.h
View file @
6ceaf58a
...
...
@@ -44,6 +44,10 @@
#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \
((long)t-2732+5)/10 : ((long)t-2732-5)/10)
#define CELSIUS_TO_KELVIN(t) ((t)*10+2732)
#define DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, off) (((t) - (off)) * 100)
#define DECI_KELVIN_TO_MILLICELSIUS(t) DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, 2732)
#define MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, off) (((t) / 100) + (off))
#define MILLICELSIUS_TO_DECI_KELVIN(t) MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, 2732)
/* Adding event notification support elements */
#define THERMAL_GENL_FAMILY_NAME "thermal_event"
...
...
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