mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
char/misc patches for 4.12-rc1
Here is the big set of new char/misc driver drivers and features for 4.12-rc1. There's lots of new drivers added this time around, new firmware drivers from Google, more auxdisplay drivers, extcon drivers, fpga drivers, and a bunch of other driver updates. Nothing major, except if you happen to have the hardware for these drivers, and then you will be happy :) All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <[email protected]> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWQvAgg8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yknsACgzkAeyz16Z97J3UTaeejbR7nKUCAAoKY4WEHY 8O9f9pr9gj8GMBwxeZQa =OIfB -----END PGP SIGNATURE----- Merge tag 'char-misc-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc Pull char/misc driver updates from Greg KH: "Here is the big set of new char/misc driver drivers and features for 4.12-rc1. There's lots of new drivers added this time around, new firmware drivers from Google, more auxdisplay drivers, extcon drivers, fpga drivers, and a bunch of other driver updates. Nothing major, except if you happen to have the hardware for these drivers, and then you will be happy :) All of these have been in linux-next for a while with no reported issues" * tag 'char-misc-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (136 commits) firmware: google memconsole: Fix return value check in platform_memconsole_init() firmware: Google VPD: Fix return value check in vpd_platform_init() goldfish_pipe: fix build warning about using too much stack. goldfish_pipe: An implementation of more parallel pipe fpga fr br: update supported version numbers fpga: region: release FPGA region reference in error path fpga altera-hps2fpga: disable/unprepare clock on error in alt_fpga_bridge_probe() mei: drop the TODO from samples firmware: Google VPD sysfs driver firmware: Google VPD: import lib_vpd source files misc: lkdtm: Add volatile to intentional NULL pointer reference eeprom: idt_89hpesx: Add OF device ID table misc: ds1682: Add OF device ID table misc: tsl2550: Add OF device ID table w1: Remove unneeded use of assert() and remove w1_log.h w1: Use kernel common min() implementation uio_mf624: Align memory regions to page size and set correct offsets uio_mf624: Refactor memory info initialization uio: Allow handling of non page-aligned memory regions hangcheck-timer: Fix typo in comment ...
This commit is contained in:
commit
af82455f7d
166 changed files with 8064 additions and 3259 deletions
|
|
@ -419,16 +419,6 @@ config VMWARE_BALLOON
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called vmw_balloon.
|
||||
|
||||
config ARM_CHARLCD
|
||||
bool "ARM Ltd. Character LCD Driver"
|
||||
depends on PLAT_VERSATILE
|
||||
help
|
||||
This is a driver for the character LCD found on the ARM Ltd.
|
||||
Versatile and RealView Platform Baseboards. It doesn't do
|
||||
very much more than display the text "ARM Linux" on the first
|
||||
line and the Linux version on the second line, but that's
|
||||
still useful.
|
||||
|
||||
config PCH_PHUB
|
||||
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB"
|
||||
select GENERIC_NET_UTILS
|
||||
|
|
@ -492,284 +482,13 @@ config VEXPRESS_SYSCFG
|
|||
bus. System Configuration interface is one of the possible means
|
||||
of generating transactions on this bus.
|
||||
|
||||
config PANEL
|
||||
tristate "Parallel port LCD/Keypad Panel support"
|
||||
depends on PARPORT
|
||||
config ASPEED_LPC_CTRL
|
||||
depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
|
||||
tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control"
|
||||
---help---
|
||||
Say Y here if you have an HD44780 or KS-0074 LCD connected to your
|
||||
parallel port. This driver also features 4 and 6-key keypads. The LCD
|
||||
is accessible through the /dev/lcd char device (10, 156), and the
|
||||
keypad through /dev/keypad (10, 185). This code can either be
|
||||
compiled as a module, or linked into the kernel and started at boot.
|
||||
If you don't understand what all this is about, say N.
|
||||
|
||||
if PANEL
|
||||
|
||||
config PANEL_PARPORT
|
||||
int "Default parallel port number (0=LPT1)"
|
||||
range 0 255
|
||||
default "0"
|
||||
---help---
|
||||
This is the index of the parallel port the panel is connected to. One
|
||||
driver instance only supports one parallel port, so if your keypad
|
||||
and LCD are connected to two separate ports, you have to start two
|
||||
modules with different arguments. Numbering starts with '0' for LPT1,
|
||||
and so on.
|
||||
|
||||
config PANEL_PROFILE
|
||||
int "Default panel profile (0-5, 0=custom)"
|
||||
range 0 5
|
||||
default "5"
|
||||
---help---
|
||||
To ease configuration, the driver supports different configuration
|
||||
profiles for past and recent wirings. These profiles can also be
|
||||
used to define an approximative configuration, completed by a few
|
||||
other options. Here are the profiles :
|
||||
|
||||
0 = custom (see further)
|
||||
1 = 2x16 parallel LCD, old keypad
|
||||
2 = 2x16 serial LCD (KS-0074), new keypad
|
||||
3 = 2x16 parallel LCD (Hantronix), no keypad
|
||||
4 = 2x16 parallel LCD (Nexcom NSA1045) with Nexcom's keypad
|
||||
5 = 2x40 parallel LCD (old one), with old keypad
|
||||
|
||||
Custom configurations allow you to define how your display is
|
||||
wired to the parallel port, and how it works. This is only intended
|
||||
for experts.
|
||||
|
||||
config PANEL_KEYPAD
|
||||
depends on PANEL_PROFILE="0"
|
||||
int "Keypad type (0=none, 1=old 6 keys, 2=new 6 keys, 3=Nexcom 4 keys)"
|
||||
range 0 3
|
||||
default 0
|
||||
---help---
|
||||
This enables and configures a keypad connected to the parallel port.
|
||||
The keys will be read from character device 10,185. Valid values are :
|
||||
|
||||
0 : do not enable this driver
|
||||
1 : old 6 keys keypad
|
||||
2 : new 6 keys keypad, as used on the server at www.ant-computing.com
|
||||
3 : Nexcom NSA1045's 4 keys keypad
|
||||
|
||||
New profiles can be described in the driver source. The driver also
|
||||
supports simultaneous keys pressed when the keypad supports them.
|
||||
|
||||
config PANEL_LCD
|
||||
depends on PANEL_PROFILE="0"
|
||||
int "LCD type (0=none, 1=custom, 2=old //, 3=ks0074, 4=hantronix, 5=Nexcom)"
|
||||
range 0 5
|
||||
default 0
|
||||
---help---
|
||||
This enables and configures an LCD connected to the parallel port.
|
||||
The driver includes an interpreter for escape codes starting with
|
||||
'\e[L' which are specific to the LCD, and a few ANSI codes. The
|
||||
driver will be registered as character device 10,156, usually
|
||||
under the name '/dev/lcd'. There are a total of 6 supported types :
|
||||
|
||||
0 : do not enable the driver
|
||||
1 : custom configuration and wiring (see further)
|
||||
2 : 2x16 & 2x40 parallel LCD (old wiring)
|
||||
3 : 2x16 serial LCD (KS-0074 based)
|
||||
4 : 2x16 parallel LCD (Hantronix wiring)
|
||||
5 : 2x16 parallel LCD (Nexcom wiring)
|
||||
|
||||
When type '1' is specified, other options will appear to configure
|
||||
more precise aspects (wiring, dimensions, protocol, ...). Please note
|
||||
that those values changed from the 2.4 driver for better consistency.
|
||||
|
||||
config PANEL_LCD_HEIGHT
|
||||
depends on PANEL_PROFILE="0" && PANEL_LCD="1"
|
||||
int "Number of lines on the LCD (1-2)"
|
||||
range 1 2
|
||||
default 2
|
||||
---help---
|
||||
This is the number of visible character lines on the LCD in custom profile.
|
||||
It can either be 1 or 2.
|
||||
|
||||
config PANEL_LCD_WIDTH
|
||||
depends on PANEL_PROFILE="0" && PANEL_LCD="1"
|
||||
int "Number of characters per line on the LCD (1-40)"
|
||||
range 1 40
|
||||
default 40
|
||||
---help---
|
||||
This is the number of characters per line on the LCD in custom profile.
|
||||
Common values are 16,20,24,40.
|
||||
|
||||
config PANEL_LCD_BWIDTH
|
||||
depends on PANEL_PROFILE="0" && PANEL_LCD="1"
|
||||
int "Internal LCD line width (1-40, 40 by default)"
|
||||
range 1 40
|
||||
default 40
|
||||
---help---
|
||||
Most LCDs use a standard controller which supports hardware lines of 40
|
||||
characters, although sometimes only 16, 20 or 24 of them are really wired
|
||||
to the terminal. This results in some non-visible but addressable characters,
|
||||
and is the case for most parallel LCDs. Other LCDs, and some serial ones,
|
||||
however, use the same line width internally as what is visible. The KS0074
|
||||
for example, uses 16 characters per line for 16 visible characters per line.
|
||||
|
||||
This option lets you configure the value used by your LCD in 'custom' profile.
|
||||
If you don't know, put '40' here.
|
||||
|
||||
config PANEL_LCD_HWIDTH
|
||||
depends on PANEL_PROFILE="0" && PANEL_LCD="1"
|
||||
int "Hardware LCD line width (1-64, 64 by default)"
|
||||
range 1 64
|
||||
default 64
|
||||
---help---
|
||||
Most LCDs use a single address bit to differentiate line 0 and line 1. Since
|
||||
some of them need to be able to address 40 chars with the lower bits, they
|
||||
often use the immediately superior power of 2, which is 64, to address the
|
||||
next line.
|
||||
|
||||
If you don't know what your LCD uses, in doubt let 16 here for a 2x16, and
|
||||
64 here for a 2x40.
|
||||
|
||||
config PANEL_LCD_CHARSET
|
||||
depends on PANEL_PROFILE="0" && PANEL_LCD="1"
|
||||
int "LCD character set (0=normal, 1=KS0074)"
|
||||
range 0 1
|
||||
default 0
|
||||
---help---
|
||||
Some controllers such as the KS0074 use a somewhat strange character set
|
||||
where many symbols are at unusual places. The driver knows how to map
|
||||
'standard' ASCII characters to the character sets used by these controllers.
|
||||
Valid values are :
|
||||
|
||||
0 : normal (untranslated) character set
|
||||
1 : KS0074 character set
|
||||
|
||||
If you don't know, use the normal one (0).
|
||||
|
||||
config PANEL_LCD_PROTO
|
||||
depends on PANEL_PROFILE="0" && PANEL_LCD="1"
|
||||
int "LCD communication mode (0=parallel 8 bits, 1=serial)"
|
||||
range 0 1
|
||||
default 0
|
||||
---help---
|
||||
This driver now supports any serial or parallel LCD wired to a parallel
|
||||
port. But before assigning signals, the driver needs to know if it will
|
||||
be driving a serial LCD or a parallel one. Serial LCDs only use 2 wires
|
||||
(SDA/SCL), while parallel ones use 2 or 3 wires for the control signals
|
||||
(E, RS, sometimes RW), and 4 or 8 for the data. Use 0 here for a 8 bits
|
||||
parallel LCD, and 1 for a serial LCD.
|
||||
|
||||
config PANEL_LCD_PIN_E
|
||||
depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0"
|
||||
int "Parallel port pin number & polarity connected to the LCD E signal (-17...17) "
|
||||
range -17 17
|
||||
default 14
|
||||
---help---
|
||||
This describes the number of the parallel port pin to which the LCD 'E'
|
||||
signal has been connected. It can be :
|
||||
|
||||
0 : no connection (eg: connected to ground)
|
||||
1..17 : directly connected to any of these pins on the DB25 plug
|
||||
-1..-17 : connected to the same pin through an inverter (eg: transistor).
|
||||
|
||||
Default for the 'E' pin in custom profile is '14' (AUTOFEED).
|
||||
|
||||
config PANEL_LCD_PIN_RS
|
||||
depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0"
|
||||
int "Parallel port pin number & polarity connected to the LCD RS signal (-17...17) "
|
||||
range -17 17
|
||||
default 17
|
||||
---help---
|
||||
This describes the number of the parallel port pin to which the LCD 'RS'
|
||||
signal has been connected. It can be :
|
||||
|
||||
0 : no connection (eg: connected to ground)
|
||||
1..17 : directly connected to any of these pins on the DB25 plug
|
||||
-1..-17 : connected to the same pin through an inverter (eg: transistor).
|
||||
|
||||
Default for the 'RS' pin in custom profile is '17' (SELECT IN).
|
||||
|
||||
config PANEL_LCD_PIN_RW
|
||||
depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0"
|
||||
int "Parallel port pin number & polarity connected to the LCD RW signal (-17...17) "
|
||||
range -17 17
|
||||
default 16
|
||||
---help---
|
||||
This describes the number of the parallel port pin to which the LCD 'RW'
|
||||
signal has been connected. It can be :
|
||||
|
||||
0 : no connection (eg: connected to ground)
|
||||
1..17 : directly connected to any of these pins on the DB25 plug
|
||||
-1..-17 : connected to the same pin through an inverter (eg: transistor).
|
||||
|
||||
Default for the 'RW' pin in custom profile is '16' (INIT).
|
||||
|
||||
config PANEL_LCD_PIN_SCL
|
||||
depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0"
|
||||
int "Parallel port pin number & polarity connected to the LCD SCL signal (-17...17) "
|
||||
range -17 17
|
||||
default 1
|
||||
---help---
|
||||
This describes the number of the parallel port pin to which the serial
|
||||
LCD 'SCL' signal has been connected. It can be :
|
||||
|
||||
0 : no connection (eg: connected to ground)
|
||||
1..17 : directly connected to any of these pins on the DB25 plug
|
||||
-1..-17 : connected to the same pin through an inverter (eg: transistor).
|
||||
|
||||
Default for the 'SCL' pin in custom profile is '1' (STROBE).
|
||||
|
||||
config PANEL_LCD_PIN_SDA
|
||||
depends on PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0"
|
||||
int "Parallel port pin number & polarity connected to the LCD SDA signal (-17...17) "
|
||||
range -17 17
|
||||
default 2
|
||||
---help---
|
||||
This describes the number of the parallel port pin to which the serial
|
||||
LCD 'SDA' signal has been connected. It can be :
|
||||
|
||||
0 : no connection (eg: connected to ground)
|
||||
1..17 : directly connected to any of these pins on the DB25 plug
|
||||
-1..-17 : connected to the same pin through an inverter (eg: transistor).
|
||||
|
||||
Default for the 'SDA' pin in custom profile is '2' (D0).
|
||||
|
||||
config PANEL_LCD_PIN_BL
|
||||
depends on PANEL_PROFILE="0" && PANEL_LCD="1"
|
||||
int "Parallel port pin number & polarity connected to the LCD backlight signal (-17...17) "
|
||||
range -17 17
|
||||
default 0
|
||||
---help---
|
||||
This describes the number of the parallel port pin to which the LCD 'BL' signal
|
||||
has been connected. It can be :
|
||||
|
||||
0 : no connection (eg: connected to ground)
|
||||
1..17 : directly connected to any of these pins on the DB25 plug
|
||||
-1..-17 : connected to the same pin through an inverter (eg: transistor).
|
||||
|
||||
Default for the 'BL' pin in custom profile is '0' (uncontrolled).
|
||||
|
||||
config PANEL_CHANGE_MESSAGE
|
||||
bool "Change LCD initialization message ?"
|
||||
default "n"
|
||||
---help---
|
||||
This allows you to replace the boot message indicating the kernel version
|
||||
and the driver version with a custom message. This is useful on appliances
|
||||
where a simple 'Starting system' message can be enough to stop a customer
|
||||
from worrying.
|
||||
|
||||
If you say 'Y' here, you'll be able to choose a message yourself. Otherwise,
|
||||
say 'N' and keep the default message with the version.
|
||||
|
||||
config PANEL_BOOT_MESSAGE
|
||||
depends on PANEL_CHANGE_MESSAGE="y"
|
||||
string "New initialization message"
|
||||
default ""
|
||||
---help---
|
||||
This allows you to replace the boot message indicating the kernel version
|
||||
and the driver version with a custom message. This is useful on appliances
|
||||
where a simple 'Starting system' message can be enough to stop a customer
|
||||
from worrying.
|
||||
|
||||
An empty message will only clear the display at driver init time. Any other
|
||||
printf()-formatted message is valid with newline and escape codes.
|
||||
|
||||
endif # PANEL
|
||||
Control Aspeed ast2400/2500 HOST LPC to BMC mappings through
|
||||
ioctl()s, the driver also provides a read/write interface to a BMC ram
|
||||
region where the host LPC read/write region can be buffered.
|
||||
|
||||
source "drivers/misc/c2port/Kconfig"
|
||||
source "drivers/misc/eeprom/Kconfig"
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ obj-y += eeprom/
|
|||
obj-y += cb710/
|
||||
obj-$(CONFIG_SPEAR13XX_PCIE_GADGET) += spear13xx_pcie_gadget.o
|
||||
obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o
|
||||
obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
|
||||
obj-$(CONFIG_PCH_PHUB) += pch_phub.o
|
||||
obj-y += ti-st/
|
||||
obj-y += lis3lv02d/
|
||||
|
|
@ -53,7 +52,7 @@ obj-$(CONFIG_GENWQE) += genwqe/
|
|||
obj-$(CONFIG_ECHO) += echo/
|
||||
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
|
||||
obj-$(CONFIG_CXL_BASE) += cxl/
|
||||
obj-$(CONFIG_PANEL) += panel.o
|
||||
obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
|
||||
|
||||
lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o
|
||||
lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o
|
||||
|
|
@ -62,6 +61,8 @@ lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o
|
|||
lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o
|
||||
lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o
|
||||
|
||||
KCOV_INSTRUMENT_lkdtm_rodata.o := n
|
||||
|
||||
OBJCOPYFLAGS :=
|
||||
OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \
|
||||
--set-section-flags .text=alloc,readonly \
|
||||
|
|
|
|||
|
|
@ -1,368 +0,0 @@
|
|||
/*
|
||||
* Driver for the on-board character LCD found on some ARM reference boards
|
||||
* This is basically an Hitachi HD44780 LCD with a custom IP block to drive it
|
||||
* http://en.wikipedia.org/wiki/HD44780_Character_LCD
|
||||
* Currently it will just display the text "ARM Linux" and the linux version
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
* Author: Linus Walleij <triad@df.lth.se>
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <generated/utsrelease.h>
|
||||
|
||||
#define DRIVERNAME "arm-charlcd"
|
||||
#define CHARLCD_TIMEOUT (msecs_to_jiffies(1000))
|
||||
|
||||
/* Offsets to registers */
|
||||
#define CHAR_COM 0x00U
|
||||
#define CHAR_DAT 0x04U
|
||||
#define CHAR_RD 0x08U
|
||||
#define CHAR_RAW 0x0CU
|
||||
#define CHAR_MASK 0x10U
|
||||
#define CHAR_STAT 0x14U
|
||||
|
||||
#define CHAR_RAW_CLEAR 0x00000000U
|
||||
#define CHAR_RAW_VALID 0x00000100U
|
||||
|
||||
/* Hitachi HD44780 display commands */
|
||||
#define HD_CLEAR 0x01U
|
||||
#define HD_HOME 0x02U
|
||||
#define HD_ENTRYMODE 0x04U
|
||||
#define HD_ENTRYMODE_INCREMENT 0x02U
|
||||
#define HD_ENTRYMODE_SHIFT 0x01U
|
||||
#define HD_DISPCTRL 0x08U
|
||||
#define HD_DISPCTRL_ON 0x04U
|
||||
#define HD_DISPCTRL_CURSOR_ON 0x02U
|
||||
#define HD_DISPCTRL_CURSOR_BLINK 0x01U
|
||||
#define HD_CRSR_SHIFT 0x10U
|
||||
#define HD_CRSR_SHIFT_DISPLAY 0x08U
|
||||
#define HD_CRSR_SHIFT_DISPLAY_RIGHT 0x04U
|
||||
#define HD_FUNCSET 0x20U
|
||||
#define HD_FUNCSET_8BIT 0x10U
|
||||
#define HD_FUNCSET_2_LINES 0x08U
|
||||
#define HD_FUNCSET_FONT_5X10 0x04U
|
||||
#define HD_SET_CGRAM 0x40U
|
||||
#define HD_SET_DDRAM 0x80U
|
||||
#define HD_BUSY_FLAG 0x80U
|
||||
|
||||
/**
|
||||
* @dev: a pointer back to containing device
|
||||
* @phybase: the offset to the controller in physical memory
|
||||
* @physize: the size of the physical page
|
||||
* @virtbase: the offset to the controller in virtual memory
|
||||
* @irq: reserved interrupt number
|
||||
* @complete: completion structure for the last LCD command
|
||||
*/
|
||||
struct charlcd {
|
||||
struct device *dev;
|
||||
u32 phybase;
|
||||
u32 physize;
|
||||
void __iomem *virtbase;
|
||||
int irq;
|
||||
struct completion complete;
|
||||
struct delayed_work init_work;
|
||||
};
|
||||
|
||||
static irqreturn_t charlcd_interrupt(int irq, void *data)
|
||||
{
|
||||
struct charlcd *lcd = data;
|
||||
u8 status;
|
||||
|
||||
status = readl(lcd->virtbase + CHAR_STAT) & 0x01;
|
||||
/* Clear IRQ */
|
||||
writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
|
||||
if (status)
|
||||
complete(&lcd->complete);
|
||||
else
|
||||
dev_info(lcd->dev, "Spurious IRQ (%02x)\n", status);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static void charlcd_wait_complete_irq(struct charlcd *lcd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = wait_for_completion_interruptible_timeout(&lcd->complete,
|
||||
CHARLCD_TIMEOUT);
|
||||
/* Disable IRQ after completion */
|
||||
writel(0x00, lcd->virtbase + CHAR_MASK);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(lcd->dev,
|
||||
"wait_for_completion_interruptible_timeout() "
|
||||
"returned %d waiting for ready\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
dev_err(lcd->dev, "charlcd controller timed out "
|
||||
"waiting for ready\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static u8 charlcd_4bit_read_char(struct charlcd *lcd)
|
||||
{
|
||||
u8 data;
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
/* If we can, use an IRQ to wait for the data, else poll */
|
||||
if (lcd->irq >= 0)
|
||||
charlcd_wait_complete_irq(lcd);
|
||||
else {
|
||||
i = 0;
|
||||
val = 0;
|
||||
while (!(val & CHAR_RAW_VALID) && i < 10) {
|
||||
udelay(100);
|
||||
val = readl(lcd->virtbase + CHAR_RAW);
|
||||
i++;
|
||||
}
|
||||
|
||||
writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
|
||||
}
|
||||
msleep(1);
|
||||
|
||||
/* Read the 4 high bits of the data */
|
||||
data = readl(lcd->virtbase + CHAR_RD) & 0xf0;
|
||||
|
||||
/*
|
||||
* The second read for the low bits does not trigger an IRQ
|
||||
* so in this case we have to poll for the 4 lower bits
|
||||
*/
|
||||
i = 0;
|
||||
val = 0;
|
||||
while (!(val & CHAR_RAW_VALID) && i < 10) {
|
||||
udelay(100);
|
||||
val = readl(lcd->virtbase + CHAR_RAW);
|
||||
i++;
|
||||
}
|
||||
writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
|
||||
msleep(1);
|
||||
|
||||
/* Read the 4 low bits of the data */
|
||||
data |= (readl(lcd->virtbase + CHAR_RD) >> 4) & 0x0f;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static bool charlcd_4bit_read_bf(struct charlcd *lcd)
|
||||
{
|
||||
if (lcd->irq >= 0) {
|
||||
/*
|
||||
* If we'll use IRQs to wait for the busyflag, clear any
|
||||
* pending flag and enable IRQ
|
||||
*/
|
||||
writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW);
|
||||
init_completion(&lcd->complete);
|
||||
writel(0x01, lcd->virtbase + CHAR_MASK);
|
||||
}
|
||||
readl(lcd->virtbase + CHAR_COM);
|
||||
return charlcd_4bit_read_char(lcd) & HD_BUSY_FLAG ? true : false;
|
||||
}
|
||||
|
||||
static void charlcd_4bit_wait_busy(struct charlcd *lcd)
|
||||
{
|
||||
int retries = 50;
|
||||
|
||||
udelay(100);
|
||||
while (charlcd_4bit_read_bf(lcd) && retries)
|
||||
retries--;
|
||||
if (!retries)
|
||||
dev_err(lcd->dev, "timeout waiting for busyflag\n");
|
||||
}
|
||||
|
||||
static void charlcd_4bit_command(struct charlcd *lcd, u8 cmd)
|
||||
{
|
||||
u32 cmdlo = (cmd << 4) & 0xf0;
|
||||
u32 cmdhi = (cmd & 0xf0);
|
||||
|
||||
writel(cmdhi, lcd->virtbase + CHAR_COM);
|
||||
udelay(10);
|
||||
writel(cmdlo, lcd->virtbase + CHAR_COM);
|
||||
charlcd_4bit_wait_busy(lcd);
|
||||
}
|
||||
|
||||
static void charlcd_4bit_char(struct charlcd *lcd, u8 ch)
|
||||
{
|
||||
u32 chlo = (ch << 4) & 0xf0;
|
||||
u32 chhi = (ch & 0xf0);
|
||||
|
||||
writel(chhi, lcd->virtbase + CHAR_DAT);
|
||||
udelay(10);
|
||||
writel(chlo, lcd->virtbase + CHAR_DAT);
|
||||
charlcd_4bit_wait_busy(lcd);
|
||||
}
|
||||
|
||||
static void charlcd_4bit_print(struct charlcd *lcd, int line, const char *str)
|
||||
{
|
||||
u8 offset;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* We support line 0, 1
|
||||
* Line 1 runs from 0x00..0x27
|
||||
* Line 2 runs from 0x28..0x4f
|
||||
*/
|
||||
if (line == 0)
|
||||
offset = 0;
|
||||
else if (line == 1)
|
||||
offset = 0x28;
|
||||
else
|
||||
return;
|
||||
|
||||
/* Set offset */
|
||||
charlcd_4bit_command(lcd, HD_SET_DDRAM | offset);
|
||||
|
||||
/* Send string */
|
||||
for (i = 0; i < strlen(str) && i < 0x28; i++)
|
||||
charlcd_4bit_char(lcd, str[i]);
|
||||
}
|
||||
|
||||
static void charlcd_4bit_init(struct charlcd *lcd)
|
||||
{
|
||||
/* These commands cannot be checked with the busy flag */
|
||||
writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM);
|
||||
msleep(5);
|
||||
writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM);
|
||||
udelay(100);
|
||||
writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM);
|
||||
udelay(100);
|
||||
/* Go to 4bit mode */
|
||||
writel(HD_FUNCSET, lcd->virtbase + CHAR_COM);
|
||||
udelay(100);
|
||||
/*
|
||||
* 4bit mode, 2 lines, 5x8 font, after this the number of lines
|
||||
* and the font cannot be changed until the next initialization sequence
|
||||
*/
|
||||
charlcd_4bit_command(lcd, HD_FUNCSET | HD_FUNCSET_2_LINES);
|
||||
charlcd_4bit_command(lcd, HD_DISPCTRL | HD_DISPCTRL_ON);
|
||||
charlcd_4bit_command(lcd, HD_ENTRYMODE | HD_ENTRYMODE_INCREMENT);
|
||||
charlcd_4bit_command(lcd, HD_CLEAR);
|
||||
charlcd_4bit_command(lcd, HD_HOME);
|
||||
/* Put something useful in the display */
|
||||
charlcd_4bit_print(lcd, 0, "ARM Linux");
|
||||
charlcd_4bit_print(lcd, 1, UTS_RELEASE);
|
||||
}
|
||||
|
||||
static void charlcd_init_work(struct work_struct *work)
|
||||
{
|
||||
struct charlcd *lcd =
|
||||
container_of(work, struct charlcd, init_work.work);
|
||||
|
||||
charlcd_4bit_init(lcd);
|
||||
}
|
||||
|
||||
static int __init charlcd_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct charlcd *lcd;
|
||||
struct resource *res;
|
||||
|
||||
lcd = kzalloc(sizeof(struct charlcd), GFP_KERNEL);
|
||||
if (!lcd)
|
||||
return -ENOMEM;
|
||||
|
||||
lcd->dev = &pdev->dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENOENT;
|
||||
goto out_no_resource;
|
||||
}
|
||||
lcd->phybase = res->start;
|
||||
lcd->physize = resource_size(res);
|
||||
|
||||
if (request_mem_region(lcd->phybase, lcd->physize,
|
||||
DRIVERNAME) == NULL) {
|
||||
ret = -EBUSY;
|
||||
goto out_no_memregion;
|
||||
}
|
||||
|
||||
lcd->virtbase = ioremap(lcd->phybase, lcd->physize);
|
||||
if (!lcd->virtbase) {
|
||||
ret = -ENOMEM;
|
||||
goto out_no_memregion;
|
||||
}
|
||||
|
||||
lcd->irq = platform_get_irq(pdev, 0);
|
||||
/* If no IRQ is supplied, we'll survive without it */
|
||||
if (lcd->irq >= 0) {
|
||||
if (request_irq(lcd->irq, charlcd_interrupt, 0,
|
||||
DRIVERNAME, lcd)) {
|
||||
ret = -EIO;
|
||||
goto out_no_irq;
|
||||
}
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, lcd);
|
||||
|
||||
/*
|
||||
* Initialize the display in a delayed work, because
|
||||
* it is VERY slow and would slow down the boot of the system.
|
||||
*/
|
||||
INIT_DELAYED_WORK(&lcd->init_work, charlcd_init_work);
|
||||
schedule_delayed_work(&lcd->init_work, 0);
|
||||
|
||||
dev_info(&pdev->dev, "initialized ARM character LCD at %08x\n",
|
||||
lcd->phybase);
|
||||
|
||||
return 0;
|
||||
|
||||
out_no_irq:
|
||||
iounmap(lcd->virtbase);
|
||||
out_no_memregion:
|
||||
release_mem_region(lcd->phybase, SZ_4K);
|
||||
out_no_resource:
|
||||
kfree(lcd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int charlcd_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct charlcd *lcd = platform_get_drvdata(pdev);
|
||||
|
||||
/* Power the display off */
|
||||
charlcd_4bit_command(lcd, HD_DISPCTRL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int charlcd_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct charlcd *lcd = platform_get_drvdata(pdev);
|
||||
|
||||
/* Turn the display back on */
|
||||
charlcd_4bit_command(lcd, HD_DISPCTRL | HD_DISPCTRL_ON);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops charlcd_pm_ops = {
|
||||
.suspend = charlcd_suspend,
|
||||
.resume = charlcd_resume,
|
||||
};
|
||||
|
||||
static const struct of_device_id charlcd_match[] = {
|
||||
{ .compatible = "arm,versatile-lcd", },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver charlcd_driver = {
|
||||
.driver = {
|
||||
.name = DRIVERNAME,
|
||||
.pm = &charlcd_pm_ops,
|
||||
.suppress_bind_attrs = true,
|
||||
.of_match_table = of_match_ptr(charlcd_match),
|
||||
},
|
||||
};
|
||||
builtin_platform_driver_probe(charlcd_driver, charlcd_probe);
|
||||
266
drivers/misc/aspeed-lpc-ctrl.c
Normal file
266
drivers/misc/aspeed-lpc-ctrl.c
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* Copyright 2017 IBM Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/aspeed-lpc-ctrl.h>
|
||||
|
||||
#define DEVICE_NAME "aspeed-lpc-ctrl"
|
||||
|
||||
#define HICR7 0x8
|
||||
#define HICR8 0xc
|
||||
|
||||
struct aspeed_lpc_ctrl {
|
||||
struct miscdevice miscdev;
|
||||
struct regmap *regmap;
|
||||
phys_addr_t mem_base;
|
||||
resource_size_t mem_size;
|
||||
u32 pnor_size;
|
||||
u32 pnor_base;
|
||||
};
|
||||
|
||||
static struct aspeed_lpc_ctrl *file_aspeed_lpc_ctrl(struct file *file)
|
||||
{
|
||||
return container_of(file->private_data, struct aspeed_lpc_ctrl,
|
||||
miscdev);
|
||||
}
|
||||
|
||||
static int aspeed_lpc_ctrl_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file);
|
||||
unsigned long vsize = vma->vm_end - vma->vm_start;
|
||||
pgprot_t prot = vma->vm_page_prot;
|
||||
|
||||
if (vma->vm_pgoff + vsize > lpc_ctrl->mem_base + lpc_ctrl->mem_size)
|
||||
return -EINVAL;
|
||||
|
||||
/* ast2400/2500 AHB accesses are not cache coherent */
|
||||
prot = pgprot_noncached(prot);
|
||||
|
||||
if (remap_pfn_range(vma, vma->vm_start,
|
||||
(lpc_ctrl->mem_base >> PAGE_SHIFT) + vma->vm_pgoff,
|
||||
vsize, prot))
|
||||
return -EAGAIN;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long aspeed_lpc_ctrl_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long param)
|
||||
{
|
||||
struct aspeed_lpc_ctrl *lpc_ctrl = file_aspeed_lpc_ctrl(file);
|
||||
void __user *p = (void __user *)param;
|
||||
struct aspeed_lpc_ctrl_mapping map;
|
||||
u32 addr;
|
||||
u32 size;
|
||||
long rc;
|
||||
|
||||
if (copy_from_user(&map, p, sizeof(map)))
|
||||
return -EFAULT;
|
||||
|
||||
if (map.flags != 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch (cmd) {
|
||||
case ASPEED_LPC_CTRL_IOCTL_GET_SIZE:
|
||||
/* The flash windows don't report their size */
|
||||
if (map.window_type != ASPEED_LPC_CTRL_WINDOW_MEMORY)
|
||||
return -EINVAL;
|
||||
|
||||
/* Support more than one window id in the future */
|
||||
if (map.window_id != 0)
|
||||
return -EINVAL;
|
||||
|
||||
map.size = lpc_ctrl->mem_size;
|
||||
|
||||
return copy_to_user(p, &map, sizeof(map)) ? -EFAULT : 0;
|
||||
case ASPEED_LPC_CTRL_IOCTL_MAP:
|
||||
|
||||
/*
|
||||
* The top half of HICR7 is the MSB of the BMC address of the
|
||||
* mapping.
|
||||
* The bottom half of HICR7 is the MSB of the HOST LPC
|
||||
* firmware space address of the mapping.
|
||||
*
|
||||
* The 1 bits in the top of half of HICR8 represent the bits
|
||||
* (in the requested address) that should be ignored and
|
||||
* replaced with those from the top half of HICR7.
|
||||
* The 1 bits in the bottom half of HICR8 represent the bits
|
||||
* (in the requested address) that should be kept and pass
|
||||
* into the BMC address space.
|
||||
*/
|
||||
|
||||
/*
|
||||
* It doesn't make sense to talk about a size or offset with
|
||||
* low 16 bits set. Both HICR7 and HICR8 talk about the top 16
|
||||
* bits of addresses and sizes.
|
||||
*/
|
||||
|
||||
if ((map.size & 0x0000ffff) || (map.offset & 0x0000ffff))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Because of the way the masks work in HICR8 offset has to
|
||||
* be a multiple of size.
|
||||
*/
|
||||
if (map.offset & (map.size - 1))
|
||||
return -EINVAL;
|
||||
|
||||
if (map.window_type == ASPEED_LPC_CTRL_WINDOW_FLASH) {
|
||||
addr = lpc_ctrl->pnor_base;
|
||||
size = lpc_ctrl->pnor_size;
|
||||
} else if (map.window_type == ASPEED_LPC_CTRL_WINDOW_MEMORY) {
|
||||
addr = lpc_ctrl->mem_base;
|
||||
size = lpc_ctrl->mem_size;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check overflow first! */
|
||||
if (map.offset + map.size < map.offset ||
|
||||
map.offset + map.size > size)
|
||||
return -EINVAL;
|
||||
|
||||
if (map.size == 0 || map.size > size)
|
||||
return -EINVAL;
|
||||
|
||||
addr += map.offset;
|
||||
|
||||
/*
|
||||
* addr (host lpc address) is safe regardless of values. This
|
||||
* simply changes the address the host has to request on its
|
||||
* side of the LPC bus. This cannot impact the hosts own
|
||||
* memory space by surprise as LPC specific accessors are
|
||||
* required. The only strange thing that could be done is
|
||||
* setting the lower 16 bits but the shift takes care of that.
|
||||
*/
|
||||
|
||||
rc = regmap_write(lpc_ctrl->regmap, HICR7,
|
||||
(addr | (map.addr >> 16)));
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return regmap_write(lpc_ctrl->regmap, HICR8,
|
||||
(~(map.size - 1)) | ((map.size >> 16) - 1));
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct file_operations aspeed_lpc_ctrl_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.mmap = aspeed_lpc_ctrl_mmap,
|
||||
.unlocked_ioctl = aspeed_lpc_ctrl_ioctl,
|
||||
};
|
||||
|
||||
static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct aspeed_lpc_ctrl *lpc_ctrl;
|
||||
struct device_node *node;
|
||||
struct resource resm;
|
||||
struct device *dev;
|
||||
int rc;
|
||||
|
||||
dev = &pdev->dev;
|
||||
|
||||
lpc_ctrl = devm_kzalloc(dev, sizeof(*lpc_ctrl), GFP_KERNEL);
|
||||
if (!lpc_ctrl)
|
||||
return -ENOMEM;
|
||||
|
||||
node = of_parse_phandle(dev->of_node, "flash", 0);
|
||||
if (!node) {
|
||||
dev_err(dev, "Didn't find host pnor flash node\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rc = of_address_to_resource(node, 1, &resm);
|
||||
of_node_put(node);
|
||||
if (rc) {
|
||||
dev_err(dev, "Couldn't address to resource for flash\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
lpc_ctrl->pnor_size = resource_size(&resm);
|
||||
lpc_ctrl->pnor_base = resm.start;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, lpc_ctrl);
|
||||
|
||||
node = of_parse_phandle(dev->of_node, "memory-region", 0);
|
||||
if (!node) {
|
||||
dev_err(dev, "Didn't find reserved memory\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = of_address_to_resource(node, 0, &resm);
|
||||
of_node_put(node);
|
||||
if (rc) {
|
||||
dev_err(dev, "Couldn't address to resource for reserved memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
lpc_ctrl->mem_size = resource_size(&resm);
|
||||
lpc_ctrl->mem_base = resm.start;
|
||||
|
||||
lpc_ctrl->regmap = syscon_node_to_regmap(
|
||||
pdev->dev.parent->of_node);
|
||||
if (IS_ERR(lpc_ctrl->regmap)) {
|
||||
dev_err(dev, "Couldn't get regmap\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
lpc_ctrl->miscdev.minor = MISC_DYNAMIC_MINOR;
|
||||
lpc_ctrl->miscdev.name = DEVICE_NAME;
|
||||
lpc_ctrl->miscdev.fops = &aspeed_lpc_ctrl_fops;
|
||||
lpc_ctrl->miscdev.parent = dev;
|
||||
rc = misc_register(&lpc_ctrl->miscdev);
|
||||
if (rc)
|
||||
dev_err(dev, "Unable to register device\n");
|
||||
else
|
||||
dev_info(dev, "Loaded at %pr\n", &resm);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int aspeed_lpc_ctrl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct aspeed_lpc_ctrl *lpc_ctrl = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
misc_deregister(&lpc_ctrl->miscdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id aspeed_lpc_ctrl_match[] = {
|
||||
{ .compatible = "aspeed,ast2400-lpc-ctrl" },
|
||||
{ .compatible = "aspeed,ast2500-lpc-ctrl" },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver aspeed_lpc_ctrl_driver = {
|
||||
.driver = {
|
||||
.name = DEVICE_NAME,
|
||||
.of_match_table = aspeed_lpc_ctrl_match,
|
||||
},
|
||||
.probe = aspeed_lpc_ctrl_probe,
|
||||
.remove = aspeed_lpc_ctrl_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(aspeed_lpc_ctrl_driver);
|
||||
|
||||
MODULE_DEVICE_TABLE(of, aspeed_lpc_ctrl_match);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Cyril Bur <[email protected]>");
|
||||
MODULE_DESCRIPTION("Control for aspeed 2400/2500 LPC HOST to BMC mappings");
|
||||
|
|
@ -227,9 +227,16 @@ static const struct i2c_device_id ds1682_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ds1682_id);
|
||||
|
||||
static const struct of_device_id ds1682_of_match[] = {
|
||||
{ .compatible = "dallas,ds1682", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ds1682_of_match);
|
||||
|
||||
static struct i2c_driver ds1682_driver = {
|
||||
.driver = {
|
||||
.name = "ds1682",
|
||||
.of_match_table = ds1682_of_match,
|
||||
},
|
||||
.probe = ds1682_probe,
|
||||
.remove = ds1682_remove,
|
||||
|
|
|
|||
|
|
@ -1541,12 +1541,69 @@ static const struct i2c_device_id idt_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, idt_ids);
|
||||
|
||||
static const struct of_device_id idt_of_match[] = {
|
||||
{ .compatible = "idt,89hpes8nt2", },
|
||||
{ .compatible = "idt,89hpes12nt3", },
|
||||
|
||||
{ .compatible = "idt,89hpes24nt6ag2", },
|
||||
{ .compatible = "idt,89hpes32nt8ag2", },
|
||||
{ .compatible = "idt,89hpes32nt8bg2", },
|
||||
{ .compatible = "idt,89hpes12nt12g2", },
|
||||
{ .compatible = "idt,89hpes16nt16g2", },
|
||||
{ .compatible = "idt,89hpes24nt24g2", },
|
||||
{ .compatible = "idt,89hpes32nt24ag2", },
|
||||
{ .compatible = "idt,89hpes32nt24bg2", },
|
||||
|
||||
{ .compatible = "idt,89hpes12n3", },
|
||||
{ .compatible = "idt,89hpes12n3a", },
|
||||
{ .compatible = "idt,89hpes24n3", },
|
||||
{ .compatible = "idt,89hpes24n3a", },
|
||||
|
||||
{ .compatible = "idt,89hpes32h8", },
|
||||
{ .compatible = "idt,89hpes32h8g2", },
|
||||
{ .compatible = "idt,89hpes48h12", },
|
||||
{ .compatible = "idt,89hpes48h12g2", },
|
||||
{ .compatible = "idt,89hpes48h12ag2", },
|
||||
{ .compatible = "idt,89hpes16h16", },
|
||||
{ .compatible = "idt,89hpes22h16", },
|
||||
{ .compatible = "idt,89hpes22h16g2", },
|
||||
{ .compatible = "idt,89hpes34h16", },
|
||||
{ .compatible = "idt,89hpes34h16g2", },
|
||||
{ .compatible = "idt,89hpes64h16", },
|
||||
{ .compatible = "idt,89hpes64h16g2", },
|
||||
{ .compatible = "idt,89hpes64h16ag2", },
|
||||
|
||||
{ .compatible = "idt,89hpes12t3g2", },
|
||||
{ .compatible = "idt,89hpes24t3g2", },
|
||||
|
||||
{ .compatible = "idt,89hpes16t4", },
|
||||
{ .compatible = "idt,89hpes4t4g2", },
|
||||
{ .compatible = "idt,89hpes10t4g2", },
|
||||
{ .compatible = "idt,89hpes16t4g2", },
|
||||
{ .compatible = "idt,89hpes16t4ag2", },
|
||||
{ .compatible = "idt,89hpes5t5", },
|
||||
{ .compatible = "idt,89hpes6t5", },
|
||||
{ .compatible = "idt,89hpes8t5", },
|
||||
{ .compatible = "idt,89hpes8t5a", },
|
||||
{ .compatible = "idt,89hpes24t6", },
|
||||
{ .compatible = "idt,89hpes6t6g2", },
|
||||
{ .compatible = "idt,89hpes24t6g2", },
|
||||
{ .compatible = "idt,89hpes16t7", },
|
||||
{ .compatible = "idt,89hpes32t8", },
|
||||
{ .compatible = "idt,89hpes32t8g2", },
|
||||
{ .compatible = "idt,89hpes48t12", },
|
||||
{ .compatible = "idt,89hpes48t12g2", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, idt_of_match);
|
||||
|
||||
/*
|
||||
* idt_driver - IDT 89HPESx driver structure
|
||||
*/
|
||||
static struct i2c_driver idt_driver = {
|
||||
.driver = {
|
||||
.name = IDT_NAME,
|
||||
.of_match_table = idt_of_match,
|
||||
},
|
||||
.probe = idt_probe,
|
||||
.remove = idt_remove,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ void lkdtm_REFCOUNT_ZERO_SUB(void);
|
|||
void lkdtm_REFCOUNT_ZERO_ADD(void);
|
||||
void lkdtm_CORRUPT_LIST_ADD(void);
|
||||
void lkdtm_CORRUPT_LIST_DEL(void);
|
||||
void lkdtm_CORRUPT_USER_DS(void);
|
||||
|
||||
/* lkdtm_heap.c */
|
||||
void lkdtm_OVERWRITE_ALLOCATION(void);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
struct lkdtm_list {
|
||||
struct list_head node;
|
||||
|
|
@ -67,7 +69,7 @@ void lkdtm_WARNING(void)
|
|||
|
||||
void lkdtm_EXCEPTION(void)
|
||||
{
|
||||
*((int *) 0) = 0;
|
||||
*((volatile int *) 0) = 0;
|
||||
}
|
||||
|
||||
void lkdtm_LOOP(void)
|
||||
|
|
@ -279,3 +281,12 @@ void lkdtm_CORRUPT_LIST_DEL(void)
|
|||
else
|
||||
pr_err("list_del() corruption not detected!\n");
|
||||
}
|
||||
|
||||
void lkdtm_CORRUPT_USER_DS(void)
|
||||
{
|
||||
pr_info("setting bad task size limit\n");
|
||||
set_fs(KERNEL_DS);
|
||||
|
||||
/* Make sure we do not keep running with a KERNEL_DS! */
|
||||
force_sig(SIGKILL, current);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,6 +199,7 @@ struct crashtype crashtypes[] = {
|
|||
CRASHTYPE(OVERFLOW),
|
||||
CRASHTYPE(CORRUPT_LIST_ADD),
|
||||
CRASHTYPE(CORRUPT_LIST_DEL),
|
||||
CRASHTYPE(CORRUPT_USER_DS),
|
||||
CRASHTYPE(CORRUPT_STACK),
|
||||
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
|
||||
CRASHTYPE(OVERWRITE_ALLOCATION),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ mei-objs += hbm.o
|
|||
mei-objs += interrupt.o
|
||||
mei-objs += client.o
|
||||
mei-objs += main.o
|
||||
mei-objs += amthif.o
|
||||
mei-objs += bus.o
|
||||
mei-objs += bus-fixup.o
|
||||
mei-$(CONFIG_DEBUG_FS) += debugfs.o
|
||||
|
|
|
|||
|
|
@ -1,340 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Copyright (c) 2003-2012, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/mei.h>
|
||||
|
||||
#include "mei_dev.h"
|
||||
#include "hbm.h"
|
||||
#include "client.h"
|
||||
|
||||
const uuid_le mei_amthif_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
|
||||
0xac, 0xa8, 0x46, 0xe0,
|
||||
0xff, 0x65, 0x81, 0x4c);
|
||||
|
||||
/**
|
||||
* mei_amthif_reset_params - initializes mei device iamthif
|
||||
*
|
||||
* @dev: the device structure
|
||||
*/
|
||||
void mei_amthif_reset_params(struct mei_device *dev)
|
||||
{
|
||||
/* reset iamthif parameters. */
|
||||
dev->iamthif_canceled = false;
|
||||
dev->iamthif_state = MEI_IAMTHIF_IDLE;
|
||||
dev->iamthif_stall_timer = 0;
|
||||
dev->iamthif_open_count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_amthif_host_init - mei initialization amthif client.
|
||||
*
|
||||
* @dev: the device structure
|
||||
* @me_cl: me client
|
||||
*
|
||||
* Return: 0 on success, <0 on failure.
|
||||
*/
|
||||
int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
|
||||
{
|
||||
struct mei_cl *cl = &dev->iamthif_cl;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dev->device_lock);
|
||||
|
||||
if (mei_cl_is_connected(cl)) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
dev->iamthif_state = MEI_IAMTHIF_IDLE;
|
||||
|
||||
mei_cl_init(cl, dev);
|
||||
|
||||
ret = mei_cl_link(cl);
|
||||
if (ret < 0) {
|
||||
dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = mei_cl_connect(cl, me_cl, NULL);
|
||||
|
||||
out:
|
||||
mutex_unlock(&dev->device_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_amthif_read_start - queue message for sending read credential
|
||||
*
|
||||
* @cl: host client
|
||||
* @fp: file pointer of message recipient
|
||||
*
|
||||
* Return: 0 on success, <0 on failure.
|
||||
*/
|
||||
static int mei_amthif_read_start(struct mei_cl *cl, const struct file *fp)
|
||||
{
|
||||
struct mei_device *dev = cl->dev;
|
||||
struct mei_cl_cb *cb;
|
||||
|
||||
cb = mei_cl_enqueue_ctrl_wr_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, fp);
|
||||
if (!cb)
|
||||
return -ENOMEM;
|
||||
|
||||
cl->rx_flow_ctrl_creds++;
|
||||
|
||||
dev->iamthif_state = MEI_IAMTHIF_READING;
|
||||
cl->fp = cb->fp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_amthif_run_next_cmd - send next amt command from queue
|
||||
*
|
||||
* @dev: the device structure
|
||||
*
|
||||
* Return: 0 on success, <0 on failure.
|
||||
*/
|
||||
int mei_amthif_run_next_cmd(struct mei_device *dev)
|
||||
{
|
||||
struct mei_cl *cl = &dev->iamthif_cl;
|
||||
struct mei_cl_cb *cb;
|
||||
int ret;
|
||||
|
||||
dev->iamthif_canceled = false;
|
||||
|
||||
dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
|
||||
|
||||
cb = list_first_entry_or_null(&dev->amthif_cmd_list, typeof(*cb), list);
|
||||
if (!cb) {
|
||||
dev->iamthif_state = MEI_IAMTHIF_IDLE;
|
||||
cl->fp = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_del_init(&cb->list);
|
||||
dev->iamthif_state = MEI_IAMTHIF_WRITING;
|
||||
cl->fp = cb->fp;
|
||||
|
||||
ret = mei_cl_write(cl, cb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (cb->completed)
|
||||
cb->status = mei_amthif_read_start(cl, cb->fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_amthif_write - write amthif data to amthif client
|
||||
*
|
||||
* @cl: host client
|
||||
* @cb: mei call back struct
|
||||
*
|
||||
* Return: 0 on success, <0 on failure.
|
||||
*/
|
||||
int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
|
||||
{
|
||||
|
||||
struct mei_device *dev = cl->dev;
|
||||
|
||||
list_add_tail(&cb->list, &dev->amthif_cmd_list);
|
||||
|
||||
/*
|
||||
* The previous request is still in processing, queue this one.
|
||||
*/
|
||||
if (dev->iamthif_state != MEI_IAMTHIF_IDLE)
|
||||
return 0;
|
||||
|
||||
return mei_amthif_run_next_cmd(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_amthif_poll - the amthif poll function
|
||||
*
|
||||
* @file: pointer to file structure
|
||||
* @wait: pointer to poll_table structure
|
||||
*
|
||||
* Return: poll mask
|
||||
*
|
||||
* Locking: called under "dev->device_lock" lock
|
||||
*/
|
||||
unsigned int mei_amthif_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct mei_cl *cl = file->private_data;
|
||||
struct mei_cl_cb *cb = mei_cl_read_cb(cl, file);
|
||||
unsigned int mask = 0;
|
||||
|
||||
poll_wait(file, &cl->rx_wait, wait);
|
||||
if (cb)
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_amthif_irq_write - write iamthif command in irq thread context.
|
||||
*
|
||||
* @cl: private data of the file object.
|
||||
* @cb: callback block.
|
||||
* @cmpl_list: complete list.
|
||||
*
|
||||
* Return: 0, OK; otherwise, error.
|
||||
*/
|
||||
int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
|
||||
struct list_head *cmpl_list)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = mei_cl_irq_write(cl, cb, cmpl_list);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cb->completed)
|
||||
cb->status = mei_amthif_read_start(cl, cb->fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_amthif_irq_read_msg - read routine after ISR to
|
||||
* handle the read amthif message
|
||||
*
|
||||
* @cl: mei client
|
||||
* @mei_hdr: header of amthif message
|
||||
* @cmpl_list: completed callbacks list
|
||||
*
|
||||
* Return: -ENODEV if cb is NULL 0 otherwise; error message is in cb->status
|
||||
*/
|
||||
int mei_amthif_irq_read_msg(struct mei_cl *cl,
|
||||
struct mei_msg_hdr *mei_hdr,
|
||||
struct list_head *cmpl_list)
|
||||
{
|
||||
struct mei_device *dev;
|
||||
int ret;
|
||||
|
||||
dev = cl->dev;
|
||||
|
||||
if (dev->iamthif_state != MEI_IAMTHIF_READING) {
|
||||
mei_irq_discard_msg(dev, mei_hdr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!mei_hdr->msg_complete)
|
||||
return 0;
|
||||
|
||||
dev_dbg(dev->dev, "completed amthif read.\n ");
|
||||
dev->iamthif_stall_timer = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_amthif_complete - complete amthif callback.
|
||||
*
|
||||
* @cl: host client
|
||||
* @cb: callback block.
|
||||
*/
|
||||
void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
|
||||
{
|
||||
struct mei_device *dev = cl->dev;
|
||||
|
||||
dev_dbg(dev->dev, "completing amthif call back.\n");
|
||||
switch (cb->fop_type) {
|
||||
case MEI_FOP_WRITE:
|
||||
if (!cb->status) {
|
||||
dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
|
||||
mei_schedule_stall_timer(dev);
|
||||
mei_io_cb_free(cb);
|
||||
return;
|
||||
}
|
||||
dev->iamthif_state = MEI_IAMTHIF_IDLE;
|
||||
cl->fp = NULL;
|
||||
if (!dev->iamthif_canceled) {
|
||||
/*
|
||||
* in case of error enqueue the write cb to complete
|
||||
* read list so it can be propagated to the reader
|
||||
*/
|
||||
list_add_tail(&cb->list, &cl->rd_completed);
|
||||
wake_up_interruptible(&cl->rx_wait);
|
||||
} else {
|
||||
mei_io_cb_free(cb);
|
||||
}
|
||||
break;
|
||||
case MEI_FOP_READ:
|
||||
if (!dev->iamthif_canceled) {
|
||||
list_add_tail(&cb->list, &cl->rd_completed);
|
||||
dev_dbg(dev->dev, "amthif read completed\n");
|
||||
wake_up_interruptible(&cl->rx_wait);
|
||||
} else {
|
||||
mei_io_cb_free(cb);
|
||||
}
|
||||
|
||||
dev->iamthif_stall_timer = 0;
|
||||
mei_amthif_run_next_cmd(dev);
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_amthif_release - the release function
|
||||
*
|
||||
* @dev: device structure
|
||||
* @fp: pointer to file structure
|
||||
*
|
||||
* Return: 0 on success, <0 on error
|
||||
*/
|
||||
int mei_amthif_release(struct mei_device *dev, struct file *fp)
|
||||
{
|
||||
struct mei_cl *cl = fp->private_data;
|
||||
|
||||
if (dev->iamthif_open_count > 0)
|
||||
dev->iamthif_open_count--;
|
||||
|
||||
if (cl->fp == fp && dev->iamthif_state != MEI_IAMTHIF_IDLE) {
|
||||
|
||||
dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
|
||||
dev->iamthif_state);
|
||||
dev->iamthif_canceled = true;
|
||||
}
|
||||
|
||||
/* Don't clean ctrl_rd_list here, the reads has to be completed */
|
||||
mei_io_list_free_fp(&dev->amthif_cmd_list, fp);
|
||||
mei_io_list_free_fp(&cl->rd_completed, fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -110,12 +110,13 @@ struct mkhi_msg {
|
|||
u8 data[0];
|
||||
} __packed;
|
||||
|
||||
#define MKHI_OSVER_BUF_LEN (sizeof(struct mkhi_msg_hdr) + \
|
||||
sizeof(struct mkhi_fwcaps) + \
|
||||
sizeof(struct mei_os_ver))
|
||||
static int mei_osver(struct mei_cl_device *cldev)
|
||||
{
|
||||
const size_t size = sizeof(struct mkhi_msg_hdr) +
|
||||
sizeof(struct mkhi_fwcaps) +
|
||||
sizeof(struct mei_os_ver);
|
||||
char buf[size];
|
||||
const size_t size = MKHI_OSVER_BUF_LEN;
|
||||
char buf[MKHI_OSVER_BUF_LEN];
|
||||
struct mkhi_msg *req;
|
||||
struct mkhi_fwcaps *fwcaps;
|
||||
struct mei_os_ver *os_ver;
|
||||
|
|
|
|||
|
|
@ -1076,12 +1076,6 @@ void mei_cl_bus_rescan_work(struct work_struct *work)
|
|||
{
|
||||
struct mei_device *bus =
|
||||
container_of(work, struct mei_device, bus_rescan_work);
|
||||
struct mei_me_client *me_cl;
|
||||
|
||||
me_cl = mei_me_cl_by_uuid(bus, &mei_amthif_guid);
|
||||
if (me_cl)
|
||||
mei_amthif_host_init(bus, me_cl);
|
||||
mei_me_cl_put(me_cl);
|
||||
|
||||
mei_cl_bus_rescan(bus);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -428,7 +428,7 @@ static inline void mei_io_list_free_cl(struct list_head *head,
|
|||
* @head: io list
|
||||
* @fp: file pointer (matching cb file object), may be NULL
|
||||
*/
|
||||
void mei_io_list_free_fp(struct list_head *head, const struct file *fp)
|
||||
static void mei_io_list_free_fp(struct list_head *head, const struct file *fp)
|
||||
{
|
||||
struct mei_cl_cb *cb, *next;
|
||||
|
||||
|
|
@ -554,7 +554,7 @@ int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp)
|
|||
* @cl: host client to be initialized
|
||||
* @dev: mei device
|
||||
*/
|
||||
void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
|
||||
static void mei_cl_init(struct mei_cl *cl, struct mei_device *dev)
|
||||
{
|
||||
memset(cl, 0, sizeof(struct mei_cl));
|
||||
init_waitqueue_head(&cl->wait);
|
||||
|
|
@ -600,7 +600,6 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev)
|
|||
int mei_cl_link(struct mei_cl *cl)
|
||||
{
|
||||
struct mei_device *dev;
|
||||
long open_handle_count;
|
||||
int id;
|
||||
|
||||
if (WARN_ON(!cl || !cl->dev))
|
||||
|
|
@ -614,8 +613,7 @@ int mei_cl_link(struct mei_cl *cl)
|
|||
return -EMFILE;
|
||||
}
|
||||
|
||||
open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
|
||||
if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
|
||||
if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
|
||||
dev_err(dev->dev, "open_handle_count exceeded %d",
|
||||
MEI_MAX_OPEN_HANDLE_COUNT);
|
||||
return -EMFILE;
|
||||
|
|
@ -649,8 +647,7 @@ int mei_cl_unlink(struct mei_cl *cl)
|
|||
if (!cl)
|
||||
return 0;
|
||||
|
||||
/* amthif might not be initialized */
|
||||
if (!cl->dev)
|
||||
if (WARN_ON(!cl->dev))
|
||||
return 0;
|
||||
|
||||
dev = cl->dev;
|
||||
|
|
@ -763,7 +760,6 @@ static void mei_cl_set_disconnected(struct mei_cl *cl)
|
|||
mei_io_list_free_cl(&dev->write_waiting_list, cl);
|
||||
mei_io_list_flush_cl(&dev->ctrl_rd_list, cl);
|
||||
mei_io_list_flush_cl(&dev->ctrl_wr_list, cl);
|
||||
mei_io_list_free_cl(&dev->amthif_cmd_list, cl);
|
||||
mei_cl_wake_all(cl);
|
||||
cl->rx_flow_ctrl_creds = 0;
|
||||
cl->tx_flow_ctrl_creds = 0;
|
||||
|
|
@ -1478,7 +1474,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
|
|||
return -ENOTTY;
|
||||
}
|
||||
|
||||
if (mei_cl_is_fixed_address(cl) || cl == &dev->iamthif_cl)
|
||||
if (mei_cl_is_fixed_address(cl))
|
||||
return 0;
|
||||
|
||||
/* HW currently supports only one pending read */
|
||||
|
|
|
|||
|
|
@ -83,15 +83,12 @@ static inline u8 mei_me_cl_ver(const struct mei_me_client *me_cl)
|
|||
* MEI IO Functions
|
||||
*/
|
||||
void mei_io_cb_free(struct mei_cl_cb *priv_cb);
|
||||
void mei_io_list_free_fp(struct list_head *head, const struct file *fp);
|
||||
|
||||
/*
|
||||
* MEI Host Client Functions
|
||||
*/
|
||||
|
||||
struct mei_cl *mei_cl_allocate(struct mei_device *dev);
|
||||
void mei_cl_init(struct mei_cl *cl, struct mei_device *dev);
|
||||
|
||||
|
||||
int mei_cl_link(struct mei_cl *cl);
|
||||
int mei_cl_unlink(struct mei_cl *cl);
|
||||
|
|
@ -205,8 +202,6 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
|
|||
int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
|
||||
struct list_head *cmpl_list);
|
||||
int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp);
|
||||
int mei_cl_irq_read_msg(struct mei_cl *cl, struct mei_msg_hdr *hdr,
|
||||
struct list_head *cmpl_list);
|
||||
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb);
|
||||
int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
|
||||
struct list_head *cmpl_list);
|
||||
|
|
|
|||
|
|
@ -166,9 +166,8 @@ void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
|
|||
*
|
||||
* Return: 0 on success, <0 on failure.
|
||||
*/
|
||||
static inline
|
||||
int mei_hbm_cl_write(struct mei_device *dev, struct mei_cl *cl,
|
||||
u8 hbm_cmd, u8 *buf, size_t len)
|
||||
static inline int mei_hbm_cl_write(struct mei_device *dev, struct mei_cl *cl,
|
||||
u8 hbm_cmd, void *buf, size_t len)
|
||||
{
|
||||
struct mei_msg_hdr mei_hdr;
|
||||
|
||||
|
|
@ -632,11 +631,11 @@ static int mei_hbm_stop_req(struct mei_device *dev)
|
|||
*/
|
||||
int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
|
||||
{
|
||||
const size_t len = sizeof(struct hbm_flow_control);
|
||||
u8 buf[len];
|
||||
struct hbm_flow_control req;
|
||||
|
||||
cl_dbg(dev, cl, "sending flow control\n");
|
||||
return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD, buf, len);
|
||||
return mei_hbm_cl_write(dev, cl, MEI_FLOW_CONTROL_CMD,
|
||||
&req, sizeof(req));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -710,10 +709,10 @@ static void mei_hbm_cl_tx_flow_ctrl_creds_res(struct mei_device *dev,
|
|||
*/
|
||||
int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
|
||||
{
|
||||
const size_t len = sizeof(struct hbm_client_connect_request);
|
||||
u8 buf[len];
|
||||
struct hbm_client_connect_request req;
|
||||
|
||||
return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD, buf, len);
|
||||
return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_REQ_CMD,
|
||||
&req, sizeof(req));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -726,10 +725,10 @@ int mei_hbm_cl_disconnect_req(struct mei_device *dev, struct mei_cl *cl)
|
|||
*/
|
||||
int mei_hbm_cl_disconnect_rsp(struct mei_device *dev, struct mei_cl *cl)
|
||||
{
|
||||
const size_t len = sizeof(struct hbm_client_connect_response);
|
||||
u8 buf[len];
|
||||
struct hbm_client_connect_response resp;
|
||||
|
||||
return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD, buf, len);
|
||||
return mei_hbm_cl_write(dev, cl, CLIENT_DISCONNECT_RES_CMD,
|
||||
&resp, sizeof(resp));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -763,10 +762,10 @@ static void mei_hbm_cl_disconnect_res(struct mei_device *dev, struct mei_cl *cl,
|
|||
*/
|
||||
int mei_hbm_cl_connect_req(struct mei_device *dev, struct mei_cl *cl)
|
||||
{
|
||||
const size_t len = sizeof(struct hbm_client_connect_request);
|
||||
u8 buf[len];
|
||||
struct hbm_client_connect_request req;
|
||||
|
||||
return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD, buf, len);
|
||||
return mei_hbm_cl_write(dev, cl, CLIENT_CONNECT_REQ_CMD,
|
||||
&req, sizeof(req));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -146,18 +146,9 @@ int mei_reset(struct mei_device *dev)
|
|||
/* fall through and remove the sw state even if hw reset has failed */
|
||||
|
||||
/* no need to clean up software state in case of power up */
|
||||
if (state != MEI_DEV_INITIALIZING &&
|
||||
state != MEI_DEV_POWER_UP) {
|
||||
|
||||
/* remove all waiting requests */
|
||||
if (state != MEI_DEV_INITIALIZING && state != MEI_DEV_POWER_UP)
|
||||
mei_cl_all_disconnect(dev);
|
||||
|
||||
/* remove entry if already in list */
|
||||
dev_dbg(dev->dev, "remove iamthif from the file list.\n");
|
||||
mei_cl_unlink(&dev->iamthif_cl);
|
||||
mei_amthif_reset_params(dev);
|
||||
}
|
||||
|
||||
mei_hbm_reset(dev);
|
||||
|
||||
dev->rd_msg_hdr = 0;
|
||||
|
|
@ -401,9 +392,6 @@ void mei_device_init(struct mei_device *dev,
|
|||
INIT_WORK(&dev->reset_work, mei_reset_work);
|
||||
INIT_WORK(&dev->bus_rescan_work, mei_cl_bus_rescan_work);
|
||||
|
||||
INIT_LIST_HEAD(&dev->iamthif_cl.link);
|
||||
INIT_LIST_HEAD(&dev->amthif_cmd_list);
|
||||
|
||||
bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX);
|
||||
dev->open_handle_count = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -47,10 +47,7 @@ void mei_irq_compl_handler(struct mei_device *dev, struct list_head *cmpl_list)
|
|||
list_del_init(&cb->list);
|
||||
|
||||
dev_dbg(dev->dev, "completing call back.\n");
|
||||
if (cl == &dev->iamthif_cl)
|
||||
mei_amthif_complete(cl, cb);
|
||||
else
|
||||
mei_cl_complete(cl, cb);
|
||||
mei_cl_complete(cl, cb);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mei_irq_compl_handler);
|
||||
|
|
@ -76,7 +73,7 @@ static inline int mei_cl_hbm_equal(struct mei_cl *cl,
|
|||
* @dev: mei device
|
||||
* @hdr: message header
|
||||
*/
|
||||
void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr)
|
||||
static void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr)
|
||||
{
|
||||
/*
|
||||
* no need to check for size as it is guarantied
|
||||
|
|
@ -96,9 +93,9 @@ void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr)
|
|||
*
|
||||
* Return: always 0
|
||||
*/
|
||||
int mei_cl_irq_read_msg(struct mei_cl *cl,
|
||||
struct mei_msg_hdr *mei_hdr,
|
||||
struct list_head *cmpl_list)
|
||||
static int mei_cl_irq_read_msg(struct mei_cl *cl,
|
||||
struct mei_msg_hdr *mei_hdr,
|
||||
struct list_head *cmpl_list)
|
||||
{
|
||||
struct mei_device *dev = cl->dev;
|
||||
struct mei_cl_cb *cb;
|
||||
|
|
@ -313,11 +310,7 @@ int mei_irq_read_handler(struct mei_device *dev,
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (cl == &dev->iamthif_cl) {
|
||||
ret = mei_amthif_irq_read_msg(cl, mei_hdr, cmpl_list);
|
||||
} else {
|
||||
ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
|
||||
}
|
||||
ret = mei_cl_irq_read_msg(cl, mei_hdr, cmpl_list);
|
||||
|
||||
|
||||
reset_slots:
|
||||
|
|
@ -423,10 +416,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list)
|
|||
dev_dbg(dev->dev, "complete write list cb.\n");
|
||||
list_for_each_entry_safe(cb, next, &dev->write_list, list) {
|
||||
cl = cb->cl;
|
||||
if (cl == &dev->iamthif_cl)
|
||||
ret = mei_amthif_irq_write(cl, cb, cmpl_list);
|
||||
else
|
||||
ret = mei_cl_irq_write(cl, cb, cmpl_list);
|
||||
ret = mei_cl_irq_write(cl, cb, cmpl_list);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -512,20 +502,6 @@ void mei_timer(struct work_struct *work)
|
|||
}
|
||||
}
|
||||
|
||||
if (!mei_cl_is_connected(&dev->iamthif_cl))
|
||||
goto out;
|
||||
|
||||
if (dev->iamthif_stall_timer) {
|
||||
if (--dev->iamthif_stall_timer == 0) {
|
||||
dev_err(dev->dev, "timer: amthif hanged.\n");
|
||||
mei_reset(dev);
|
||||
|
||||
mei_amthif_run_next_cmd(dev);
|
||||
goto out;
|
||||
}
|
||||
reschedule_timer = true;
|
||||
}
|
||||
|
||||
out:
|
||||
if (dev->dev_state != MEI_DEV_DISABLED && reschedule_timer)
|
||||
mei_schedule_stall_timer(dev);
|
||||
|
|
|
|||
|
|
@ -103,10 +103,7 @@ static int mei_release(struct inode *inode, struct file *file)
|
|||
dev = cl->dev;
|
||||
|
||||
mutex_lock(&dev->device_lock);
|
||||
if (cl == &dev->iamthif_cl) {
|
||||
rets = mei_amthif_release(dev, file);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rets = mei_cl_disconnect(cl);
|
||||
|
||||
mei_cl_flush_queues(cl, file);
|
||||
|
|
@ -117,7 +114,7 @@ static int mei_release(struct inode *inode, struct file *file)
|
|||
file->private_data = NULL;
|
||||
|
||||
kfree(cl);
|
||||
out:
|
||||
|
||||
mutex_unlock(&dev->device_lock);
|
||||
return rets;
|
||||
}
|
||||
|
|
@ -182,8 +179,6 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
|
|||
goto out;
|
||||
}
|
||||
|
||||
|
||||
again:
|
||||
mutex_unlock(&dev->device_lock);
|
||||
if (wait_event_interruptible(cl->rx_wait,
|
||||
!list_empty(&cl->rd_completed) ||
|
||||
|
|
@ -201,14 +196,6 @@ again:
|
|||
|
||||
cb = mei_cl_read_cb(cl, file);
|
||||
if (!cb) {
|
||||
/*
|
||||
* For amthif all the waiters are woken up,
|
||||
* but only fp with matching cb->fp get the cb,
|
||||
* the others have to return to wait on read.
|
||||
*/
|
||||
if (cl == &dev->iamthif_cl)
|
||||
goto again;
|
||||
|
||||
rets = 0;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -319,13 +306,6 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (cl == &dev->iamthif_cl) {
|
||||
rets = mei_amthif_write(cl, cb);
|
||||
if (!rets)
|
||||
rets = length;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rets = mei_cl_write(cl, cb);
|
||||
out:
|
||||
mutex_unlock(&dev->device_lock);
|
||||
|
|
@ -388,30 +368,6 @@ static int mei_ioctl_connect_client(struct file *file,
|
|||
dev_dbg(dev->dev, "FW Client - Max Msg Len = %d\n",
|
||||
me_cl->props.max_msg_length);
|
||||
|
||||
/* if we're connecting to amthif client then we will use the
|
||||
* existing connection
|
||||
*/
|
||||
if (uuid_le_cmp(data->in_client_uuid, mei_amthif_guid) == 0) {
|
||||
dev_dbg(dev->dev, "FW Client is amthi\n");
|
||||
if (!mei_cl_is_connected(&dev->iamthif_cl)) {
|
||||
rets = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
mei_cl_unlink(cl);
|
||||
|
||||
kfree(cl);
|
||||
cl = NULL;
|
||||
dev->iamthif_open_count++;
|
||||
file->private_data = &dev->iamthif_cl;
|
||||
|
||||
client = &data->out_client_properties;
|
||||
client->max_msg_length = me_cl->props.max_msg_length;
|
||||
client->protocol_version = me_cl->props.protocol_version;
|
||||
rets = dev->iamthif_cl.status;
|
||||
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* prepare the output buffer */
|
||||
client = &data->out_client_properties;
|
||||
client->max_msg_length = me_cl->props.max_msg_length;
|
||||
|
|
@ -615,11 +571,6 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
|
|||
mask |= POLLPRI;
|
||||
}
|
||||
|
||||
if (cl == &dev->iamthif_cl) {
|
||||
mask |= mei_amthif_poll(file, wait);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (req_events & (POLLIN | POLLRDNORM)) {
|
||||
poll_wait(file, &cl->rx_wait, wait);
|
||||
|
||||
|
|
@ -634,6 +585,77 @@ out:
|
|||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_cl_is_write_queued - check if the client has pending writes.
|
||||
*
|
||||
* @cl: writing host client
|
||||
*
|
||||
* Return: true if client is writing, false otherwise.
|
||||
*/
|
||||
static bool mei_cl_is_write_queued(struct mei_cl *cl)
|
||||
{
|
||||
struct mei_device *dev = cl->dev;
|
||||
struct mei_cl_cb *cb;
|
||||
|
||||
list_for_each_entry(cb, &dev->write_list, list)
|
||||
if (cb->cl == cl)
|
||||
return true;
|
||||
list_for_each_entry(cb, &dev->write_waiting_list, list)
|
||||
if (cb->cl == cl)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_fsync - the fsync handler
|
||||
*
|
||||
* @fp: pointer to file structure
|
||||
* @start: unused
|
||||
* @end: unused
|
||||
* @datasync: unused
|
||||
*
|
||||
* Return: 0 on success, -ENODEV if client is not connected
|
||||
*/
|
||||
static int mei_fsync(struct file *fp, loff_t start, loff_t end, int datasync)
|
||||
{
|
||||
struct mei_cl *cl = fp->private_data;
|
||||
struct mei_device *dev;
|
||||
int rets;
|
||||
|
||||
if (WARN_ON(!cl || !cl->dev))
|
||||
return -ENODEV;
|
||||
|
||||
dev = cl->dev;
|
||||
|
||||
mutex_lock(&dev->device_lock);
|
||||
|
||||
if (dev->dev_state != MEI_DEV_ENABLED || !mei_cl_is_connected(cl)) {
|
||||
rets = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (mei_cl_is_write_queued(cl)) {
|
||||
mutex_unlock(&dev->device_lock);
|
||||
rets = wait_event_interruptible(cl->tx_wait,
|
||||
cl->writing_state == MEI_WRITE_COMPLETE ||
|
||||
!mei_cl_is_connected(cl));
|
||||
mutex_lock(&dev->device_lock);
|
||||
if (rets) {
|
||||
if (signal_pending(current))
|
||||
rets = -EINTR;
|
||||
goto out;
|
||||
}
|
||||
if (!mei_cl_is_connected(cl)) {
|
||||
rets = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
rets = 0;
|
||||
out:
|
||||
mutex_unlock(&dev->device_lock);
|
||||
return rets;
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_fasync - asynchronous io support
|
||||
*
|
||||
|
|
@ -749,6 +771,7 @@ static const struct file_operations mei_fops = {
|
|||
.release = mei_release,
|
||||
.write = mei_write,
|
||||
.poll = mei_poll,
|
||||
.fsync = mei_fsync,
|
||||
.fasync = mei_fasync,
|
||||
.llseek = no_llseek
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,12 +26,6 @@
|
|||
#include "hw.h"
|
||||
#include "hbm.h"
|
||||
|
||||
|
||||
/*
|
||||
* AMTHI Client UUID
|
||||
*/
|
||||
extern const uuid_le mei_amthif_guid;
|
||||
|
||||
#define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32))
|
||||
|
||||
/*
|
||||
|
|
@ -78,12 +72,6 @@ enum mei_dev_state {
|
|||
|
||||
const char *mei_dev_state_str(int state);
|
||||
|
||||
enum iamthif_states {
|
||||
MEI_IAMTHIF_IDLE,
|
||||
MEI_IAMTHIF_WRITING,
|
||||
MEI_IAMTHIF_READING,
|
||||
};
|
||||
|
||||
enum mei_file_transaction_states {
|
||||
MEI_IDLE,
|
||||
MEI_WRITING,
|
||||
|
|
@ -418,13 +406,6 @@ const char *mei_pg_state_str(enum mei_pg_state state);
|
|||
* @allow_fixed_address: allow user space to connect a fixed client
|
||||
* @override_fixed_address: force allow fixed address behavior
|
||||
*
|
||||
* @amthif_cmd_list : amthif list for cmd waiting
|
||||
* @iamthif_cl : amthif host client
|
||||
* @iamthif_open_count : number of opened amthif connections
|
||||
* @iamthif_stall_timer : timer to detect amthif hang
|
||||
* @iamthif_state : amthif processor state
|
||||
* @iamthif_canceled : current amthif command is canceled
|
||||
*
|
||||
* @reset_work : work item for the device reset
|
||||
* @bus_rescan_work : work item for the bus rescan
|
||||
*
|
||||
|
|
@ -500,14 +481,6 @@ struct mei_device {
|
|||
bool allow_fixed_address;
|
||||
bool override_fixed_address;
|
||||
|
||||
/* amthif list for cmd waiting */
|
||||
struct list_head amthif_cmd_list;
|
||||
struct mei_cl iamthif_cl;
|
||||
long iamthif_open_count;
|
||||
u32 iamthif_stall_timer;
|
||||
enum iamthif_states iamthif_state;
|
||||
bool iamthif_canceled;
|
||||
|
||||
struct work_struct reset_work;
|
||||
struct work_struct bus_rescan_work;
|
||||
|
||||
|
|
@ -578,28 +551,6 @@ int mei_irq_read_handler(struct mei_device *dev,
|
|||
int mei_irq_write_handler(struct mei_device *dev, struct list_head *cmpl_list);
|
||||
void mei_irq_compl_handler(struct mei_device *dev, struct list_head *cmpl_list);
|
||||
|
||||
/*
|
||||
* AMTHIF - AMT Host Interface Functions
|
||||
*/
|
||||
void mei_amthif_reset_params(struct mei_device *dev);
|
||||
|
||||
int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl);
|
||||
|
||||
unsigned int mei_amthif_poll(struct file *file, poll_table *wait);
|
||||
|
||||
int mei_amthif_release(struct mei_device *dev, struct file *file);
|
||||
|
||||
int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb);
|
||||
int mei_amthif_run_next_cmd(struct mei_device *dev);
|
||||
int mei_amthif_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
|
||||
struct list_head *cmpl_list);
|
||||
|
||||
void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb);
|
||||
int mei_amthif_irq_read_msg(struct mei_cl *cl,
|
||||
struct mei_msg_hdr *mei_hdr,
|
||||
struct list_head *cmpl_list);
|
||||
int mei_amthif_irq_read(struct mei_device *dev, s32 *slots);
|
||||
|
||||
/*
|
||||
* Register Access Function
|
||||
*/
|
||||
|
|
@ -711,8 +662,6 @@ bool mei_hbuf_acquire(struct mei_device *dev);
|
|||
|
||||
bool mei_write_is_idle(struct mei_device *dev);
|
||||
|
||||
void mei_irq_discard_msg(struct mei_device *dev, struct mei_msg_hdr *hdr);
|
||||
|
||||
#if IS_ENABLED(CONFIG_DEBUG_FS)
|
||||
int mei_dbgfs_register(struct mei_device *dev, const char *name);
|
||||
void mei_dbgfs_deregister(struct mei_device *dev);
|
||||
|
|
|
|||
|
|
@ -241,12 +241,39 @@ end:
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_me_shutdown - Device Removal Routine
|
||||
*
|
||||
* @pdev: PCI device structure
|
||||
*
|
||||
* mei_me_shutdown is called from the reboot notifier
|
||||
* it's a simplified version of remove so we go down
|
||||
* faster.
|
||||
*/
|
||||
static void mei_me_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
struct mei_device *dev;
|
||||
|
||||
dev = pci_get_drvdata(pdev);
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
dev_dbg(&pdev->dev, "shutdown\n");
|
||||
mei_stop(dev);
|
||||
|
||||
if (!pci_dev_run_wake(pdev))
|
||||
mei_me_unset_pm_domain(dev);
|
||||
|
||||
mei_disable_interrupts(dev);
|
||||
free_irq(pdev->irq, dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_me_remove - Device Removal Routine
|
||||
*
|
||||
* @pdev: PCI device structure
|
||||
*
|
||||
* mei_remove is called by the PCI subsystem to alert the driver
|
||||
* mei_me_remove is called by the PCI subsystem to alert the driver
|
||||
* that it should release a PCI device.
|
||||
*/
|
||||
static void mei_me_remove(struct pci_dev *pdev)
|
||||
|
|
@ -456,7 +483,7 @@ static struct pci_driver mei_me_driver = {
|
|||
.id_table = mei_me_pci_tbl,
|
||||
.probe = mei_me_probe,
|
||||
.remove = mei_me_remove,
|
||||
.shutdown = mei_me_remove,
|
||||
.shutdown = mei_me_shutdown,
|
||||
.driver.pm = MEI_ME_PM_OPS,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -160,6 +160,33 @@ end:
|
|||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_txe_remove - Device Shutdown Routine
|
||||
*
|
||||
* @pdev: PCI device structure
|
||||
*
|
||||
* mei_txe_shutdown is called from the reboot notifier
|
||||
* it's a simplified version of remove so we go down
|
||||
* faster.
|
||||
*/
|
||||
static void mei_txe_shutdown(struct pci_dev *pdev)
|
||||
{
|
||||
struct mei_device *dev;
|
||||
|
||||
dev = pci_get_drvdata(pdev);
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
dev_dbg(&pdev->dev, "shutdown\n");
|
||||
mei_stop(dev);
|
||||
|
||||
if (!pci_dev_run_wake(pdev))
|
||||
mei_txe_unset_pm_domain(dev);
|
||||
|
||||
mei_disable_interrupts(dev);
|
||||
free_irq(pdev->irq, dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* mei_txe_remove - Device Removal Routine
|
||||
*
|
||||
|
|
@ -386,7 +413,7 @@ static struct pci_driver mei_txe_driver = {
|
|||
.id_table = mei_txe_pci_tbl,
|
||||
.probe = mei_txe_probe,
|
||||
.remove = mei_txe_remove,
|
||||
.shutdown = mei_txe_remove,
|
||||
.shutdown = mei_txe_shutdown,
|
||||
.driver.pm = MEI_TXE_PM_OPS,
|
||||
};
|
||||
|
||||
|
|
|
|||
2439
drivers/misc/panel.c
2439
drivers/misc/panel.c
File diff suppressed because it is too large
Load diff
|
|
@ -443,9 +443,16 @@ static const struct i2c_device_id tsl2550_id[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tsl2550_id);
|
||||
|
||||
static const struct of_device_id tsl2550_of_match[] = {
|
||||
{ .compatible = "taos,tsl2550" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tsl2550_of_match);
|
||||
|
||||
static struct i2c_driver tsl2550_driver = {
|
||||
.driver = {
|
||||
.name = TSL2550_DRV_NAME,
|
||||
.of_match_table = tsl2550_of_match,
|
||||
.pm = TSL2550_PM_OPS,
|
||||
},
|
||||
.probe = tsl2550_probe,
|
||||
|
|
|
|||
Loading…
Reference in a new issue