char/misc driver merge for 3.7-rc1
Here is the "big" char/misc driver tree update for the 3.7-rc1 merge window. Nothing major, just a number of driver updates and fixes, all of which have been in the linux-next releases for a while now either in my tree, or in Andrew's (the lis3l driver changes came from his tree last week). Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iEYEABECAAYFAlBp3pcACgkQMUfUDdst+ymLswCcDYG9RkRcEdYwT5bOm1zM4IVl WM0AoLKfC86g6xe4MdS7zROJn7ep/9qu =zAHk -----END PGP SIGNATURE----- Merge tag 'char-misc-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc Pull char/misc driver merge from Greg Kroah-Hartman: "Here is the "big" char/misc driver tree update for the 3.7-rc1 merge window. Nothing major, just a number of driver updates and fixes, all of which have been in the linux-next releases for a while now either in my tree, or in Andrew's (the lis3l driver changes came from his tree last week). Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" * tag 'char-misc-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (52 commits) drivers/misc/lis3lv02d/lis3lv02d_i2c.c: add lis3lv02d device tree init drivers/misc/lis3lv02d/lis3lv02d_spi.c: add lis3lv02d device tree init drivers/misc/lis3lv02d: remove lis3lv02d driver DT init drivers/misc/lis3lv02d/lis3lv02d_spi.c: add DT matching table passthru code drivers/misc/lis3lv02d: add generic DT matching code lis3lv02d: fix some comments specific to lis331dlh driver MISC: hpilo, remove pci_disable_device pcmcia: synclink_cs: fix potential tty NULL dereference drivers/char/mmtimer.c: Remove useless kfree drivers/char: removes unnecessary semicolon char/misc: remove CONFIG_EXPERIMENTAL dependencies mei: don't print buffer as a string mei: struct mei_message_data doesn't have to be packed mei: add error messages for open count errors misc: use module_spi_driver tifm: use module_pci_driver misc/at25, dt: Improve at25 SPI eeprom device tree bindings. mei: add lynx point pci device ids mei: fix max number of open handles mei: rename struct pci_dev *mei_device to mei_pdev ...
This commit is contained in:
commit
3aebd34b12
|
@ -1,21 +1,35 @@
|
||||||
Atmel AT25 eeprom
|
EEPROMs (SPI) compatible with Atmel at25.
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible : "atmel,at25".
|
- compatible : "atmel,at25".
|
||||||
- reg : chip select number
|
- reg : chip select number
|
||||||
- spi-max-frequency : max spi frequency to use
|
- spi-max-frequency : max spi frequency to use
|
||||||
|
- pagesize : size of the eeprom page
|
||||||
|
- size : total eeprom size in bytes
|
||||||
|
- address-width : number of address bits (one of 8, 16, or 24)
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- spi-cpha : SPI shifted clock phase, as per spi-bus bindings.
|
||||||
|
- spi-cpol : SPI inverse clock polarity, as per spi-bus bindings.
|
||||||
|
- read-only : this parameter-less property disables writes to the eeprom
|
||||||
|
|
||||||
|
Obsolete legacy properties are can be used in place of "size", "pagesize",
|
||||||
|
"address-width", and "read-only":
|
||||||
- at25,byte-len : total eeprom size in bytes
|
- at25,byte-len : total eeprom size in bytes
|
||||||
- at25,addr-mode : addr-mode flags, as defined in include/linux/spi/eeprom.h
|
- at25,addr-mode : addr-mode flags, as defined in include/linux/spi/eeprom.h
|
||||||
- at25,page-size : size of the eeprom page
|
- at25,page-size : size of the eeprom page
|
||||||
|
|
||||||
Examples:
|
Additional compatible properties are also allowed.
|
||||||
at25@0 {
|
|
||||||
compatible = "atmel,at25";
|
|
||||||
reg = <0>
|
|
||||||
spi-max-frequency = <5000000>;
|
|
||||||
|
|
||||||
at25,byte-len = <0x8000>;
|
Example:
|
||||||
at25,addr-mode = <2>;
|
at25@0 {
|
||||||
at25,page-size = <64>;
|
compatible = "atmel,at25", "st,m95256";
|
||||||
};
|
reg = <0>
|
||||||
|
spi-max-frequency = <5000000>;
|
||||||
|
spi-cpha;
|
||||||
|
spi-cpol;
|
||||||
|
|
||||||
|
pagesize = <64>;
|
||||||
|
size = <32768>;
|
||||||
|
address-width = <16>;
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
LIS302 accelerometer devicetree bindings
|
||||||
|
|
||||||
|
This device is matched via its bus drivers, and has a number of properties
|
||||||
|
that apply in on the generic device (independent from the bus).
|
||||||
|
|
||||||
|
|
||||||
|
Required properties for the SPI bindings:
|
||||||
|
- compatible: should be set to "st,lis3lv02d_spi"
|
||||||
|
- reg: the chipselect index
|
||||||
|
- spi-max-frequency: maximal bus speed, should be set to 1000000 unless
|
||||||
|
constrained by external circuitry
|
||||||
|
- interrupts: the interrupt generated by the device
|
||||||
|
|
||||||
|
Required properties for the I2C bindings:
|
||||||
|
- compatible: should be set to "st,lis3lv02d"
|
||||||
|
- reg: i2c slave address
|
||||||
|
- Vdd-supply: The input supply for Vdd
|
||||||
|
- Vdd_IO-supply: The input supply for Vdd_IO
|
||||||
|
|
||||||
|
|
||||||
|
Optional properties for all bus drivers:
|
||||||
|
|
||||||
|
- st,click-single-{x,y,z}: if present, tells the device to issue an
|
||||||
|
interrupt on single click events on the
|
||||||
|
x/y/z axis.
|
||||||
|
- st,click-double-{x,y,z}: if present, tells the device to issue an
|
||||||
|
interrupt on double click events on the
|
||||||
|
x/y/z axis.
|
||||||
|
- st,click-thresh-{x,y,z}: set the x/y/z axis threshold
|
||||||
|
- st,click-click-time-limit: click time limit, from 0 to 127.5msec
|
||||||
|
with step of 0.5 msec
|
||||||
|
- st,click-latency: click latency, from 0 to 255 msec with
|
||||||
|
step of 1 msec.
|
||||||
|
- st,click-window: click window, from 0 to 255 msec with
|
||||||
|
step of 1 msec.
|
||||||
|
- st,irq{1,2}-disable: disable IRQ 1/2
|
||||||
|
- st,irq{1,2}-ff-wu-1: raise IRQ 1/2 on FF_WU_1 condition
|
||||||
|
- st,irq{1,2}-ff-wu-2: raise IRQ 1/2 on FF_WU_2 condition
|
||||||
|
- st,irq{1,2}-data-ready: raise IRQ 1/2 on data ready contition
|
||||||
|
- st,irq{1,2}-click: raise IRQ 1/2 on click condition
|
||||||
|
- st,irq-open-drain: consider IRQ lines open-drain
|
||||||
|
- st,irq-active-low: make IRQ lines active low
|
||||||
|
- st,wu-duration-1: duration register for Free-Fall/Wake-Up
|
||||||
|
interrupt 1
|
||||||
|
- st,wu-duration-2: duration register for Free-Fall/Wake-Up
|
||||||
|
interrupt 2
|
||||||
|
- st,wakeup-{x,y,z}-{lo,hi}: set wakeup condition on x/y/z axis for
|
||||||
|
upper/lower limit
|
||||||
|
- st,highpass-cutoff-hz=: 1, 2, 4 or 8 for 1Hz, 2Hz, 4Hz or 8Hz of
|
||||||
|
highpass cut-off frequency
|
||||||
|
- st,hipass{1,2}-disable: disable highpass 1/2.
|
||||||
|
- st,default-rate=: set the default rate
|
||||||
|
- st,axis-{x,y,z}=: set the axis to map to the three coordinates
|
||||||
|
- st,{min,max}-limit-{x,y,z} set the min/max limits for x/y/z axis
|
||||||
|
(used by self-test)
|
||||||
|
|
||||||
|
|
||||||
|
Example for a SPI device node:
|
||||||
|
|
||||||
|
lis302@0 {
|
||||||
|
compatible = "st,lis302dl-spi";
|
||||||
|
reg = <0>;
|
||||||
|
spi-max-frequency = <1000000>;
|
||||||
|
interrupt-parent = <&gpio>;
|
||||||
|
interrupts = <104 0>;
|
||||||
|
|
||||||
|
st,click-single-x;
|
||||||
|
st,click-single-y;
|
||||||
|
st,click-single-z;
|
||||||
|
st,click-thresh-x = <10>;
|
||||||
|
st,click-thresh-y = <10>;
|
||||||
|
st,click-thresh-z = <10>;
|
||||||
|
st,irq1-click;
|
||||||
|
st,irq2-click;
|
||||||
|
st,wakeup-x-lo;
|
||||||
|
st,wakeup-x-hi;
|
||||||
|
st,wakeup-y-lo;
|
||||||
|
st,wakeup-y-hi;
|
||||||
|
st,wakeup-z-lo;
|
||||||
|
st,wakeup-z-hi;
|
||||||
|
};
|
||||||
|
|
||||||
|
Example for a I2C device node:
|
||||||
|
|
||||||
|
lis331dlh: lis331dlh@18 {
|
||||||
|
compatible = "st,lis331dlh", "st,lis3lv02d";
|
||||||
|
reg = <0x18>;
|
||||||
|
Vdd-supply = <&lis3_reg>;
|
||||||
|
Vdd_IO-supply = <&lis3_reg>;
|
||||||
|
|
||||||
|
st,click-single-x;
|
||||||
|
st,click-single-y;
|
||||||
|
st,click-single-z;
|
||||||
|
st,click-thresh-x = <10>;
|
||||||
|
st,click-thresh-y = <10>;
|
||||||
|
st,click-thresh-z = <10>;
|
||||||
|
st,irq1-click;
|
||||||
|
st,irq2-click;
|
||||||
|
st,wakeup-x-lo;
|
||||||
|
st,wakeup-x-hi;
|
||||||
|
st,wakeup-y-lo;
|
||||||
|
st,wakeup-y-hi;
|
||||||
|
st,wakeup-z-lo;
|
||||||
|
st,wakeup-z-hi;
|
||||||
|
st,min-limit-x = <120>;
|
||||||
|
st,min-limit-y = <120>;
|
||||||
|
st,min-limit-z = <140>;
|
||||||
|
st,max-limit-x = <550>;
|
||||||
|
st,max-limit-y = <550>;
|
||||||
|
st,max-limit-z = <750>;
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
w1-gpio devicetree bindings
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
|
||||||
|
- compatible: "w1-gpio"
|
||||||
|
- gpios: one or two GPIO specs:
|
||||||
|
- the first one is used as data I/O pin
|
||||||
|
- the second one is optional. If specified, it is used as
|
||||||
|
enable pin for an external pin pullup.
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
|
||||||
|
- linux,open-drain: if specified, the data pin is considered in
|
||||||
|
open-drain mode.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
onewire@0 {
|
||||||
|
compatible = "w1-gpio";
|
||||||
|
gpios = <&gpio 126 0>, <&gpio 105 0>;
|
||||||
|
};
|
||||||
|
|
|
@ -4,7 +4,8 @@ Kernel driver lis3lv02d
|
||||||
Supported chips:
|
Supported chips:
|
||||||
|
|
||||||
* STMicroelectronics LIS3LV02DL, LIS3LV02DQ (12 bits precision)
|
* STMicroelectronics LIS3LV02DL, LIS3LV02DQ (12 bits precision)
|
||||||
* STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits)
|
* STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits) and
|
||||||
|
LIS331DLH (16 bits)
|
||||||
|
|
||||||
Authors:
|
Authors:
|
||||||
Yan Burman <burman.yan@gmail.com>
|
Yan Burman <burman.yan@gmail.com>
|
||||||
|
|
|
@ -418,8 +418,8 @@ config APPLICOM
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
config SONYPI
|
config SONYPI
|
||||||
tristate "Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)"
|
tristate "Sony Vaio Programmable I/O Control Device support"
|
||||||
depends on EXPERIMENTAL && X86 && PCI && INPUT && !64BIT
|
depends on X86 && PCI && INPUT && !64BIT
|
||||||
---help---
|
---help---
|
||||||
This driver enables access to the Sony Programmable I/O Control
|
This driver enables access to the Sony Programmable I/O Control
|
||||||
Device which can be found in many (all ?) Sony Vaio laptops.
|
Device which can be found in many (all ?) Sony Vaio laptops.
|
||||||
|
@ -566,7 +566,7 @@ source "drivers/char/tpm/Kconfig"
|
||||||
|
|
||||||
config TELCLOCK
|
config TELCLOCK
|
||||||
tristate "Telecom clock driver for ATCA SBC"
|
tristate "Telecom clock driver for ATCA SBC"
|
||||||
depends on EXPERIMENTAL && X86
|
depends on X86
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
The telecom clock device is specific to the MPCBL0010 and MPCBL0050
|
The telecom clock device is specific to the MPCBL0010 and MPCBL0050
|
||||||
|
|
|
@ -826,7 +826,7 @@ static int __init mmtimer_init(void)
|
||||||
|
|
||||||
/* Allocate list of node ptrs to mmtimer_t's */
|
/* Allocate list of node ptrs to mmtimer_t's */
|
||||||
timers = kzalloc(sizeof(struct mmtimer_node)*maxn, GFP_KERNEL);
|
timers = kzalloc(sizeof(struct mmtimer_node)*maxn, GFP_KERNEL);
|
||||||
if (timers == NULL) {
|
if (!timers) {
|
||||||
printk(KERN_ERR "%s: failed to allocate memory for device\n",
|
printk(KERN_ERR "%s: failed to allocate memory for device\n",
|
||||||
MMTIMER_NAME);
|
MMTIMER_NAME);
|
||||||
goto out3;
|
goto out3;
|
||||||
|
@ -848,7 +848,6 @@ static int __init mmtimer_init(void)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out3:
|
out3:
|
||||||
kfree(timers);
|
|
||||||
misc_deregister(&mmtimer_miscdev);
|
misc_deregister(&mmtimer_miscdev);
|
||||||
out2:
|
out2:
|
||||||
free_irq(SGI_MMTIMER_VECTOR, NULL);
|
free_irq(SGI_MMTIMER_VECTOR, NULL);
|
||||||
|
|
|
@ -93,9 +93,9 @@ int button_del_callback (void (*callback) (void))
|
||||||
button_callback_list [lp].count = 0;
|
button_callback_list [lp].count = 0;
|
||||||
callback_count--;
|
callback_count--;
|
||||||
return 0;
|
return 0;
|
||||||
};
|
}
|
||||||
lp--;
|
lp--;
|
||||||
};
|
}
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -891,6 +891,14 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty)
|
||||||
int work = 0;
|
int work = 0;
|
||||||
struct mgsl_icount *icount = &info->icount;
|
struct mgsl_icount *icount = &info->icount;
|
||||||
|
|
||||||
|
if (!tty) {
|
||||||
|
/* tty is not available anymore */
|
||||||
|
issue_command(info, CHA, CMD_RXRESET);
|
||||||
|
if (debug_level >= DEBUG_LEVEL_ISR)
|
||||||
|
printk("%s(%d):rx_ready_async(tty=NULL)\n",__FILE__,__LINE__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (tcd) {
|
if (tcd) {
|
||||||
/* early termination, get FIFO count from RBCL register */
|
/* early termination, get FIFO count from RBCL register */
|
||||||
fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f);
|
fifo_count = (unsigned char)(read_reg(info, CHA+RBCL) & 0x1f);
|
||||||
|
@ -980,7 +988,7 @@ static void tx_done(MGSLPC_INFO *info, struct tty_struct *tty)
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (tty->stopped || tty->hw_stopped) {
|
if (tty && (tty->stopped || tty->hw_stopped)) {
|
||||||
tx_stop(info);
|
tx_stop(info);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1000,7 +1008,7 @@ static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty)
|
||||||
if (!info->tx_active)
|
if (!info->tx_active)
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
if (tty->stopped || tty->hw_stopped) {
|
if (tty && (tty->stopped || tty->hw_stopped)) {
|
||||||
tx_stop(info);
|
tx_stop(info);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1050,13 +1058,12 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty)
|
||||||
wake_up_interruptible(&info->status_event_wait_q);
|
wake_up_interruptible(&info->status_event_wait_q);
|
||||||
wake_up_interruptible(&info->event_wait_q);
|
wake_up_interruptible(&info->event_wait_q);
|
||||||
|
|
||||||
if (info->port.flags & ASYNC_CTS_FLOW) {
|
if (tty && (info->port.flags & ASYNC_CTS_FLOW)) {
|
||||||
if (tty->hw_stopped) {
|
if (tty->hw_stopped) {
|
||||||
if (info->serial_signals & SerialSignal_CTS) {
|
if (info->serial_signals & SerialSignal_CTS) {
|
||||||
if (debug_level >= DEBUG_LEVEL_ISR)
|
if (debug_level >= DEBUG_LEVEL_ISR)
|
||||||
printk("CTS tx start...");
|
printk("CTS tx start...");
|
||||||
if (tty)
|
tty->hw_stopped = 0;
|
||||||
tty->hw_stopped = 0;
|
|
||||||
tx_start(info, tty);
|
tx_start(info, tty);
|
||||||
info->pending_bh |= BH_TRANSMIT;
|
info->pending_bh |= BH_TRANSMIT;
|
||||||
return;
|
return;
|
||||||
|
@ -1065,8 +1072,7 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty)
|
||||||
if (!(info->serial_signals & SerialSignal_CTS)) {
|
if (!(info->serial_signals & SerialSignal_CTS)) {
|
||||||
if (debug_level >= DEBUG_LEVEL_ISR)
|
if (debug_level >= DEBUG_LEVEL_ISR)
|
||||||
printk("CTS tx stop...");
|
printk("CTS tx stop...");
|
||||||
if (tty)
|
tty->hw_stopped = 1;
|
||||||
tty->hw_stopped = 1;
|
|
||||||
tx_stop(info);
|
tx_stop(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -783,7 +783,8 @@ static int __init ppdev_init (void)
|
||||||
err = PTR_ERR(ppdev_class);
|
err = PTR_ERR(ppdev_class);
|
||||||
goto out_chrdev;
|
goto out_chrdev;
|
||||||
}
|
}
|
||||||
if (parport_register_driver(&pp_driver)) {
|
err = parport_register_driver(&pp_driver);
|
||||||
|
if (err < 0) {
|
||||||
printk (KERN_WARNING CHRDEV ": unable to register with parport\n");
|
printk (KERN_WARNING CHRDEV ": unable to register with parport\n");
|
||||||
goto out_class;
|
goto out_class;
|
||||||
}
|
}
|
||||||
|
|
|
@ -411,7 +411,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
|
||||||
case RTC_IRQP_READ:
|
case RTC_IRQP_READ:
|
||||||
case RTC_IRQP_SET:
|
case RTC_IRQP_SET:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -784,8 +784,10 @@ static int __init tlclk_init(void)
|
||||||
}
|
}
|
||||||
tlclk_major = ret;
|
tlclk_major = ret;
|
||||||
alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL);
|
alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL);
|
||||||
if (!alarm_events)
|
if (!alarm_events) {
|
||||||
|
ret = -ENOMEM;
|
||||||
goto out1;
|
goto out1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read telecom clock IRQ number (Set by BIOS) */
|
/* Read telecom clock IRQ number (Set by BIOS) */
|
||||||
if (!request_region(TLCLK_BASE, 8, "telco_clock")) {
|
if (!request_region(TLCLK_BASE, 8, "telco_clock")) {
|
||||||
|
|
|
@ -1941,7 +1941,17 @@ static int __init init(void)
|
||||||
INIT_LIST_HEAD(&pdrvdata.consoles);
|
INIT_LIST_HEAD(&pdrvdata.consoles);
|
||||||
INIT_LIST_HEAD(&pdrvdata.portdevs);
|
INIT_LIST_HEAD(&pdrvdata.portdevs);
|
||||||
|
|
||||||
return register_virtio_driver(&virtio_console);
|
err = register_virtio_driver(&virtio_console);
|
||||||
|
if (err < 0) {
|
||||||
|
pr_err("Error %d registering virtio driver\n", err);
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
free:
|
||||||
|
if (pdrvdata.debugfs_dir)
|
||||||
|
debugfs_remove_recursive(pdrvdata.debugfs_dir);
|
||||||
|
class_destroy(pdrvdata.class);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit fini(void)
|
static void __exit fini(void)
|
||||||
|
|
|
@ -105,7 +105,7 @@ config ATMEL_TCB_CLKSRC_BLOCK
|
||||||
|
|
||||||
config IBM_ASM
|
config IBM_ASM
|
||||||
tristate "Device driver for IBM RSA service processor"
|
tristate "Device driver for IBM RSA service processor"
|
||||||
depends on X86 && PCI && INPUT && EXPERIMENTAL
|
depends on X86 && PCI && INPUT
|
||||||
---help---
|
---help---
|
||||||
This option enables device driver support for in-band access to the
|
This option enables device driver support for in-band access to the
|
||||||
IBM RSA (Condor) service processor in eServer xSeries systems.
|
IBM RSA (Condor) service processor in eServer xSeries systems.
|
||||||
|
@ -162,8 +162,8 @@ config SGI_IOC4
|
||||||
Otherwise say N.
|
Otherwise say N.
|
||||||
|
|
||||||
config TIFM_CORE
|
config TIFM_CORE
|
||||||
tristate "TI Flash Media interface support (EXPERIMENTAL)"
|
tristate "TI Flash Media interface support"
|
||||||
depends on EXPERIMENTAL && PCI
|
depends on PCI
|
||||||
help
|
help
|
||||||
If you want support for Texas Instruments(R) Flash Media adapters
|
If you want support for Texas Instruments(R) Flash Media adapters
|
||||||
you should select this option and then also choose an appropriate
|
you should select this option and then also choose an appropriate
|
||||||
|
@ -178,8 +178,8 @@ config TIFM_CORE
|
||||||
be called tifm_core.
|
be called tifm_core.
|
||||||
|
|
||||||
config TIFM_7XX1
|
config TIFM_7XX1
|
||||||
tristate "TI Flash Media PCI74xx/PCI76xx host adapter support (EXPERIMENTAL)"
|
tristate "TI Flash Media PCI74xx/PCI76xx host adapter support"
|
||||||
depends on PCI && TIFM_CORE && EXPERIMENTAL
|
depends on PCI && TIFM_CORE
|
||||||
default TIFM_CORE
|
default TIFM_CORE
|
||||||
help
|
help
|
||||||
This option enables support for Texas Instruments(R) PCI74xx and
|
This option enables support for Texas Instruments(R) PCI74xx and
|
||||||
|
@ -192,7 +192,7 @@ config TIFM_7XX1
|
||||||
|
|
||||||
config ICS932S401
|
config ICS932S401
|
||||||
tristate "Integrated Circuits ICS932S401"
|
tristate "Integrated Circuits ICS932S401"
|
||||||
depends on I2C && EXPERIMENTAL
|
depends on I2C
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the Integrated Circuits
|
If you say yes here you get support for the Integrated Circuits
|
||||||
ICS932S401 clock control chips.
|
ICS932S401 clock control chips.
|
||||||
|
@ -398,7 +398,7 @@ config EP93XX_PWM
|
||||||
|
|
||||||
config DS1682
|
config DS1682
|
||||||
tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
|
tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
|
||||||
depends on I2C && EXPERIMENTAL
|
depends on I2C
|
||||||
help
|
help
|
||||||
If you say yes here you get support for Dallas Semiconductor
|
If you say yes here you get support for Dallas Semiconductor
|
||||||
DS1682 Total Elapsed Time Recorder.
|
DS1682 Total Elapsed Time Recorder.
|
||||||
|
|
|
@ -57,12 +57,6 @@ static int bmp085_i2c_remove(struct i2c_client *client)
|
||||||
return bmp085_remove(&client->dev);
|
return bmp085_remove(&client->dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id bmp085_of_match[] = {
|
|
||||||
{ .compatible = "bosch,bmp085", },
|
|
||||||
{ },
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(of, bmp085_of_match);
|
|
||||||
|
|
||||||
static const struct i2c_device_id bmp085_id[] = {
|
static const struct i2c_device_id bmp085_id[] = {
|
||||||
{ BMP085_NAME, 0 },
|
{ BMP085_NAME, 0 },
|
||||||
{ "bmp180", 0 },
|
{ "bmp180", 0 },
|
||||||
|
@ -74,7 +68,6 @@ static struct i2c_driver bmp085_i2c_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = BMP085_NAME,
|
.name = BMP085_NAME,
|
||||||
.of_match_table = bmp085_of_match
|
|
||||||
},
|
},
|
||||||
.id_table = bmp085_id,
|
.id_table = bmp085_id,
|
||||||
.probe = bmp085_i2c_probe,
|
.probe = bmp085_i2c_probe,
|
||||||
|
|
|
@ -73,19 +73,8 @@ static struct spi_driver bmp085_spi_driver = {
|
||||||
.remove = __devexit_p(bmp085_spi_remove)
|
.remove = __devexit_p(bmp085_spi_remove)
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init bmp085_spi_init(void)
|
module_spi_driver(bmp085_spi_driver);
|
||||||
{
|
|
||||||
return spi_register_driver(&bmp085_spi_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit bmp085_spi_exit(void)
|
|
||||||
{
|
|
||||||
spi_unregister_driver(&bmp085_spi_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
|
MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
|
||||||
MODULE_DESCRIPTION("BMP085 SPI bus driver");
|
MODULE_DESCRIPTION("BMP085 SPI bus driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
module_init(bmp085_spi_init);
|
|
||||||
module_exit(bmp085_spi_exit);
|
|
||||||
|
|
|
@ -3,8 +3,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
menuconfig C2PORT
|
menuconfig C2PORT
|
||||||
tristate "Silicon Labs C2 port support (EXPERIMENTAL)"
|
tristate "Silicon Labs C2 port support"
|
||||||
depends on EXPERIMENTAL
|
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
This option enables support for Silicon Labs C2 port used to
|
This option enables support for Silicon Labs C2 port used to
|
||||||
|
@ -22,7 +21,7 @@ menuconfig C2PORT
|
||||||
if C2PORT
|
if C2PORT
|
||||||
|
|
||||||
config C2PORT_DURAMAR_2150
|
config C2PORT_DURAMAR_2150
|
||||||
tristate "C2 port support for Eurotech's Duramar 2150 (EXPERIMENTAL)"
|
tristate "C2 port support for Eurotech's Duramar 2150"
|
||||||
depends on X86
|
depends on X86
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
|
|
|
@ -978,7 +978,6 @@ static int fpga_of_probe(struct platform_device *op)
|
||||||
dev_set_drvdata(priv->dev, priv);
|
dev_set_drvdata(priv->dev, priv);
|
||||||
dma_cap_zero(mask);
|
dma_cap_zero(mask);
|
||||||
dma_cap_set(DMA_MEMCPY, mask);
|
dma_cap_set(DMA_MEMCPY, mask);
|
||||||
dma_cap_set(DMA_INTERRUPT, mask);
|
|
||||||
dma_cap_set(DMA_SLAVE, mask);
|
dma_cap_set(DMA_SLAVE, mask);
|
||||||
dma_cap_set(DMA_SG, mask);
|
dma_cap_set(DMA_SG, mask);
|
||||||
|
|
||||||
|
|
|
@ -666,7 +666,7 @@ static int data_submit_dma(struct fpga_device *priv, struct data_buf *buf)
|
||||||
src = SYS_FPGA_BLOCK;
|
src = SYS_FPGA_BLOCK;
|
||||||
tx = chan->device->device_prep_dma_memcpy(chan, dst, src,
|
tx = chan->device->device_prep_dma_memcpy(chan, dst, src,
|
||||||
REG_BLOCK_SIZE,
|
REG_BLOCK_SIZE,
|
||||||
DMA_PREP_INTERRUPT);
|
0);
|
||||||
if (!tx) {
|
if (!tx) {
|
||||||
dev_err(priv->dev, "unable to prep SYS-FPGA DMA\n");
|
dev_err(priv->dev, "unable to prep SYS-FPGA DMA\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
|
@ -50,7 +50,7 @@ config EEPROM_LEGACY
|
||||||
|
|
||||||
config EEPROM_MAX6875
|
config EEPROM_MAX6875
|
||||||
tristate "Maxim MAX6874/5 power supply supervisor"
|
tristate "Maxim MAX6874/5 power supply supervisor"
|
||||||
depends on I2C && EXPERIMENTAL
|
depends on I2C
|
||||||
help
|
help
|
||||||
If you say yes here you get read-only support for the user EEPROM of
|
If you say yes here you get read-only support for the user EEPROM of
|
||||||
the Maxim MAX6874/5 EEPROM-programmable, quad power-supply
|
the Maxim MAX6874/5 EEPROM-programmable, quad power-supply
|
||||||
|
|
|
@ -302,6 +302,61 @@ static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf,
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static int at25_np_to_chip(struct device *dev,
|
||||||
|
struct device_node *np,
|
||||||
|
struct spi_eeprom *chip)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
memset(chip, 0, sizeof(*chip));
|
||||||
|
strncpy(chip->name, np->name, sizeof(chip->name));
|
||||||
|
|
||||||
|
if (of_property_read_u32(np, "size", &val) == 0 ||
|
||||||
|
of_property_read_u32(np, "at25,byte-len", &val) == 0) {
|
||||||
|
chip->byte_len = val;
|
||||||
|
} else {
|
||||||
|
dev_err(dev, "Error: missing \"size\" property\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (of_property_read_u32(np, "pagesize", &val) == 0 ||
|
||||||
|
of_property_read_u32(np, "at25,page-size", &val) == 0) {
|
||||||
|
chip->page_size = (u16)val;
|
||||||
|
} else {
|
||||||
|
dev_err(dev, "Error: missing \"pagesize\" property\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (of_property_read_u32(np, "at25,addr-mode", &val) == 0) {
|
||||||
|
chip->flags = (u16)val;
|
||||||
|
} else {
|
||||||
|
if (of_property_read_u32(np, "address-width", &val)) {
|
||||||
|
dev_err(dev,
|
||||||
|
"Error: missing \"address-width\" property\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
switch (val) {
|
||||||
|
case 8:
|
||||||
|
chip->flags |= EE_ADDR1;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
chip->flags |= EE_ADDR2;
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
chip->flags |= EE_ADDR3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(dev,
|
||||||
|
"Error: bad \"address-width\" property: %u\n",
|
||||||
|
val);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
if (of_find_property(np, "read-only", NULL))
|
||||||
|
chip->flags |= EE_READONLY;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int at25_probe(struct spi_device *spi)
|
static int at25_probe(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct at25_data *at25 = NULL;
|
struct at25_data *at25 = NULL;
|
||||||
|
@ -314,33 +369,11 @@ static int at25_probe(struct spi_device *spi)
|
||||||
/* Chip description */
|
/* Chip description */
|
||||||
if (!spi->dev.platform_data) {
|
if (!spi->dev.platform_data) {
|
||||||
if (np) {
|
if (np) {
|
||||||
u32 val;
|
err = at25_np_to_chip(&spi->dev, np, &chip);
|
||||||
|
if (err)
|
||||||
memset(&chip, 0, sizeof(chip));
|
|
||||||
strncpy(chip.name, np->name, 10);
|
|
||||||
|
|
||||||
err = of_property_read_u32(np, "at25,byte-len", &val);
|
|
||||||
if (err) {
|
|
||||||
dev_dbg(&spi->dev, "invalid chip dt description\n");
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
|
||||||
chip.byte_len = val;
|
|
||||||
|
|
||||||
err = of_property_read_u32(np, "at25,addr-mode", &val);
|
|
||||||
if (err) {
|
|
||||||
dev_dbg(&spi->dev, "invalid chip dt description\n");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
chip.flags = (u16)val;
|
|
||||||
|
|
||||||
err = of_property_read_u32(np, "at25,page-size", &val);
|
|
||||||
if (err) {
|
|
||||||
dev_dbg(&spi->dev, "invalid chip dt description\n");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
chip.page_size = (u16)val;
|
|
||||||
} else {
|
} else {
|
||||||
dev_dbg(&spi->dev, "no chip description\n");
|
dev_err(&spi->dev, "Error: no chip description\n");
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
|
@ -736,7 +736,14 @@ static void ilo_remove(struct pci_dev *pdev)
|
||||||
free_irq(pdev->irq, ilo_hw);
|
free_irq(pdev->irq, ilo_hw);
|
||||||
ilo_unmap_device(pdev, ilo_hw);
|
ilo_unmap_device(pdev, ilo_hw);
|
||||||
pci_release_regions(pdev);
|
pci_release_regions(pdev);
|
||||||
pci_disable_device(pdev);
|
/*
|
||||||
|
* pci_disable_device(pdev) used to be here. But this PCI device has
|
||||||
|
* two functions with interrupt lines connected to a single pin. The
|
||||||
|
* other one is a USB host controller. So when we disable the PIN here
|
||||||
|
* e.g. by rmmod hpilo, the controller stops working. It is because
|
||||||
|
* the interrupt link is disabled in ACPI since it is not refcounted
|
||||||
|
* yet. See acpi_pci_link_free_irq called from acpi_pci_irq_disable.
|
||||||
|
*/
|
||||||
kfree(ilo_hw);
|
kfree(ilo_hw);
|
||||||
ilo_hwdev[(minor / max_ccb)] = 0;
|
ilo_hwdev[(minor / max_ccb)] = 0;
|
||||||
}
|
}
|
||||||
|
@ -826,7 +833,7 @@ unmap:
|
||||||
free_regions:
|
free_regions:
|
||||||
pci_release_regions(pdev);
|
pci_release_regions(pdev);
|
||||||
disable:
|
disable:
|
||||||
pci_disable_device(pdev);
|
/* pci_disable_device(pdev); see comment in ilo_remove */
|
||||||
free:
|
free:
|
||||||
kfree(ilo_hw);
|
kfree(ilo_hw);
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include <linux/miscdevice.h>
|
#include <linux/miscdevice.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include "lis3lv02d.h"
|
#include "lis3lv02d.h"
|
||||||
|
|
||||||
#define DRIVER_NAME "lis3lv02d"
|
#define DRIVER_NAME "lis3lv02d"
|
||||||
|
@ -80,6 +81,15 @@
|
||||||
#define LIS3_SENSITIVITY_12B ((LIS3_ACCURACY * 1000) / 1024)
|
#define LIS3_SENSITIVITY_12B ((LIS3_ACCURACY * 1000) / 1024)
|
||||||
#define LIS3_SENSITIVITY_8B (18 * LIS3_ACCURACY)
|
#define LIS3_SENSITIVITY_8B (18 * LIS3_ACCURACY)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LIS331DLH spec says 1LSBs corresponds 4G/4096 -> 1LSB is 1000/1024 mG.
|
||||||
|
* Below macros defines sensitivity values for +/-2G. Dataout bits for
|
||||||
|
* +/-2G range is 12 bits so 4 bits adjustment must be done to get 12bit
|
||||||
|
* data from 16bit value. Currently this driver supports only 2G range.
|
||||||
|
*/
|
||||||
|
#define LIS3DLH_SENSITIVITY_2G ((LIS3_ACCURACY * 1000) / 1024)
|
||||||
|
#define SHIFT_ADJ_2G 4
|
||||||
|
|
||||||
#define LIS3_DEFAULT_FUZZ_12B 3
|
#define LIS3_DEFAULT_FUZZ_12B 3
|
||||||
#define LIS3_DEFAULT_FLAT_12B 3
|
#define LIS3_DEFAULT_FLAT_12B 3
|
||||||
#define LIS3_DEFAULT_FUZZ_8B 1
|
#define LIS3_DEFAULT_FUZZ_8B 1
|
||||||
|
@ -135,6 +145,19 @@ static s16 lis3lv02d_read_12(struct lis3lv02d *lis3, int reg)
|
||||||
return (s16)((hi << 8) | lo);
|
return (s16)((hi << 8) | lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 12bits for 2G range, 13 bits for 4G range and 14 bits for 8G range */
|
||||||
|
static s16 lis331dlh_read_data(struct lis3lv02d *lis3, int reg)
|
||||||
|
{
|
||||||
|
u8 lo, hi;
|
||||||
|
int v;
|
||||||
|
|
||||||
|
lis3->read(lis3, reg - 1, &lo);
|
||||||
|
lis3->read(lis3, reg, &hi);
|
||||||
|
v = (int) ((hi << 8) | lo);
|
||||||
|
|
||||||
|
return (s16) v >> lis3->shift_adj;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lis3lv02d_get_axis - For the given axis, give the value converted
|
* lis3lv02d_get_axis - For the given axis, give the value converted
|
||||||
* @axis: 1,2,3 - can also be negative
|
* @axis: 1,2,3 - can also be negative
|
||||||
|
@ -195,6 +218,7 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
|
||||||
static int lis3_12_rates[4] = {40, 160, 640, 2560};
|
static int lis3_12_rates[4] = {40, 160, 640, 2560};
|
||||||
static int lis3_8_rates[2] = {100, 400};
|
static int lis3_8_rates[2] = {100, 400};
|
||||||
static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
|
static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000};
|
||||||
|
static int lis3_3dlh_rates[4] = {50, 100, 400, 1000};
|
||||||
|
|
||||||
/* ODR is Output Data Rate */
|
/* ODR is Output Data Rate */
|
||||||
static int lis3lv02d_get_odr(struct lis3lv02d *lis3)
|
static int lis3lv02d_get_odr(struct lis3lv02d *lis3)
|
||||||
|
@ -267,7 +291,7 @@ static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3])
|
||||||
(LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
|
(LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lis3->whoami == WAI_3DC) {
|
if ((lis3->whoami == WAI_3DC) || (lis3->whoami == WAI_3DLH)) {
|
||||||
ctlreg = CTRL_REG4;
|
ctlreg = CTRL_REG4;
|
||||||
selftest = CTRL4_ST0;
|
selftest = CTRL4_ST0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -398,9 +422,17 @@ int lis3lv02d_poweron(struct lis3lv02d *lis3)
|
||||||
lis3->read(lis3, CTRL_REG2, ®);
|
lis3->read(lis3, CTRL_REG2, ®);
|
||||||
if (lis3->whoami == WAI_12B)
|
if (lis3->whoami == WAI_12B)
|
||||||
reg |= CTRL2_BDU | CTRL2_BOOT;
|
reg |= CTRL2_BDU | CTRL2_BOOT;
|
||||||
|
else if (lis3->whoami == WAI_3DLH)
|
||||||
|
reg |= CTRL2_BOOT_3DLH;
|
||||||
else
|
else
|
||||||
reg |= CTRL2_BOOT_8B;
|
reg |= CTRL2_BOOT_8B;
|
||||||
lis3->write(lis3, CTRL_REG2, reg);
|
lis3->write(lis3, CTRL_REG2, reg);
|
||||||
|
|
||||||
|
if (lis3->whoami == WAI_3DLH) {
|
||||||
|
lis3->read(lis3, CTRL_REG4, ®);
|
||||||
|
reg |= CTRL4_BDU;
|
||||||
|
lis3->write(lis3, CTRL_REG4, reg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = lis3lv02d_get_pwron_wait(lis3);
|
err = lis3lv02d_get_pwron_wait(lis3);
|
||||||
|
@ -912,6 +944,154 @@ static void lis3lv02d_8b_configure(struct lis3lv02d *lis3,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
int lis3lv02d_init_dt(struct lis3lv02d *lis3)
|
||||||
|
{
|
||||||
|
struct lis3lv02d_platform_data *pdata;
|
||||||
|
struct device_node *np = lis3->of_node;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
if (!lis3->of_node)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
|
||||||
|
if (!pdata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (of_get_property(np, "st,click-single-x", NULL))
|
||||||
|
pdata->click_flags |= LIS3_CLICK_SINGLE_X;
|
||||||
|
if (of_get_property(np, "st,click-double-x", NULL))
|
||||||
|
pdata->click_flags |= LIS3_CLICK_DOUBLE_X;
|
||||||
|
|
||||||
|
if (of_get_property(np, "st,click-single-y", NULL))
|
||||||
|
pdata->click_flags |= LIS3_CLICK_SINGLE_Y;
|
||||||
|
if (of_get_property(np, "st,click-double-y", NULL))
|
||||||
|
pdata->click_flags |= LIS3_CLICK_DOUBLE_Y;
|
||||||
|
|
||||||
|
if (of_get_property(np, "st,click-single-z", NULL))
|
||||||
|
pdata->click_flags |= LIS3_CLICK_SINGLE_Z;
|
||||||
|
if (of_get_property(np, "st,click-double-z", NULL))
|
||||||
|
pdata->click_flags |= LIS3_CLICK_DOUBLE_Z;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "st,click-threshold-x", &val))
|
||||||
|
pdata->click_thresh_x = val;
|
||||||
|
if (!of_property_read_u32(np, "st,click-threshold-y", &val))
|
||||||
|
pdata->click_thresh_y = val;
|
||||||
|
if (!of_property_read_u32(np, "st,click-threshold-z", &val))
|
||||||
|
pdata->click_thresh_z = val;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "st,click-time-limit", &val))
|
||||||
|
pdata->click_time_limit = val;
|
||||||
|
if (!of_property_read_u32(np, "st,click-latency", &val))
|
||||||
|
pdata->click_latency = val;
|
||||||
|
if (!of_property_read_u32(np, "st,click-window", &val))
|
||||||
|
pdata->click_window = val;
|
||||||
|
|
||||||
|
if (of_get_property(np, "st,irq1-disable", NULL))
|
||||||
|
pdata->irq_cfg |= LIS3_IRQ1_DISABLE;
|
||||||
|
if (of_get_property(np, "st,irq1-ff-wu-1", NULL))
|
||||||
|
pdata->irq_cfg |= LIS3_IRQ1_FF_WU_1;
|
||||||
|
if (of_get_property(np, "st,irq1-ff-wu-2", NULL))
|
||||||
|
pdata->irq_cfg |= LIS3_IRQ1_FF_WU_2;
|
||||||
|
if (of_get_property(np, "st,irq1-data-ready", NULL))
|
||||||
|
pdata->irq_cfg |= LIS3_IRQ1_DATA_READY;
|
||||||
|
if (of_get_property(np, "st,irq1-click", NULL))
|
||||||
|
pdata->irq_cfg |= LIS3_IRQ1_CLICK;
|
||||||
|
|
||||||
|
if (of_get_property(np, "st,irq2-disable", NULL))
|
||||||
|
pdata->irq_cfg |= LIS3_IRQ2_DISABLE;
|
||||||
|
if (of_get_property(np, "st,irq2-ff-wu-1", NULL))
|
||||||
|
pdata->irq_cfg |= LIS3_IRQ2_FF_WU_1;
|
||||||
|
if (of_get_property(np, "st,irq2-ff-wu-2", NULL))
|
||||||
|
pdata->irq_cfg |= LIS3_IRQ2_FF_WU_2;
|
||||||
|
if (of_get_property(np, "st,irq2-data-ready", NULL))
|
||||||
|
pdata->irq_cfg |= LIS3_IRQ2_DATA_READY;
|
||||||
|
if (of_get_property(np, "st,irq2-click", NULL))
|
||||||
|
pdata->irq_cfg |= LIS3_IRQ2_CLICK;
|
||||||
|
|
||||||
|
if (of_get_property(np, "st,irq-open-drain", NULL))
|
||||||
|
pdata->irq_cfg |= LIS3_IRQ_OPEN_DRAIN;
|
||||||
|
if (of_get_property(np, "st,irq-active-low", NULL))
|
||||||
|
pdata->irq_cfg |= LIS3_IRQ_ACTIVE_LOW;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "st,wu-duration-1", &val))
|
||||||
|
pdata->duration1 = val;
|
||||||
|
if (!of_property_read_u32(np, "st,wu-duration-2", &val))
|
||||||
|
pdata->duration2 = val;
|
||||||
|
|
||||||
|
if (of_get_property(np, "st,wakeup-x-lo", NULL))
|
||||||
|
pdata->wakeup_flags |= LIS3_WAKEUP_X_LO;
|
||||||
|
if (of_get_property(np, "st,wakeup-x-hi", NULL))
|
||||||
|
pdata->wakeup_flags |= LIS3_WAKEUP_X_HI;
|
||||||
|
if (of_get_property(np, "st,wakeup-y-lo", NULL))
|
||||||
|
pdata->wakeup_flags |= LIS3_WAKEUP_Y_LO;
|
||||||
|
if (of_get_property(np, "st,wakeup-y-hi", NULL))
|
||||||
|
pdata->wakeup_flags |= LIS3_WAKEUP_Y_HI;
|
||||||
|
if (of_get_property(np, "st,wakeup-z-lo", NULL))
|
||||||
|
pdata->wakeup_flags |= LIS3_WAKEUP_Z_LO;
|
||||||
|
if (of_get_property(np, "st,wakeup-z-hi", NULL))
|
||||||
|
pdata->wakeup_flags |= LIS3_WAKEUP_Z_HI;
|
||||||
|
|
||||||
|
if (!of_property_read_u32(np, "st,highpass-cutoff-hz", &val)) {
|
||||||
|
switch (val) {
|
||||||
|
case 1:
|
||||||
|
pdata->hipass_ctrl = LIS3_HIPASS_CUTFF_1HZ;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
pdata->hipass_ctrl = LIS3_HIPASS_CUTFF_2HZ;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
pdata->hipass_ctrl = LIS3_HIPASS_CUTFF_4HZ;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
pdata->hipass_ctrl = LIS3_HIPASS_CUTFF_8HZ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (of_get_property(np, "st,hipass1-disable", NULL))
|
||||||
|
pdata->hipass_ctrl |= LIS3_HIPASS1_DISABLE;
|
||||||
|
if (of_get_property(np, "st,hipass2-disable", NULL))
|
||||||
|
pdata->hipass_ctrl |= LIS3_HIPASS2_DISABLE;
|
||||||
|
|
||||||
|
if (of_get_property(np, "st,axis-x", &val))
|
||||||
|
pdata->axis_x = val;
|
||||||
|
if (of_get_property(np, "st,axis-y", &val))
|
||||||
|
pdata->axis_y = val;
|
||||||
|
if (of_get_property(np, "st,axis-z", &val))
|
||||||
|
pdata->axis_z = val;
|
||||||
|
|
||||||
|
if (of_get_property(np, "st,default-rate", NULL))
|
||||||
|
pdata->default_rate = val;
|
||||||
|
|
||||||
|
if (of_get_property(np, "st,min-limit-x", &val))
|
||||||
|
pdata->st_min_limits[0] = val;
|
||||||
|
if (of_get_property(np, "st,min-limit-y", &val))
|
||||||
|
pdata->st_min_limits[1] = val;
|
||||||
|
if (of_get_property(np, "st,min-limit-z", &val))
|
||||||
|
pdata->st_min_limits[2] = val;
|
||||||
|
|
||||||
|
if (of_get_property(np, "st,max-limit-x", &val))
|
||||||
|
pdata->st_max_limits[0] = val;
|
||||||
|
if (of_get_property(np, "st,max-limit-y", &val))
|
||||||
|
pdata->st_max_limits[1] = val;
|
||||||
|
if (of_get_property(np, "st,max-limit-z", &val))
|
||||||
|
pdata->st_max_limits[2] = val;
|
||||||
|
|
||||||
|
|
||||||
|
lis3->pdata = pdata;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
int lis3lv02d_init_dt(struct lis3lv02d *lis3)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
EXPORT_SYMBOL_GPL(lis3lv02d_init_dt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialise the accelerometer and the various subsystems.
|
* Initialise the accelerometer and the various subsystems.
|
||||||
* Should be rather independent of the bus system.
|
* Should be rather independent of the bus system.
|
||||||
|
@ -956,6 +1136,16 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3)
|
||||||
lis3->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
|
lis3->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3;
|
||||||
lis3->scale = LIS3_SENSITIVITY_8B;
|
lis3->scale = LIS3_SENSITIVITY_8B;
|
||||||
break;
|
break;
|
||||||
|
case WAI_3DLH:
|
||||||
|
pr_info("16 bits lis331dlh sensor found\n");
|
||||||
|
lis3->read_data = lis331dlh_read_data;
|
||||||
|
lis3->mdps_max_val = 2048; /* 12 bits for 2G */
|
||||||
|
lis3->shift_adj = SHIFT_ADJ_2G;
|
||||||
|
lis3->pwron_delay = LIS3_PWRON_DELAY_WAI_8B;
|
||||||
|
lis3->odrs = lis3_3dlh_rates;
|
||||||
|
lis3->odr_mask = CTRL1_DR0 | CTRL1_DR1;
|
||||||
|
lis3->scale = LIS3DLH_SENSITIVITY_2G;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
pr_err("unknown sensor type 0x%X\n", lis3->whoami);
|
pr_err("unknown sensor type 0x%X\n", lis3->whoami);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
|
@ -26,12 +26,12 @@
|
||||||
/*
|
/*
|
||||||
* This driver tries to support the "digital" accelerometer chips from
|
* This driver tries to support the "digital" accelerometer chips from
|
||||||
* STMicroelectronics such as LIS3LV02DL, LIS302DL, LIS3L02DQ, LIS331DL,
|
* STMicroelectronics such as LIS3LV02DL, LIS302DL, LIS3L02DQ, LIS331DL,
|
||||||
* LIS35DE, or LIS202DL. They are very similar in terms of programming, with
|
* LIS331DLH, LIS35DE, or LIS202DL. They are very similar in terms of
|
||||||
* almost the same registers. In addition to differing on physical properties,
|
* programming, with almost the same registers. In addition to differing
|
||||||
* they differ on the number of axes (2/3), precision (8/12 bits), and special
|
* on physical properties, they differ on the number of axes (2/3),
|
||||||
* features (freefall detection, click...). Unfortunately, not all the
|
* precision (8/12 bits), and special features (freefall detection,
|
||||||
* differences can be probed via a register.
|
* click...). Unfortunately, not all the differences can be probed via
|
||||||
* They can be connected either via I²C or SPI.
|
* a register. They can be connected either via I²C or SPI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/lis3lv02d.h>
|
#include <linux/lis3lv02d.h>
|
||||||
|
@ -96,12 +96,22 @@ enum lis3lv02d_reg {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum lis3_who_am_i {
|
enum lis3_who_am_i {
|
||||||
|
WAI_3DLH = 0x32, /* 16 bits: LIS331DLH */
|
||||||
WAI_3DC = 0x33, /* 8 bits: LIS3DC, HP3DC */
|
WAI_3DC = 0x33, /* 8 bits: LIS3DC, HP3DC */
|
||||||
WAI_12B = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */
|
WAI_12B = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */
|
||||||
WAI_8B = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */
|
WAI_8B = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */
|
||||||
WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */
|
WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum lis3_type {
|
||||||
|
LIS3LV02D,
|
||||||
|
LIS3DC,
|
||||||
|
HP3DC,
|
||||||
|
LIS2302D,
|
||||||
|
LIS331DLF,
|
||||||
|
LIS331DLH,
|
||||||
|
};
|
||||||
|
|
||||||
enum lis3lv02d_ctrl1_12b {
|
enum lis3lv02d_ctrl1_12b {
|
||||||
CTRL1_Xen = 0x01,
|
CTRL1_Xen = 0x01,
|
||||||
CTRL1_Yen = 0x02,
|
CTRL1_Yen = 0x02,
|
||||||
|
@ -129,6 +139,27 @@ enum lis3lv02d_ctrl1_3dc {
|
||||||
CTRL1_ODR3 = 0x80,
|
CTRL1_ODR3 = 0x80,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum lis331dlh_ctrl1 {
|
||||||
|
CTRL1_DR0 = 0x08,
|
||||||
|
CTRL1_DR1 = 0x10,
|
||||||
|
CTRL1_PM0 = 0x20,
|
||||||
|
CTRL1_PM1 = 0x40,
|
||||||
|
CTRL1_PM2 = 0x80,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum lis331dlh_ctrl2 {
|
||||||
|
CTRL2_HPEN1 = 0x04,
|
||||||
|
CTRL2_HPEN2 = 0x08,
|
||||||
|
CTRL2_FDS_3DLH = 0x10,
|
||||||
|
CTRL2_BOOT_3DLH = 0x80,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum lis331dlh_ctrl4 {
|
||||||
|
CTRL4_STSIGN = 0x08,
|
||||||
|
CTRL4_BLE = 0x40,
|
||||||
|
CTRL4_BDU = 0x80,
|
||||||
|
};
|
||||||
|
|
||||||
enum lis3lv02d_ctrl2 {
|
enum lis3lv02d_ctrl2 {
|
||||||
CTRL2_DAS = 0x01,
|
CTRL2_DAS = 0x01,
|
||||||
CTRL2_SIM = 0x02,
|
CTRL2_SIM = 0x02,
|
||||||
|
@ -279,9 +310,14 @@ struct lis3lv02d {
|
||||||
int data_ready_count[2];
|
int data_ready_count[2];
|
||||||
atomic_t wake_thread;
|
atomic_t wake_thread;
|
||||||
unsigned char irq_cfg;
|
unsigned char irq_cfg;
|
||||||
|
unsigned int shift_adj;
|
||||||
|
|
||||||
struct lis3lv02d_platform_data *pdata; /* for passing board config */
|
struct lis3lv02d_platform_data *pdata; /* for passing board config */
|
||||||
struct mutex mutex; /* Serialize poll and selftest */
|
struct mutex mutex; /* Serialize poll and selftest */
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
struct device_node *of_node;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
int lis3lv02d_init_device(struct lis3lv02d *lis3);
|
int lis3lv02d_init_device(struct lis3lv02d *lis3);
|
||||||
|
@ -290,5 +326,6 @@ void lis3lv02d_joystick_disable(struct lis3lv02d *lis3);
|
||||||
void lis3lv02d_poweroff(struct lis3lv02d *lis3);
|
void lis3lv02d_poweroff(struct lis3lv02d *lis3);
|
||||||
int lis3lv02d_poweron(struct lis3lv02d *lis3);
|
int lis3lv02d_poweron(struct lis3lv02d *lis3);
|
||||||
int lis3lv02d_remove_fs(struct lis3lv02d *lis3);
|
int lis3lv02d_remove_fs(struct lis3lv02d *lis3);
|
||||||
|
int lis3lv02d_init_dt(struct lis3lv02d *lis3);
|
||||||
|
|
||||||
extern struct lis3lv02d lis3_dev;
|
extern struct lis3lv02d lis3_dev;
|
||||||
|
|
|
@ -31,6 +31,10 @@
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
|
||||||
#include "lis3lv02d.h"
|
#include "lis3lv02d.h"
|
||||||
|
|
||||||
#define DRV_NAME "lis3lv02d_i2c"
|
#define DRV_NAME "lis3lv02d_i2c"
|
||||||
|
@ -90,7 +94,11 @@ static int lis3_i2c_init(struct lis3lv02d *lis3)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
|
if (lis3->whoami == WAI_3DLH)
|
||||||
|
reg |= CTRL1_PM0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
|
||||||
|
else
|
||||||
|
reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen;
|
||||||
|
|
||||||
return lis3->write(lis3, CTRL_REG1, reg);
|
return lis3->write(lis3, CTRL_REG1, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,12 +106,30 @@ static int lis3_i2c_init(struct lis3lv02d *lis3)
|
||||||
static union axis_conversion lis3lv02d_axis_map =
|
static union axis_conversion lis3lv02d_axis_map =
|
||||||
{ .as_array = { LIS3_DEV_X, LIS3_DEV_Y, LIS3_DEV_Z } };
|
{ .as_array = { LIS3_DEV_X, LIS3_DEV_Y, LIS3_DEV_Z } };
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static struct of_device_id lis3lv02d_i2c_dt_ids[] = {
|
||||||
|
{ .compatible = "st,lis3lv02d" },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, lis3lv02d_i2c_dt_ids);
|
||||||
|
#endif
|
||||||
|
|
||||||
static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
|
static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
|
struct lis3lv02d_platform_data *pdata = client->dev.platform_data;
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
if (of_match_device(lis3lv02d_i2c_dt_ids, &client->dev)) {
|
||||||
|
lis3_dev.of_node = client->dev.of_node;
|
||||||
|
ret = lis3lv02d_init_dt(&lis3_dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
pdata = lis3_dev.pdata;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (pdata) {
|
if (pdata) {
|
||||||
if ((pdata->driver_features & LIS3_USE_BLOCK_READ) &&
|
if ((pdata->driver_features & LIS3_USE_BLOCK_READ) &&
|
||||||
(i2c_check_functionality(client->adapter,
|
(i2c_check_functionality(client->adapter,
|
||||||
|
@ -231,7 +257,8 @@ static int lis3_i2c_runtime_resume(struct device *dev)
|
||||||
#endif /* CONFIG_PM_RUNTIME */
|
#endif /* CONFIG_PM_RUNTIME */
|
||||||
|
|
||||||
static const struct i2c_device_id lis3lv02d_id[] = {
|
static const struct i2c_device_id lis3lv02d_id[] = {
|
||||||
{"lis3lv02d", 0 },
|
{"lis3lv02d", LIS3LV02D},
|
||||||
|
{"lis331dlh", LIS331DLH},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -250,6 +277,7 @@ static struct i2c_driver lis3lv02d_i2c_driver = {
|
||||||
.name = DRV_NAME,
|
.name = DRV_NAME,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.pm = &lis3_pm_ops,
|
.pm = &lis3_pm_ops,
|
||||||
|
.of_match_table = of_match_ptr(lis3lv02d_i2c_dt_ids),
|
||||||
},
|
},
|
||||||
.probe = lis3lv02d_i2c_probe,
|
.probe = lis3lv02d_i2c_probe,
|
||||||
.remove = __devexit_p(lis3lv02d_i2c_remove),
|
.remove = __devexit_p(lis3lv02d_i2c_remove),
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
|
||||||
#include "lis3lv02d.h"
|
#include "lis3lv02d.h"
|
||||||
|
|
||||||
|
@ -58,6 +61,14 @@ static int lis3_spi_init(struct lis3lv02d *lis3)
|
||||||
static union axis_conversion lis3lv02d_axis_normal =
|
static union axis_conversion lis3lv02d_axis_normal =
|
||||||
{ .as_array = { 1, 2, 3 } };
|
{ .as_array = { 1, 2, 3 } };
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static struct of_device_id lis302dl_spi_dt_ids[] = {
|
||||||
|
{ .compatible = "st,lis302dl-spi" },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids);
|
||||||
|
#endif
|
||||||
|
|
||||||
static int __devinit lis302dl_spi_probe(struct spi_device *spi)
|
static int __devinit lis302dl_spi_probe(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -75,6 +86,15 @@ static int __devinit lis302dl_spi_probe(struct spi_device *spi)
|
||||||
lis3_dev.irq = spi->irq;
|
lis3_dev.irq = spi->irq;
|
||||||
lis3_dev.ac = lis3lv02d_axis_normal;
|
lis3_dev.ac = lis3lv02d_axis_normal;
|
||||||
lis3_dev.pdata = spi->dev.platform_data;
|
lis3_dev.pdata = spi->dev.platform_data;
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
if (of_match_device(lis302dl_spi_dt_ids, &spi->dev)) {
|
||||||
|
lis3_dev.of_node = spi->dev.of_node;
|
||||||
|
ret = lis3lv02d_init_dt(&lis3_dev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
spi_set_drvdata(spi, &lis3_dev);
|
spi_set_drvdata(spi, &lis3_dev);
|
||||||
|
|
||||||
return lis3lv02d_init_device(&lis3_dev);
|
return lis3lv02d_init_device(&lis3_dev);
|
||||||
|
@ -121,6 +141,7 @@ static struct spi_driver lis302dl_spi_driver = {
|
||||||
.name = DRV_NAME,
|
.name = DRV_NAME,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.pm = &lis3lv02d_spi_pm,
|
.pm = &lis3lv02d_spi_pm,
|
||||||
|
.of_match_table = of_match_ptr(lis302dl_spi_dt_ids),
|
||||||
},
|
},
|
||||||
.probe = lis302dl_spi_probe,
|
.probe = lis302dl_spi_probe,
|
||||||
.remove = __devexit_p(lis302dl_spi_remove),
|
.remove = __devexit_p(lis302dl_spi_remove),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
config INTEL_MEI
|
config INTEL_MEI
|
||||||
tristate "Intel Management Engine Interface (Intel MEI)"
|
tristate "Intel Management Engine Interface (Intel MEI)"
|
||||||
depends on X86 && PCI && EXPERIMENTAL && WATCHDOG_CORE
|
depends on X86 && PCI && WATCHDOG_CORE
|
||||||
help
|
help
|
||||||
The Intel Management Engine (Intel ME) provides Manageability,
|
The Intel Management Engine (Intel ME) provides Manageability,
|
||||||
Security and Media services for system containing Intel chipsets.
|
Security and Media services for system containing Intel chipsets.
|
||||||
|
|
|
@ -40,47 +40,48 @@
|
||||||
/*
|
/*
|
||||||
* MEI device IDs
|
* MEI device IDs
|
||||||
*/
|
*/
|
||||||
#define MEI_DEV_ID_82946GZ 0x2974 /* 82946GZ/GL */
|
#define MEI_DEV_ID_82946GZ 0x2974 /* 82946GZ/GL */
|
||||||
#define MEI_DEV_ID_82G35 0x2984 /* 82G35 Express */
|
#define MEI_DEV_ID_82G35 0x2984 /* 82G35 Express */
|
||||||
#define MEI_DEV_ID_82Q965 0x2994 /* 82Q963/Q965 */
|
#define MEI_DEV_ID_82Q965 0x2994 /* 82Q963/Q965 */
|
||||||
#define MEI_DEV_ID_82G965 0x29A4 /* 82P965/G965 */
|
#define MEI_DEV_ID_82G965 0x29A4 /* 82P965/G965 */
|
||||||
|
|
||||||
#define MEI_DEV_ID_82GM965 0x2A04 /* Mobile PM965/GM965 */
|
#define MEI_DEV_ID_82GM965 0x2A04 /* Mobile PM965/GM965 */
|
||||||
#define MEI_DEV_ID_82GME965 0x2A14 /* Mobile GME965/GLE960 */
|
#define MEI_DEV_ID_82GME965 0x2A14 /* Mobile GME965/GLE960 */
|
||||||
|
|
||||||
#define MEI_DEV_ID_ICH9_82Q35 0x29B4 /* 82Q35 Express */
|
#define MEI_DEV_ID_ICH9_82Q35 0x29B4 /* 82Q35 Express */
|
||||||
#define MEI_DEV_ID_ICH9_82G33 0x29C4 /* 82G33/G31/P35/P31 Express */
|
#define MEI_DEV_ID_ICH9_82G33 0x29C4 /* 82G33/G31/P35/P31 Express */
|
||||||
#define MEI_DEV_ID_ICH9_82Q33 0x29D4 /* 82Q33 Express */
|
#define MEI_DEV_ID_ICH9_82Q33 0x29D4 /* 82Q33 Express */
|
||||||
#define MEI_DEV_ID_ICH9_82X38 0x29E4 /* 82X38/X48 Express */
|
#define MEI_DEV_ID_ICH9_82X38 0x29E4 /* 82X38/X48 Express */
|
||||||
#define MEI_DEV_ID_ICH9_3200 0x29F4 /* 3200/3210 Server */
|
#define MEI_DEV_ID_ICH9_3200 0x29F4 /* 3200/3210 Server */
|
||||||
|
|
||||||
#define MEI_DEV_ID_ICH9_6 0x28B4 /* Bearlake */
|
#define MEI_DEV_ID_ICH9_6 0x28B4 /* Bearlake */
|
||||||
#define MEI_DEV_ID_ICH9_7 0x28C4 /* Bearlake */
|
#define MEI_DEV_ID_ICH9_7 0x28C4 /* Bearlake */
|
||||||
#define MEI_DEV_ID_ICH9_8 0x28D4 /* Bearlake */
|
#define MEI_DEV_ID_ICH9_8 0x28D4 /* Bearlake */
|
||||||
#define MEI_DEV_ID_ICH9_9 0x28E4 /* Bearlake */
|
#define MEI_DEV_ID_ICH9_9 0x28E4 /* Bearlake */
|
||||||
#define MEI_DEV_ID_ICH9_10 0x28F4 /* Bearlake */
|
#define MEI_DEV_ID_ICH9_10 0x28F4 /* Bearlake */
|
||||||
|
|
||||||
#define MEI_DEV_ID_ICH9M_1 0x2A44 /* Cantiga */
|
#define MEI_DEV_ID_ICH9M_1 0x2A44 /* Cantiga */
|
||||||
#define MEI_DEV_ID_ICH9M_2 0x2A54 /* Cantiga */
|
#define MEI_DEV_ID_ICH9M_2 0x2A54 /* Cantiga */
|
||||||
#define MEI_DEV_ID_ICH9M_3 0x2A64 /* Cantiga */
|
#define MEI_DEV_ID_ICH9M_3 0x2A64 /* Cantiga */
|
||||||
#define MEI_DEV_ID_ICH9M_4 0x2A74 /* Cantiga */
|
#define MEI_DEV_ID_ICH9M_4 0x2A74 /* Cantiga */
|
||||||
|
|
||||||
#define MEI_DEV_ID_ICH10_1 0x2E04 /* Eaglelake */
|
#define MEI_DEV_ID_ICH10_1 0x2E04 /* Eaglelake */
|
||||||
#define MEI_DEV_ID_ICH10_2 0x2E14 /* Eaglelake */
|
#define MEI_DEV_ID_ICH10_2 0x2E14 /* Eaglelake */
|
||||||
#define MEI_DEV_ID_ICH10_3 0x2E24 /* Eaglelake */
|
#define MEI_DEV_ID_ICH10_3 0x2E24 /* Eaglelake */
|
||||||
#define MEI_DEV_ID_ICH10_4 0x2E34 /* Eaglelake */
|
#define MEI_DEV_ID_ICH10_4 0x2E34 /* Eaglelake */
|
||||||
|
|
||||||
#define MEI_DEV_ID_IBXPK_1 0x3B64 /* Calpella */
|
#define MEI_DEV_ID_IBXPK_1 0x3B64 /* Calpella */
|
||||||
#define MEI_DEV_ID_IBXPK_2 0x3B65 /* Calpella */
|
#define MEI_DEV_ID_IBXPK_2 0x3B65 /* Calpella */
|
||||||
|
|
||||||
#define MEI_DEV_ID_CPT_1 0x1C3A /* Cougerpoint */
|
#define MEI_DEV_ID_CPT_1 0x1C3A /* Couger Point */
|
||||||
#define MEI_DEV_ID_PBG_1 0x1D3A /* PBG */
|
#define MEI_DEV_ID_PBG_1 0x1D3A /* C600/X79 Patsburg */
|
||||||
|
|
||||||
#define MEI_DEV_ID_PPT_1 0x1E3A /* Pantherpoint PPT */
|
|
||||||
#define MEI_DEV_ID_PPT_2 0x1CBA /* Pantherpoint PPT */
|
|
||||||
#define MEI_DEV_ID_PPT_3 0x1DBA /* Pantherpoint PPT */
|
|
||||||
|
|
||||||
|
#define MEI_DEV_ID_PPT_1 0x1E3A /* Panther Point */
|
||||||
|
#define MEI_DEV_ID_PPT_2 0x1CBA /* Panther Point */
|
||||||
|
#define MEI_DEV_ID_PPT_3 0x1DBA /* Panther Point */
|
||||||
|
|
||||||
|
#define MEI_DEV_ID_LPT 0x8C3A /* Lynx Point */
|
||||||
|
#define MEI_DEV_ID_LPT_LP 0x9C3A /* Lynx Point LP */
|
||||||
/*
|
/*
|
||||||
* MEI HW Section
|
* MEI HW Section
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -24,6 +24,25 @@
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include <linux/mei.h>
|
#include <linux/mei.h>
|
||||||
|
|
||||||
|
const char *mei_dev_state_str(int state)
|
||||||
|
{
|
||||||
|
#define MEI_DEV_STATE(state) case MEI_DEV_##state: return #state
|
||||||
|
switch (state) {
|
||||||
|
MEI_DEV_STATE(INITIALIZING);
|
||||||
|
MEI_DEV_STATE(INIT_CLIENTS);
|
||||||
|
MEI_DEV_STATE(ENABLED);
|
||||||
|
MEI_DEV_STATE(RESETING);
|
||||||
|
MEI_DEV_STATE(DISABLED);
|
||||||
|
MEI_DEV_STATE(RECOVERING_FROM_RESET);
|
||||||
|
MEI_DEV_STATE(POWER_DOWN);
|
||||||
|
MEI_DEV_STATE(POWER_UP);
|
||||||
|
default:
|
||||||
|
return "unkown";
|
||||||
|
}
|
||||||
|
#undef MEI_DEV_STATE
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
|
const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
|
||||||
0xa8, 0x46, 0xe0, 0xff, 0x65,
|
0xa8, 0x46, 0xe0, 0xff, 0x65,
|
||||||
0x81, 0x4c);
|
0x81, 0x4c);
|
||||||
|
@ -123,7 +142,7 @@ struct mei_device *mei_device_init(struct pci_dev *pdev)
|
||||||
mutex_init(&dev->device_lock);
|
mutex_init(&dev->device_lock);
|
||||||
init_waitqueue_head(&dev->wait_recvd_msg);
|
init_waitqueue_head(&dev->wait_recvd_msg);
|
||||||
init_waitqueue_head(&dev->wait_stop_wd);
|
init_waitqueue_head(&dev->wait_stop_wd);
|
||||||
dev->mei_state = MEI_INITIALIZING;
|
dev->dev_state = MEI_DEV_INITIALIZING;
|
||||||
dev->iamthif_state = MEI_IAMTHIF_IDLE;
|
dev->iamthif_state = MEI_IAMTHIF_IDLE;
|
||||||
dev->wd_interface_reg = false;
|
dev->wd_interface_reg = false;
|
||||||
|
|
||||||
|
@ -182,7 +201,7 @@ int mei_hw_init(struct mei_device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err <= 0 && !dev->recvd_msg) {
|
if (err <= 0 && !dev->recvd_msg) {
|
||||||
dev->mei_state = MEI_DISABLED;
|
dev->dev_state = MEI_DEV_DISABLED;
|
||||||
dev_dbg(&dev->pdev->dev,
|
dev_dbg(&dev->pdev->dev,
|
||||||
"wait_event_interruptible_timeout failed"
|
"wait_event_interruptible_timeout failed"
|
||||||
"on wait for ME to turn on ME_RDY.\n");
|
"on wait for ME to turn on ME_RDY.\n");
|
||||||
|
@ -192,7 +211,7 @@ int mei_hw_init(struct mei_device *dev)
|
||||||
|
|
||||||
if (!(((dev->host_hw_state & H_RDY) == H_RDY) &&
|
if (!(((dev->host_hw_state & H_RDY) == H_RDY) &&
|
||||||
((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) {
|
((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) {
|
||||||
dev->mei_state = MEI_DISABLED;
|
dev->dev_state = MEI_DEV_DISABLED;
|
||||||
dev_dbg(&dev->pdev->dev,
|
dev_dbg(&dev->pdev->dev,
|
||||||
"host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
|
"host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
|
||||||
dev->host_hw_state, dev->me_hw_state);
|
dev->host_hw_state, dev->me_hw_state);
|
||||||
|
@ -258,15 +277,15 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
|
||||||
struct mei_cl_cb *cb_next = NULL;
|
struct mei_cl_cb *cb_next = NULL;
|
||||||
bool unexpected;
|
bool unexpected;
|
||||||
|
|
||||||
if (dev->mei_state == MEI_RECOVERING_FROM_RESET) {
|
if (dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
|
||||||
dev->need_reset = true;
|
dev->need_reset = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unexpected = (dev->mei_state != MEI_INITIALIZING &&
|
unexpected = (dev->dev_state != MEI_DEV_INITIALIZING &&
|
||||||
dev->mei_state != MEI_DISABLED &&
|
dev->dev_state != MEI_DEV_DISABLED &&
|
||||||
dev->mei_state != MEI_POWER_DOWN &&
|
dev->dev_state != MEI_DEV_POWER_DOWN &&
|
||||||
dev->mei_state != MEI_POWER_UP);
|
dev->dev_state != MEI_DEV_POWER_UP);
|
||||||
|
|
||||||
dev->host_hw_state = mei_hcsr_read(dev);
|
dev->host_hw_state = mei_hcsr_read(dev);
|
||||||
|
|
||||||
|
@ -285,10 +304,10 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
|
||||||
|
|
||||||
dev->need_reset = false;
|
dev->need_reset = false;
|
||||||
|
|
||||||
if (dev->mei_state != MEI_INITIALIZING) {
|
if (dev->dev_state != MEI_DEV_INITIALIZING) {
|
||||||
if (dev->mei_state != MEI_DISABLED &&
|
if (dev->dev_state != MEI_DEV_DISABLED &&
|
||||||
dev->mei_state != MEI_POWER_DOWN)
|
dev->dev_state != MEI_DEV_POWER_DOWN)
|
||||||
dev->mei_state = MEI_RESETING;
|
dev->dev_state = MEI_DEV_RESETING;
|
||||||
|
|
||||||
list_for_each_entry_safe(cl_pos,
|
list_for_each_entry_safe(cl_pos,
|
||||||
cl_next, &dev->file_list, link) {
|
cl_next, &dev->file_list, link) {
|
||||||
|
@ -311,7 +330,6 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
|
||||||
|
|
||||||
dev->me_clients_num = 0;
|
dev->me_clients_num = 0;
|
||||||
dev->rd_msg_hdr = 0;
|
dev->rd_msg_hdr = 0;
|
||||||
dev->stop = false;
|
|
||||||
dev->wd_pending = false;
|
dev->wd_pending = false;
|
||||||
|
|
||||||
/* update the state of the registers after reset */
|
/* update the state of the registers after reset */
|
||||||
|
@ -322,7 +340,8 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
|
||||||
dev->host_hw_state, dev->me_hw_state);
|
dev->host_hw_state, dev->me_hw_state);
|
||||||
|
|
||||||
if (unexpected)
|
if (unexpected)
|
||||||
dev_warn(&dev->pdev->dev, "unexpected reset.\n");
|
dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
|
||||||
|
mei_dev_state_str(dev->dev_state));
|
||||||
|
|
||||||
/* Wake up all readings so they can be interrupted */
|
/* Wake up all readings so they can be interrupted */
|
||||||
list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
|
list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
|
||||||
|
@ -371,7 +390,7 @@ void mei_host_start_message(struct mei_device *dev)
|
||||||
if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req,
|
if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req,
|
||||||
mei_hdr->length)) {
|
mei_hdr->length)) {
|
||||||
dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
|
dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
|
||||||
dev->mei_state = MEI_RESETING;
|
dev->dev_state = MEI_DEV_RESETING;
|
||||||
mei_reset(dev, 1);
|
mei_reset(dev, 1);
|
||||||
}
|
}
|
||||||
dev->init_clients_state = MEI_START_MESSAGE;
|
dev->init_clients_state = MEI_START_MESSAGE;
|
||||||
|
@ -403,7 +422,7 @@ void mei_host_enum_clients_message(struct mei_device *dev)
|
||||||
host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
|
host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
|
||||||
if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req,
|
if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req,
|
||||||
mei_hdr->length)) {
|
mei_hdr->length)) {
|
||||||
dev->mei_state = MEI_RESETING;
|
dev->dev_state = MEI_DEV_RESETING;
|
||||||
dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
|
dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
|
||||||
mei_reset(dev, 1);
|
mei_reset(dev, 1);
|
||||||
}
|
}
|
||||||
|
@ -444,7 +463,7 @@ void mei_allocate_me_clients_storage(struct mei_device *dev)
|
||||||
sizeof(struct mei_me_client), GFP_KERNEL);
|
sizeof(struct mei_me_client), GFP_KERNEL);
|
||||||
if (!clients) {
|
if (!clients) {
|
||||||
dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
|
dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
|
||||||
dev->mei_state = MEI_RESETING;
|
dev->dev_state = MEI_DEV_RESETING;
|
||||||
mei_reset(dev, 1);
|
mei_reset(dev, 1);
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
@ -490,7 +509,7 @@ int mei_host_client_properties(struct mei_device *dev)
|
||||||
if (mei_write_message(dev, mei_header,
|
if (mei_write_message(dev, mei_header,
|
||||||
(unsigned char *)host_cli_req,
|
(unsigned char *)host_cli_req,
|
||||||
mei_header->length)) {
|
mei_header->length)) {
|
||||||
dev->mei_state = MEI_RESETING;
|
dev->dev_state = MEI_DEV_RESETING;
|
||||||
dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
|
dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
|
||||||
mei_reset(dev, 1);
|
mei_reset(dev, 1);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -522,12 +541,12 @@ void mei_cl_init(struct mei_cl *priv, struct mei_device *dev)
|
||||||
priv->dev = dev;
|
priv->dev = dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid)
|
int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid)
|
||||||
{
|
{
|
||||||
int i, res = -1;
|
int i, res = -ENOENT;
|
||||||
|
|
||||||
for (i = 0; i < dev->me_clients_num; ++i)
|
for (i = 0; i < dev->me_clients_num; ++i)
|
||||||
if (uuid_le_cmp(cuuid,
|
if (uuid_le_cmp(*cuuid,
|
||||||
dev->me_clients[i].props.protocol_name) == 0) {
|
dev->me_clients[i].props.protocol_name) == 0) {
|
||||||
res = i;
|
res = i;
|
||||||
break;
|
break;
|
||||||
|
@ -538,35 +557,35 @@ int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mei_find_me_client_update_filext - searches for ME client guid
|
* mei_me_cl_update_filext - searches for ME client guid
|
||||||
* sets client_id in mei_file_private if found
|
* sets client_id in mei_file_private if found
|
||||||
* @dev: the device structure
|
* @dev: the device structure
|
||||||
* @priv: private file structure to set client_id in
|
* @cl: private file structure to set client_id in
|
||||||
* @cguid: searched guid of ME client
|
* @cuuid: searched uuid of ME client
|
||||||
* @client_id: id of host client to be set in file private structure
|
* @client_id: id of host client to be set in file private structure
|
||||||
*
|
*
|
||||||
* returns ME client index
|
* returns ME client index
|
||||||
*/
|
*/
|
||||||
u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv,
|
int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl,
|
||||||
const uuid_le *cguid, u8 client_id)
|
const uuid_le *cuuid, u8 host_cl_id)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!dev || !priv || !cguid)
|
if (!dev || !cl || !cuuid)
|
||||||
return 0;
|
return -EINVAL;
|
||||||
|
|
||||||
/* check for valid client id */
|
/* check for valid client id */
|
||||||
i = mei_find_me_client_index(dev, *cguid);
|
i = mei_me_cl_by_uuid(dev, cuuid);
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
priv->me_client_id = dev->me_clients[i].client_id;
|
cl->me_client_id = dev->me_clients[i].client_id;
|
||||||
priv->state = MEI_FILE_CONNECTING;
|
cl->state = MEI_FILE_CONNECTING;
|
||||||
priv->host_client_id = client_id;
|
cl->host_client_id = host_cl_id;
|
||||||
|
|
||||||
list_add_tail(&priv->link, &dev->file_list);
|
list_add_tail(&cl->link, &dev->file_list);
|
||||||
return (u8)i;
|
return (u8)i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -577,16 +596,16 @@ u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv,
|
||||||
*/
|
*/
|
||||||
void mei_host_init_iamthif(struct mei_device *dev)
|
void mei_host_init_iamthif(struct mei_device *dev)
|
||||||
{
|
{
|
||||||
u8 i;
|
int i;
|
||||||
unsigned char *msg_buf;
|
unsigned char *msg_buf;
|
||||||
|
|
||||||
mei_cl_init(&dev->iamthif_cl, dev);
|
mei_cl_init(&dev->iamthif_cl, dev);
|
||||||
dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
|
dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
|
||||||
|
|
||||||
/* find ME amthi client */
|
/* find ME amthi client */
|
||||||
i = mei_find_me_client_update_filext(dev, &dev->iamthif_cl,
|
i = mei_me_cl_update_filext(dev, &dev->iamthif_cl,
|
||||||
&mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID);
|
&mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID);
|
||||||
if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) {
|
if (i < 0) {
|
||||||
dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n");
|
dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,14 +23,6 @@
|
||||||
#include "mei_dev.h"
|
#include "mei_dev.h"
|
||||||
|
|
||||||
|
|
||||||
#define AMT_WD_DEFAULT_TIMEOUT 120 /* seconds */
|
|
||||||
#define AMT_WD_MIN_TIMEOUT 120 /* seconds */
|
|
||||||
#define AMT_WD_MAX_TIMEOUT 65535 /* seconds */
|
|
||||||
|
|
||||||
#define MEI_WATCHDOG_DATA_SIZE 16
|
|
||||||
#define MEI_START_WD_DATA_SIZE 20
|
|
||||||
#define MEI_WD_PARAMS_SIZE 4
|
|
||||||
|
|
||||||
|
|
||||||
void mei_read_slots(struct mei_device *dev,
|
void mei_read_slots(struct mei_device *dev,
|
||||||
unsigned char *buffer,
|
unsigned char *buffer,
|
||||||
|
@ -64,7 +56,7 @@ int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl);
|
||||||
|
|
||||||
|
|
||||||
int mei_wd_send(struct mei_device *dev);
|
int mei_wd_send(struct mei_device *dev);
|
||||||
int mei_wd_stop(struct mei_device *dev, bool preserve);
|
int mei_wd_stop(struct mei_device *dev);
|
||||||
int mei_wd_host_init(struct mei_device *dev);
|
int mei_wd_host_init(struct mei_device *dev);
|
||||||
/*
|
/*
|
||||||
* mei_watchdog_register - Registering watchdog interface
|
* mei_watchdog_register - Registering watchdog interface
|
||||||
|
|
|
@ -221,17 +221,10 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list,
|
||||||
cl->status = 0;
|
cl->status = 0;
|
||||||
list_del(&cb_pos->cb_list);
|
list_del(&cb_pos->cb_list);
|
||||||
dev_dbg(&dev->pdev->dev,
|
dev_dbg(&dev->pdev->dev,
|
||||||
"completed read host client = %d,"
|
"completed read H cl = %d, ME cl = %d, length = %lu\n",
|
||||||
"ME client = %d, "
|
|
||||||
"data length = %lu\n",
|
|
||||||
cl->host_client_id,
|
cl->host_client_id,
|
||||||
cl->me_client_id,
|
cl->me_client_id,
|
||||||
cb_pos->information);
|
cb_pos->information);
|
||||||
|
|
||||||
*(cb_pos->response_buffer.data +
|
|
||||||
cb_pos->information) = '\0';
|
|
||||||
dev_dbg(&dev->pdev->dev, "cb_pos->res_buffer - %s\n",
|
|
||||||
cb_pos->response_buffer.data);
|
|
||||||
list_add_tail(&cb_pos->cb_list,
|
list_add_tail(&cb_pos->cb_list,
|
||||||
&complete_list->mei_cb.cb_list);
|
&complete_list->mei_cb.cb_list);
|
||||||
}
|
}
|
||||||
|
@ -633,7 +626,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
|
||||||
if (version_res->host_version_supported) {
|
if (version_res->host_version_supported) {
|
||||||
dev->version.major_version = HBM_MAJOR_VERSION;
|
dev->version.major_version = HBM_MAJOR_VERSION;
|
||||||
dev->version.minor_version = HBM_MINOR_VERSION;
|
dev->version.minor_version = HBM_MINOR_VERSION;
|
||||||
if (dev->mei_state == MEI_INIT_CLIENTS &&
|
if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
|
||||||
dev->init_clients_state == MEI_START_MESSAGE) {
|
dev->init_clients_state == MEI_START_MESSAGE) {
|
||||||
dev->init_clients_timer = 0;
|
dev->init_clients_timer = 0;
|
||||||
mei_host_enum_clients_message(dev);
|
mei_host_enum_clients_message(dev);
|
||||||
|
@ -707,7 +700,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
|
||||||
dev->me_clients[dev->me_client_presentation_num].props
|
dev->me_clients[dev->me_client_presentation_num].props
|
||||||
= props_res->client_properties;
|
= props_res->client_properties;
|
||||||
|
|
||||||
if (dev->mei_state == MEI_INIT_CLIENTS &&
|
if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
|
||||||
dev->init_clients_state ==
|
dev->init_clients_state ==
|
||||||
MEI_CLIENT_PROPERTIES_MESSAGE) {
|
MEI_CLIENT_PROPERTIES_MESSAGE) {
|
||||||
dev->me_client_index++;
|
dev->me_client_index++;
|
||||||
|
@ -734,7 +727,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
|
||||||
* Client ID 2 - Reserved for AMTHI
|
* Client ID 2 - Reserved for AMTHI
|
||||||
*/
|
*/
|
||||||
bitmap_set(dev->host_clients_map, 0, 3);
|
bitmap_set(dev->host_clients_map, 0, 3);
|
||||||
dev->mei_state = MEI_ENABLED;
|
dev->dev_state = MEI_DEV_ENABLED;
|
||||||
|
|
||||||
/* if wd initialization fails, initialization the AMTHI client,
|
/* if wd initialization fails, initialization the AMTHI client,
|
||||||
* otherwise the AMTHI client will be initialized after the WD client connect response
|
* otherwise the AMTHI client will be initialized after the WD client connect response
|
||||||
|
@ -759,7 +752,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
|
||||||
case HOST_ENUM_RES_CMD:
|
case HOST_ENUM_RES_CMD:
|
||||||
enum_res = (struct hbm_host_enum_response *) mei_msg;
|
enum_res = (struct hbm_host_enum_response *) mei_msg;
|
||||||
memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
|
memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
|
||||||
if (dev->mei_state == MEI_INIT_CLIENTS &&
|
if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
|
||||||
dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
|
dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
|
||||||
dev->init_clients_timer = 0;
|
dev->init_clients_timer = 0;
|
||||||
dev->me_client_presentation_num = 0;
|
dev->me_client_presentation_num = 0;
|
||||||
|
@ -776,7 +769,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HOST_STOP_RES_CMD:
|
case HOST_STOP_RES_CMD:
|
||||||
dev->mei_state = MEI_DISABLED;
|
dev->dev_state = MEI_DEV_DISABLED;
|
||||||
dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
|
dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
|
||||||
mei_reset(dev, 1);
|
mei_reset(dev, 1);
|
||||||
break;
|
break;
|
||||||
|
@ -1224,10 +1217,9 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->stop && !dev->wd_pending) {
|
if (dev->wd_state == MEI_WD_STOPPING) {
|
||||||
dev->wd_stopped = true;
|
dev->wd_state = MEI_WD_IDLE;
|
||||||
wake_up_interruptible(&dev->wait_stop_wd);
|
wake_up_interruptible(&dev->wait_stop_wd);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->extra_write_index) {
|
if (dev->extra_write_index) {
|
||||||
|
@ -1240,7 +1232,7 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
|
||||||
*slots -= dev->extra_write_index;
|
*slots -= dev->extra_write_index;
|
||||||
dev->extra_write_index = 0;
|
dev->extra_write_index = 0;
|
||||||
}
|
}
|
||||||
if (dev->mei_state == MEI_ENABLED) {
|
if (dev->dev_state == MEI_DEV_ENABLED) {
|
||||||
if (dev->wd_pending &&
|
if (dev->wd_pending &&
|
||||||
mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
|
mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
|
||||||
if (mei_wd_send(dev))
|
if (mei_wd_send(dev))
|
||||||
|
@ -1250,14 +1242,12 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
|
||||||
|
|
||||||
dev->wd_pending = false;
|
dev->wd_pending = false;
|
||||||
|
|
||||||
if (dev->wd_timeout)
|
if (dev->wd_state == MEI_WD_RUNNING)
|
||||||
*slots -= mei_data2slots(MEI_START_WD_DATA_SIZE);
|
*slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
|
||||||
else
|
else
|
||||||
*slots -= mei_data2slots(MEI_WD_PARAMS_SIZE);
|
*slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dev->stop)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
/* complete control write list CB */
|
/* complete control write list CB */
|
||||||
dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
|
dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
|
||||||
|
@ -1361,8 +1351,8 @@ void mei_timer(struct work_struct *work)
|
||||||
|
|
||||||
|
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
if (dev->mei_state != MEI_ENABLED) {
|
if (dev->dev_state != MEI_DEV_ENABLED) {
|
||||||
if (dev->mei_state == MEI_INIT_CLIENTS) {
|
if (dev->dev_state == MEI_DEV_INIT_CLIENTS) {
|
||||||
if (dev->init_clients_timer) {
|
if (dev->init_clients_timer) {
|
||||||
if (--dev->init_clients_timer == 0) {
|
if (--dev->init_clients_timer == 0) {
|
||||||
dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
|
dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
|
||||||
|
@ -1484,8 +1474,8 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
|
||||||
|
|
||||||
/* check if ME wants a reset */
|
/* check if ME wants a reset */
|
||||||
if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
|
if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
|
||||||
dev->mei_state != MEI_RESETING &&
|
dev->dev_state != MEI_DEV_RESETING &&
|
||||||
dev->mei_state != MEI_INITIALIZING) {
|
dev->dev_state != MEI_DEV_INITIALIZING) {
|
||||||
dev_dbg(&dev->pdev->dev, "FW not ready.\n");
|
dev_dbg(&dev->pdev->dev, "FW not ready.\n");
|
||||||
mei_reset(dev, 1);
|
mei_reset(dev, 1);
|
||||||
mutex_unlock(&dev->device_lock);
|
mutex_unlock(&dev->device_lock);
|
||||||
|
@ -1498,7 +1488,7 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
|
||||||
dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
|
dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
|
||||||
dev->host_hw_state |= (H_IE | H_IG | H_RDY);
|
dev->host_hw_state |= (H_IE | H_IG | H_RDY);
|
||||||
mei_hcsr_set(dev);
|
mei_hcsr_set(dev);
|
||||||
dev->mei_state = MEI_INIT_CLIENTS;
|
dev->dev_state = MEI_DEV_INIT_CLIENTS;
|
||||||
dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
|
dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
|
||||||
/* link is established
|
/* link is established
|
||||||
* start sending messages.
|
* start sending messages.
|
||||||
|
|
|
@ -38,7 +38,31 @@
|
||||||
#include <linux/mei.h>
|
#include <linux/mei.h>
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mei_me_cl_by_id return index to me_clients for client_id
|
||||||
|
*
|
||||||
|
* @dev: the device structure
|
||||||
|
* @client_id: me client id
|
||||||
|
*
|
||||||
|
* Locking: called under "dev->device_lock" lock
|
||||||
|
*
|
||||||
|
* returns index on success, -ENOENT on failure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < dev->me_clients_num; i++)
|
||||||
|
if (dev->me_clients[i].client_id == client_id)
|
||||||
|
break;
|
||||||
|
if (WARN_ON(dev->me_clients[i].client_id != client_id))
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
if (i == dev->me_clients_num)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mei_ioctl_connect_client - the connect to fw client IOCTL function
|
* mei_ioctl_connect_client - the connect to fw client IOCTL function
|
||||||
|
@ -84,7 +108,7 @@ int mei_ioctl_connect_client(struct file *file,
|
||||||
|
|
||||||
cb->major_file_operations = MEI_IOCTL;
|
cb->major_file_operations = MEI_IOCTL;
|
||||||
|
|
||||||
if (dev->mei_state != MEI_ENABLED) {
|
if (dev->dev_state != MEI_DEV_ENABLED) {
|
||||||
rets = -ENODEV;
|
rets = -ENODEV;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
@ -95,7 +119,7 @@ int mei_ioctl_connect_client(struct file *file,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find ME client we're trying to connect to */
|
/* find ME client we're trying to connect to */
|
||||||
i = mei_find_me_client_index(dev, data->in_client_uuid);
|
i = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
|
||||||
if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
|
if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
|
||||||
cl->me_client_id = dev->me_clients[i].client_id;
|
cl->me_client_id = dev->me_clients[i].client_id;
|
||||||
cl->state = MEI_FILE_CONNECTING;
|
cl->state = MEI_FILE_CONNECTING;
|
||||||
|
@ -273,19 +297,12 @@ int amthi_read(struct mei_device *dev, struct file *file,
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < dev->me_clients_num; i++) {
|
i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
|
||||||
if (dev->me_clients[i].client_id ==
|
|
||||||
dev->iamthif_cl.me_client_id)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == dev->me_clients_num) {
|
if (i < 0) {
|
||||||
dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
|
dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id))
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
dev_dbg(&dev->pdev->dev, "checking amthi data\n");
|
dev_dbg(&dev->pdev->dev, "checking amthi data\n");
|
||||||
cb = find_amthi_read_list_entry(dev, file);
|
cb = find_amthi_read_list_entry(dev, file);
|
||||||
|
|
||||||
|
@ -316,8 +333,7 @@ int amthi_read(struct mei_device *dev, struct file *file,
|
||||||
dev->iamthif_timer = 0;
|
dev->iamthif_timer = 0;
|
||||||
|
|
||||||
if (cb) {
|
if (cb) {
|
||||||
timeout = cb->read_time +
|
timeout = cb->read_time + msecs_to_jiffies(IAMTHIF_READ_TIMER);
|
||||||
msecs_to_jiffies(IAMTHIF_READ_TIMER);
|
|
||||||
dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n",
|
dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n",
|
||||||
timeout);
|
timeout);
|
||||||
|
|
||||||
|
@ -386,7 +402,7 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
|
||||||
if (cl->state != MEI_FILE_CONNECTED)
|
if (cl->state != MEI_FILE_CONNECTED)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (dev->mei_state != MEI_ENABLED)
|
if (dev->dev_state != MEI_DEV_ENABLED)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
dev_dbg(&dev->pdev->dev, "check if read is pending.\n");
|
dev_dbg(&dev->pdev->dev, "check if read is pending.\n");
|
||||||
|
@ -401,19 +417,8 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
|
||||||
|
|
||||||
dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n",
|
dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n",
|
||||||
cl->host_client_id, cl->me_client_id);
|
cl->host_client_id, cl->me_client_id);
|
||||||
|
i = mei_me_cl_by_id(dev, cl->me_client_id);
|
||||||
for (i = 0; i < dev->me_clients_num; i++) {
|
if (i < 0) {
|
||||||
if (dev->me_clients[i].client_id == cl->me_client_id)
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
|
|
||||||
rets = -ENODEV;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == dev->me_clients_num) {
|
|
||||||
rets = -ENODEV;
|
rets = -ENODEV;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,11 +41,8 @@
|
||||||
#include <linux/mei.h>
|
#include <linux/mei.h>
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
|
|
||||||
static const char mei_driver_name[] = "mei";
|
/* AMT device is a singleton on the platform */
|
||||||
|
static struct pci_dev *mei_pdev;
|
||||||
/* The device pointer */
|
|
||||||
/* Currently this driver works as long as there is only a single AMT device. */
|
|
||||||
struct pci_dev *mei_device;
|
|
||||||
|
|
||||||
/* mei_pci_tbl - PCI Device ID Table */
|
/* mei_pci_tbl - PCI Device ID Table */
|
||||||
static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
|
static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
|
||||||
|
@ -80,6 +77,8 @@ static DEFINE_PCI_DEVICE_TABLE(mei_pci_tbl) = {
|
||||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
|
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
|
||||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
|
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
|
||||||
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
|
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
|
||||||
|
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT)},
|
||||||
|
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_LP)},
|
||||||
|
|
||||||
/* required last entry */
|
/* required last entry */
|
||||||
{0, }
|
{0, }
|
||||||
|
@ -220,10 +219,10 @@ static int mei_open(struct inode *inode, struct file *file)
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
if (!mei_device)
|
if (!mei_pdev)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
dev = pci_get_drvdata(mei_device);
|
dev = pci_get_drvdata(mei_pdev);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -234,18 +233,24 @@ static int mei_open(struct inode *inode, struct file *file)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
if (dev->mei_state != MEI_ENABLED) {
|
if (dev->dev_state != MEI_DEV_ENABLED) {
|
||||||
dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED mei_state= %d\n",
|
dev_dbg(&dev->pdev->dev, "dev_state != MEI_ENABLED dev_state = %s\n",
|
||||||
dev->mei_state);
|
mei_dev_state_str(dev->dev_state));
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
err = -EMFILE;
|
err = -EMFILE;
|
||||||
if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT)
|
if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
|
||||||
|
dev_err(&dev->pdev->dev, "open_handle_count exceded %d",
|
||||||
|
MEI_MAX_OPEN_HANDLE_COUNT);
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
cl_id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX);
|
cl_id = find_first_zero_bit(dev->host_clients_map, MEI_CLIENTS_MAX);
|
||||||
if (cl_id >= MEI_CLIENTS_MAX)
|
if (cl_id >= MEI_CLIENTS_MAX) {
|
||||||
|
dev_err(&dev->pdev->dev, "client_id exceded %d",
|
||||||
|
MEI_CLIENTS_MAX) ;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
cl->host_client_id = cl_id;
|
cl->host_client_id = cl_id;
|
||||||
|
|
||||||
|
@ -386,17 +391,16 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
|
||||||
dev = cl->dev;
|
dev = cl->dev;
|
||||||
|
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
if (dev->mei_state != MEI_ENABLED) {
|
if (dev->dev_state != MEI_DEV_ENABLED) {
|
||||||
rets = -ENODEV;
|
rets = -ENODEV;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
|
if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
|
||||||
/* Do not allow to read watchdog client */
|
/* Do not allow to read watchdog client */
|
||||||
i = mei_find_me_client_index(dev, mei_wd_guid);
|
i = mei_me_cl_by_uuid(dev, &mei_wd_guid);
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
struct mei_me_client *me_client = &dev->me_clients[i];
|
struct mei_me_client *me_client = &dev->me_clients[i];
|
||||||
|
|
||||||
if (cl->me_client_id == me_client->client_id) {
|
if (cl->me_client_id == me_client->client_id) {
|
||||||
rets = -EBADF;
|
rets = -EBADF;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -541,7 +545,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
|
||||||
|
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
|
|
||||||
if (dev->mei_state != MEI_ENABLED) {
|
if (dev->dev_state != MEI_DEV_ENABLED) {
|
||||||
mutex_unlock(&dev->device_lock);
|
mutex_unlock(&dev->device_lock);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
@ -616,26 +620,16 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
|
||||||
rets = -ENOMEM;
|
rets = -ENOMEM;
|
||||||
goto unlock_dev;
|
goto unlock_dev;
|
||||||
}
|
}
|
||||||
if (dev->mei_state != MEI_ENABLED) {
|
if (dev->dev_state != MEI_DEV_ENABLED) {
|
||||||
rets = -ENODEV;
|
rets = -ENODEV;
|
||||||
goto unlock_dev;
|
goto unlock_dev;
|
||||||
}
|
}
|
||||||
for (i = 0; i < dev->me_clients_num; i++) {
|
i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
|
||||||
if (dev->me_clients[i].client_id ==
|
if (i < 0) {
|
||||||
dev->iamthif_cl.me_client_id)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
|
|
||||||
rets = -ENODEV;
|
rets = -ENODEV;
|
||||||
goto unlock_dev;
|
goto unlock_dev;
|
||||||
}
|
}
|
||||||
if (i == dev->me_clients_num ||
|
if (length > dev->me_clients[i].props.max_msg_length ||
|
||||||
(dev->me_clients[i].client_id !=
|
|
||||||
dev->iamthif_cl.me_client_id)) {
|
|
||||||
rets = -ENODEV;
|
|
||||||
goto unlock_dev;
|
|
||||||
} else if (length > dev->me_clients[i].props.max_msg_length ||
|
|
||||||
length <= 0) {
|
length <= 0) {
|
||||||
rets = -EMSGSIZE;
|
rets = -EMSGSIZE;
|
||||||
goto unlock_dev;
|
goto unlock_dev;
|
||||||
|
@ -688,16 +682,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
|
||||||
cl->me_client_id);
|
cl->me_client_id);
|
||||||
goto unlock_dev;
|
goto unlock_dev;
|
||||||
}
|
}
|
||||||
for (i = 0; i < dev->me_clients_num; i++) {
|
i = mei_me_cl_by_id(dev, cl->me_client_id);
|
||||||
if (dev->me_clients[i].client_id ==
|
if (i < 0) {
|
||||||
cl->me_client_id)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
|
|
||||||
rets = -ENODEV;
|
|
||||||
goto unlock_dev;
|
|
||||||
}
|
|
||||||
if (i == dev->me_clients_num) {
|
|
||||||
rets = -ENODEV;
|
rets = -ENODEV;
|
||||||
goto unlock_dev;
|
goto unlock_dev;
|
||||||
}
|
}
|
||||||
|
@ -790,7 +776,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
|
||||||
dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd);
|
dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd);
|
||||||
|
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
if (dev->mei_state != MEI_ENABLED) {
|
if (dev->dev_state != MEI_DEV_ENABLED) {
|
||||||
rets = -ENODEV;
|
rets = -ENODEV;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -869,7 +855,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
|
||||||
|
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
|
|
||||||
if (dev->mei_state != MEI_ENABLED)
|
if (dev->dev_state != MEI_DEV_ENABLED)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
||||||
|
@ -966,7 +952,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mei_device) {
|
if (mei_pdev) {
|
||||||
err = -EEXIST;
|
err = -EEXIST;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
@ -979,7 +965,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
|
||||||
/* set PCI host mastering */
|
/* set PCI host mastering */
|
||||||
pci_set_master(pdev);
|
pci_set_master(pdev);
|
||||||
/* pci request regions for mei driver */
|
/* pci request regions for mei driver */
|
||||||
err = pci_request_regions(pdev, mei_driver_name);
|
err = pci_request_regions(pdev, KBUILD_MODNAME);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&pdev->dev, "failed to get pci regions.\n");
|
dev_err(&pdev->dev, "failed to get pci regions.\n");
|
||||||
goto disable_device;
|
goto disable_device;
|
||||||
|
@ -1004,12 +990,12 @@ static int __devinit mei_probe(struct pci_dev *pdev,
|
||||||
err = request_threaded_irq(pdev->irq,
|
err = request_threaded_irq(pdev->irq,
|
||||||
NULL,
|
NULL,
|
||||||
mei_interrupt_thread_handler,
|
mei_interrupt_thread_handler,
|
||||||
IRQF_ONESHOT, mei_driver_name, dev);
|
IRQF_ONESHOT, KBUILD_MODNAME, dev);
|
||||||
else
|
else
|
||||||
err = request_threaded_irq(pdev->irq,
|
err = request_threaded_irq(pdev->irq,
|
||||||
mei_interrupt_quick_handler,
|
mei_interrupt_quick_handler,
|
||||||
mei_interrupt_thread_handler,
|
mei_interrupt_thread_handler,
|
||||||
IRQF_SHARED, mei_driver_name, dev);
|
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
|
dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
|
||||||
|
@ -1027,7 +1013,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
|
||||||
if (err)
|
if (err)
|
||||||
goto release_irq;
|
goto release_irq;
|
||||||
|
|
||||||
mei_device = pdev;
|
mei_pdev = pdev;
|
||||||
pci_set_drvdata(pdev, dev);
|
pci_set_drvdata(pdev, dev);
|
||||||
|
|
||||||
|
|
||||||
|
@ -1072,7 +1058,7 @@ static void __devexit mei_remove(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct mei_device *dev;
|
struct mei_device *dev;
|
||||||
|
|
||||||
if (mei_device != pdev)
|
if (mei_pdev != pdev)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dev = pci_get_drvdata(pdev);
|
dev = pci_get_drvdata(pdev);
|
||||||
|
@ -1081,9 +1067,11 @@ static void __devexit mei_remove(struct pci_dev *pdev)
|
||||||
|
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
|
|
||||||
mei_wd_stop(dev, false);
|
cancel_delayed_work(&dev->timer_work);
|
||||||
|
|
||||||
mei_device = NULL;
|
mei_wd_stop(dev);
|
||||||
|
|
||||||
|
mei_pdev = NULL;
|
||||||
|
|
||||||
if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
|
if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
|
||||||
dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
|
dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
|
||||||
|
@ -1136,12 +1124,15 @@ static int mei_pci_suspend(struct device *device)
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
|
|
||||||
|
cancel_delayed_work(&dev->timer_work);
|
||||||
|
|
||||||
/* Stop watchdog if exists */
|
/* Stop watchdog if exists */
|
||||||
err = mei_wd_stop(dev, true);
|
err = mei_wd_stop(dev);
|
||||||
/* Set new mei state */
|
/* Set new mei state */
|
||||||
if (dev->mei_state == MEI_ENABLED ||
|
if (dev->dev_state == MEI_DEV_ENABLED ||
|
||||||
dev->mei_state == MEI_RECOVERING_FROM_RESET) {
|
dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
|
||||||
dev->mei_state = MEI_POWER_DOWN;
|
dev->dev_state = MEI_DEV_POWER_DOWN;
|
||||||
mei_reset(dev, 0);
|
mei_reset(dev, 0);
|
||||||
}
|
}
|
||||||
mutex_unlock(&dev->device_lock);
|
mutex_unlock(&dev->device_lock);
|
||||||
|
@ -1169,12 +1160,12 @@ static int mei_pci_resume(struct device *device)
|
||||||
err = request_threaded_irq(pdev->irq,
|
err = request_threaded_irq(pdev->irq,
|
||||||
NULL,
|
NULL,
|
||||||
mei_interrupt_thread_handler,
|
mei_interrupt_thread_handler,
|
||||||
IRQF_ONESHOT, mei_driver_name, dev);
|
IRQF_ONESHOT, KBUILD_MODNAME, dev);
|
||||||
else
|
else
|
||||||
err = request_threaded_irq(pdev->irq,
|
err = request_threaded_irq(pdev->irq,
|
||||||
mei_interrupt_quick_handler,
|
mei_interrupt_quick_handler,
|
||||||
mei_interrupt_thread_handler,
|
mei_interrupt_thread_handler,
|
||||||
IRQF_SHARED, mei_driver_name, dev);
|
IRQF_SHARED, KBUILD_MODNAME, dev);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
|
dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
|
||||||
|
@ -1183,7 +1174,7 @@ static int mei_pci_resume(struct device *device)
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
dev->mei_state = MEI_POWER_UP;
|
dev->dev_state = MEI_DEV_POWER_UP;
|
||||||
mei_reset(dev, 1);
|
mei_reset(dev, 1);
|
||||||
mutex_unlock(&dev->device_lock);
|
mutex_unlock(&dev->device_lock);
|
||||||
|
|
||||||
|
@ -1201,7 +1192,7 @@ static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
|
||||||
* PCI driver structure
|
* PCI driver structure
|
||||||
*/
|
*/
|
||||||
static struct pci_driver mei_driver = {
|
static struct pci_driver mei_driver = {
|
||||||
.name = mei_driver_name,
|
.name = KBUILD_MODNAME,
|
||||||
.id_table = mei_pci_tbl,
|
.id_table = mei_pci_tbl,
|
||||||
.probe = mei_probe,
|
.probe = mei_probe,
|
||||||
.remove = __devexit_p(mei_remove),
|
.remove = __devexit_p(mei_remove),
|
||||||
|
|
|
@ -25,18 +25,20 @@
|
||||||
/*
|
/*
|
||||||
* watch dog definition
|
* watch dog definition
|
||||||
*/
|
*/
|
||||||
#define MEI_WATCHDOG_DATA_SIZE 16
|
#define MEI_WD_HDR_SIZE 4
|
||||||
#define MEI_START_WD_DATA_SIZE 20
|
#define MEI_WD_STOP_MSG_SIZE MEI_WD_HDR_SIZE
|
||||||
#define MEI_WD_PARAMS_SIZE 4
|
#define MEI_WD_START_MSG_SIZE (MEI_WD_HDR_SIZE + 16)
|
||||||
|
|
||||||
|
#define MEI_WD_DEFAULT_TIMEOUT 120 /* seconds */
|
||||||
|
#define MEI_WD_MIN_TIMEOUT 120 /* seconds */
|
||||||
|
#define MEI_WD_MAX_TIMEOUT 65535 /* seconds */
|
||||||
|
|
||||||
|
#define MEI_WD_STOP_TIMEOUT 10 /* msecs */
|
||||||
|
|
||||||
#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0)
|
#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0)
|
||||||
|
|
||||||
#define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32))
|
#define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32))
|
||||||
|
|
||||||
/*
|
|
||||||
* MEI PCI Device object
|
|
||||||
*/
|
|
||||||
extern struct pci_dev *mei_device;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AMTHI Client UUID
|
* AMTHI Client UUID
|
||||||
|
@ -53,20 +55,22 @@ extern const uuid_le mei_wd_guid;
|
||||||
*/
|
*/
|
||||||
extern const u8 mei_wd_state_independence_msg[3][4];
|
extern const u8 mei_wd_state_independence_msg[3][4];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of Maximum MEI Clients
|
||||||
|
*/
|
||||||
|
#define MEI_CLIENTS_MAX 256
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Number of File descriptors/handles
|
* Number of File descriptors/handles
|
||||||
* that can be opened to the driver.
|
* that can be opened to the driver.
|
||||||
*
|
*
|
||||||
* Limit to 253: 255 Total Clients
|
* Limit to 253: 256 Total Clients
|
||||||
|
* minus internal client for MEI Bus Messags
|
||||||
* minus internal client for AMTHI
|
* minus internal client for AMTHI
|
||||||
* minus internal client for Watchdog
|
* minus internal client for Watchdog
|
||||||
*/
|
*/
|
||||||
#define MEI_MAX_OPEN_HANDLE_COUNT 253
|
#define MEI_MAX_OPEN_HANDLE_COUNT (MEI_CLIENTS_MAX - 3)
|
||||||
|
|
||||||
/*
|
|
||||||
* Number of Maximum MEI Clients
|
|
||||||
*/
|
|
||||||
#define MEI_CLIENTS_MAX 255
|
|
||||||
|
|
||||||
/* File state */
|
/* File state */
|
||||||
enum file_state {
|
enum file_state {
|
||||||
|
@ -78,17 +82,19 @@ enum file_state {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* MEI device states */
|
/* MEI device states */
|
||||||
enum mei_states {
|
enum mei_dev_state {
|
||||||
MEI_INITIALIZING = 0,
|
MEI_DEV_INITIALIZING = 0,
|
||||||
MEI_INIT_CLIENTS,
|
MEI_DEV_INIT_CLIENTS,
|
||||||
MEI_ENABLED,
|
MEI_DEV_ENABLED,
|
||||||
MEI_RESETING,
|
MEI_DEV_RESETING,
|
||||||
MEI_DISABLED,
|
MEI_DEV_DISABLED,
|
||||||
MEI_RECOVERING_FROM_RESET,
|
MEI_DEV_RECOVERING_FROM_RESET,
|
||||||
MEI_POWER_DOWN,
|
MEI_DEV_POWER_DOWN,
|
||||||
MEI_POWER_UP
|
MEI_DEV_POWER_UP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *mei_dev_state_str(int state);
|
||||||
|
|
||||||
/* init clients states*/
|
/* init clients states*/
|
||||||
enum mei_init_clients_states {
|
enum mei_init_clients_states {
|
||||||
MEI_START_MESSAGE = 0,
|
MEI_START_MESSAGE = 0,
|
||||||
|
@ -113,6 +119,12 @@ enum mei_file_transaction_states {
|
||||||
MEI_READ_COMPLETE
|
MEI_READ_COMPLETE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum mei_wd_states {
|
||||||
|
MEI_WD_IDLE,
|
||||||
|
MEI_WD_RUNNING,
|
||||||
|
MEI_WD_STOPPING,
|
||||||
|
};
|
||||||
|
|
||||||
/* MEI CB */
|
/* MEI CB */
|
||||||
enum mei_cb_major_types {
|
enum mei_cb_major_types {
|
||||||
MEI_READ = 0,
|
MEI_READ = 0,
|
||||||
|
@ -128,7 +140,7 @@ enum mei_cb_major_types {
|
||||||
struct mei_message_data {
|
struct mei_message_data {
|
||||||
u32 size;
|
u32 size;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
} __packed;
|
};
|
||||||
|
|
||||||
|
|
||||||
struct mei_cl_cb {
|
struct mei_cl_cb {
|
||||||
|
@ -218,10 +230,9 @@ struct mei_device {
|
||||||
/*
|
/*
|
||||||
* mei device states
|
* mei device states
|
||||||
*/
|
*/
|
||||||
enum mei_states mei_state;
|
enum mei_dev_state dev_state;
|
||||||
enum mei_init_clients_states init_clients_state;
|
enum mei_init_clients_states init_clients_state;
|
||||||
u16 init_clients_timer;
|
u16 init_clients_timer;
|
||||||
bool stop;
|
|
||||||
bool need_reset;
|
bool need_reset;
|
||||||
|
|
||||||
u32 extra_write_index;
|
u32 extra_write_index;
|
||||||
|
@ -241,12 +252,11 @@ struct mei_device {
|
||||||
bool mei_host_buffer_is_empty;
|
bool mei_host_buffer_is_empty;
|
||||||
|
|
||||||
struct mei_cl wd_cl;
|
struct mei_cl wd_cl;
|
||||||
|
enum mei_wd_states wd_state;
|
||||||
bool wd_interface_reg;
|
bool wd_interface_reg;
|
||||||
bool wd_pending;
|
bool wd_pending;
|
||||||
bool wd_stopped;
|
u16 wd_timeout;
|
||||||
bool wd_bypass; /* if false, don't refresh watchdog ME client */
|
unsigned char wd_data[MEI_WD_START_MSG_SIZE];
|
||||||
u16 wd_timeout; /* seconds ((wd_data[1] << 8) + wd_data[0]) */
|
|
||||||
unsigned char wd_data[MEI_START_WD_DATA_SIZE];
|
|
||||||
|
|
||||||
|
|
||||||
struct file *iamthif_file_object;
|
struct file *iamthif_file_object;
|
||||||
|
@ -279,9 +289,10 @@ void mei_host_init_iamthif(struct mei_device *dev);
|
||||||
void mei_allocate_me_clients_storage(struct mei_device *dev);
|
void mei_allocate_me_clients_storage(struct mei_device *dev);
|
||||||
|
|
||||||
|
|
||||||
u8 mei_find_me_client_update_filext(struct mei_device *dev,
|
int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl,
|
||||||
struct mei_cl *priv,
|
const uuid_le *cguid, u8 host_client_id);
|
||||||
const uuid_le *cguid, u8 client_id);
|
int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid);
|
||||||
|
int mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MEI IO List Functions
|
* MEI IO List Functions
|
||||||
|
@ -348,7 +359,6 @@ void mei_run_next_iamthif_cmd(struct mei_device *dev);
|
||||||
|
|
||||||
void mei_free_cb_private(struct mei_cl_cb *priv_cb);
|
void mei_free_cb_private(struct mei_cl_cb *priv_cb);
|
||||||
|
|
||||||
int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register Access Function
|
* Register Access Function
|
||||||
|
|
|
@ -48,8 +48,8 @@ const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
|
||||||
static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
|
static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
|
||||||
{
|
{
|
||||||
dev_dbg(&dev->pdev->dev, "wd: set timeout=%d.\n", timeout);
|
dev_dbg(&dev->pdev->dev, "wd: set timeout=%d.\n", timeout);
|
||||||
memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE);
|
memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE);
|
||||||
memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE, &timeout, sizeof(u16));
|
memcpy(dev->wd_data + MEI_WD_HDR_SIZE, &timeout, sizeof(u16));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,10 +66,11 @@ int mei_wd_host_init(struct mei_device *dev)
|
||||||
|
|
||||||
/* look for WD client and connect to it */
|
/* look for WD client and connect to it */
|
||||||
dev->wd_cl.state = MEI_FILE_DISCONNECTED;
|
dev->wd_cl.state = MEI_FILE_DISCONNECTED;
|
||||||
dev->wd_timeout = AMT_WD_DEFAULT_TIMEOUT;
|
dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT;
|
||||||
|
dev->wd_state = MEI_WD_IDLE;
|
||||||
|
|
||||||
/* find ME WD client */
|
/* find ME WD client */
|
||||||
mei_find_me_client_update_filext(dev, &dev->wd_cl,
|
mei_me_cl_update_filext(dev, &dev->wd_cl,
|
||||||
&mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
|
&mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
|
||||||
|
|
||||||
dev_dbg(&dev->pdev->dev, "wd: check client\n");
|
dev_dbg(&dev->pdev->dev, "wd: check client\n");
|
||||||
|
@ -108,10 +109,10 @@ int mei_wd_send(struct mei_device *dev)
|
||||||
mei_hdr->msg_complete = 1;
|
mei_hdr->msg_complete = 1;
|
||||||
mei_hdr->reserved = 0;
|
mei_hdr->reserved = 0;
|
||||||
|
|
||||||
if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE))
|
if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE))
|
||||||
mei_hdr->length = MEI_START_WD_DATA_SIZE;
|
mei_hdr->length = MEI_WD_START_MSG_SIZE;
|
||||||
else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE))
|
else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
|
||||||
mei_hdr->length = MEI_WD_PARAMS_SIZE;
|
mei_hdr->length = MEI_WD_STOP_MSG_SIZE;
|
||||||
else
|
else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -128,18 +129,17 @@ int mei_wd_send(struct mei_device *dev)
|
||||||
* -EIO when message send fails
|
* -EIO when message send fails
|
||||||
* -EINVAL when invalid message is to be sent
|
* -EINVAL when invalid message is to be sent
|
||||||
*/
|
*/
|
||||||
int mei_wd_stop(struct mei_device *dev, bool preserve)
|
int mei_wd_stop(struct mei_device *dev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
u16 wd_timeout = dev->wd_timeout;
|
|
||||||
|
|
||||||
cancel_delayed_work(&dev->timer_work);
|
if (dev->wd_cl.state != MEI_FILE_CONNECTED ||
|
||||||
if (dev->wd_cl.state != MEI_FILE_CONNECTED || !dev->wd_timeout)
|
dev->wd_state != MEI_WD_RUNNING)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dev->wd_timeout = 0;
|
memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_STOP_MSG_SIZE);
|
||||||
memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE);
|
|
||||||
dev->stop = true;
|
dev->wd_state = MEI_WD_STOPPING;
|
||||||
|
|
||||||
ret = mei_flow_ctrl_creds(dev, &dev->wd_cl);
|
ret = mei_flow_ctrl_creds(dev, &dev->wd_cl);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -161,13 +161,14 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
|
||||||
} else {
|
} else {
|
||||||
dev->wd_pending = true;
|
dev->wd_pending = true;
|
||||||
}
|
}
|
||||||
dev->wd_stopped = false;
|
|
||||||
mutex_unlock(&dev->device_lock);
|
mutex_unlock(&dev->device_lock);
|
||||||
|
|
||||||
ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
|
ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
|
||||||
dev->wd_stopped, 10 * HZ);
|
dev->wd_state == MEI_WD_IDLE,
|
||||||
|
msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
if (dev->wd_stopped) {
|
if (dev->wd_state == MEI_WD_IDLE) {
|
||||||
dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
|
dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -177,9 +178,6 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
|
||||||
"wd: stop failed to complete ret=%d.\n", ret);
|
"wd: stop failed to complete ret=%d.\n", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preserve)
|
|
||||||
dev->wd_timeout = wd_timeout;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -196,16 +194,16 @@ static int mei_wd_ops_start(struct watchdog_device *wd_dev)
|
||||||
int err = -ENODEV;
|
int err = -ENODEV;
|
||||||
struct mei_device *dev;
|
struct mei_device *dev;
|
||||||
|
|
||||||
dev = pci_get_drvdata(mei_device);
|
dev = watchdog_get_drvdata(wd_dev);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
|
|
||||||
if (dev->mei_state != MEI_ENABLED) {
|
if (dev->dev_state != MEI_DEV_ENABLED) {
|
||||||
dev_dbg(&dev->pdev->dev,
|
dev_dbg(&dev->pdev->dev,
|
||||||
"wd: mei_state != MEI_ENABLED mei_state = %d\n",
|
"wd: dev_state != MEI_DEV_ENABLED dev_state = %s\n",
|
||||||
dev->mei_state);
|
mei_dev_state_str(dev->dev_state));
|
||||||
goto end_unlock;
|
goto end_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,13 +231,13 @@ end_unlock:
|
||||||
static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
|
static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
|
||||||
{
|
{
|
||||||
struct mei_device *dev;
|
struct mei_device *dev;
|
||||||
dev = pci_get_drvdata(mei_device);
|
|
||||||
|
|
||||||
|
dev = watchdog_get_drvdata(wd_dev);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
mei_wd_stop(dev, false);
|
mei_wd_stop(dev);
|
||||||
mutex_unlock(&dev->device_lock);
|
mutex_unlock(&dev->device_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -256,8 +254,8 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct mei_device *dev;
|
struct mei_device *dev;
|
||||||
dev = pci_get_drvdata(mei_device);
|
|
||||||
|
|
||||||
|
dev = watchdog_get_drvdata(wd_dev);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
@ -269,6 +267,8 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev->wd_state = MEI_WD_RUNNING;
|
||||||
|
|
||||||
/* Check if we can send the ping to HW*/
|
/* Check if we can send the ping to HW*/
|
||||||
if (dev->mei_host_buffer_is_empty &&
|
if (dev->mei_host_buffer_is_empty &&
|
||||||
mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
|
mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
|
||||||
|
@ -309,13 +309,13 @@ end:
|
||||||
static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout)
|
static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout)
|
||||||
{
|
{
|
||||||
struct mei_device *dev;
|
struct mei_device *dev;
|
||||||
dev = pci_get_drvdata(mei_device);
|
|
||||||
|
|
||||||
|
dev = watchdog_get_drvdata(wd_dev);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
/* Check Timeout value */
|
/* Check Timeout value */
|
||||||
if (timeout < AMT_WD_MIN_TIMEOUT || timeout > AMT_WD_MAX_TIMEOUT)
|
if (timeout < MEI_WD_MIN_TIMEOUT || timeout > MEI_WD_MAX_TIMEOUT)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&dev->device_lock);
|
mutex_lock(&dev->device_lock);
|
||||||
|
@ -341,37 +341,42 @@ static const struct watchdog_ops wd_ops = {
|
||||||
};
|
};
|
||||||
static const struct watchdog_info wd_info = {
|
static const struct watchdog_info wd_info = {
|
||||||
.identity = INTEL_AMT_WATCHDOG_ID,
|
.identity = INTEL_AMT_WATCHDOG_ID,
|
||||||
.options = WDIOF_KEEPALIVEPING | WDIOF_ALARMONLY,
|
.options = WDIOF_KEEPALIVEPING |
|
||||||
|
WDIOF_SETTIMEOUT |
|
||||||
|
WDIOF_ALARMONLY,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct watchdog_device amt_wd_dev = {
|
static struct watchdog_device amt_wd_dev = {
|
||||||
.info = &wd_info,
|
.info = &wd_info,
|
||||||
.ops = &wd_ops,
|
.ops = &wd_ops,
|
||||||
.timeout = AMT_WD_DEFAULT_TIMEOUT,
|
.timeout = MEI_WD_DEFAULT_TIMEOUT,
|
||||||
.min_timeout = AMT_WD_MIN_TIMEOUT,
|
.min_timeout = MEI_WD_MIN_TIMEOUT,
|
||||||
.max_timeout = AMT_WD_MAX_TIMEOUT,
|
.max_timeout = MEI_WD_MAX_TIMEOUT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void mei_watchdog_register(struct mei_device *dev)
|
void mei_watchdog_register(struct mei_device *dev)
|
||||||
{
|
{
|
||||||
dev_dbg(&dev->pdev->dev, "dev->wd_timeout =%d.\n", dev->wd_timeout);
|
|
||||||
|
|
||||||
if (watchdog_register_device(&amt_wd_dev)) {
|
if (watchdog_register_device(&amt_wd_dev)) {
|
||||||
dev_err(&dev->pdev->dev,
|
dev_err(&dev->pdev->dev,
|
||||||
"wd: unable to register watchdog device.\n");
|
"wd: unable to register watchdog device.\n");
|
||||||
dev->wd_interface_reg = false;
|
dev->wd_interface_reg = false;
|
||||||
} else {
|
return;
|
||||||
dev_dbg(&dev->pdev->dev,
|
|
||||||
"wd: successfully register watchdog interface.\n");
|
|
||||||
dev->wd_interface_reg = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev_dbg(&dev->pdev->dev,
|
||||||
|
"wd: successfully register watchdog interface.\n");
|
||||||
|
dev->wd_interface_reg = true;
|
||||||
|
watchdog_set_drvdata(&amt_wd_dev, dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mei_watchdog_unregister(struct mei_device *dev)
|
void mei_watchdog_unregister(struct mei_device *dev)
|
||||||
{
|
{
|
||||||
if (dev->wd_interface_reg)
|
if (!dev->wd_interface_reg)
|
||||||
watchdog_unregister_device(&amt_wd_dev);
|
return;
|
||||||
|
|
||||||
|
watchdog_set_drvdata(&amt_wd_dev, NULL);
|
||||||
|
watchdog_unregister_device(&amt_wd_dev);
|
||||||
dev->wd_interface_reg = false;
|
dev->wd_interface_reg = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -699,7 +699,7 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev,
|
||||||
chip->pch_phub_base_address = pci_iomap(pdev, 1, 0);
|
chip->pch_phub_base_address = pci_iomap(pdev, 1, 0);
|
||||||
|
|
||||||
|
|
||||||
if (chip->pch_phub_base_address == 0) {
|
if (chip->pch_phub_base_address == NULL) {
|
||||||
dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__);
|
dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__);
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err_pci_iomap;
|
goto err_pci_iomap;
|
||||||
|
@ -893,18 +893,7 @@ static struct pci_driver pch_phub_driver = {
|
||||||
.resume = pch_phub_resume
|
.resume = pch_phub_resume
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init pch_phub_pci_init(void)
|
module_pci_driver(pch_phub_driver);
|
||||||
{
|
|
||||||
return pci_register_driver(&pch_phub_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit pch_phub_pci_exit(void)
|
|
||||||
{
|
|
||||||
pci_unregister_driver(&pch_phub_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(pch_phub_pci_init);
|
|
||||||
module_exit(pch_phub_pci_exit);
|
|
||||||
|
|
||||||
MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7223) PHUB");
|
MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7223) PHUB");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -30,11 +30,13 @@
|
||||||
|
|
||||||
#include <linux/ti_wilink_st.h>
|
#include <linux/ti_wilink_st.h>
|
||||||
|
|
||||||
|
extern void st_kim_recv(void *, const unsigned char *, long);
|
||||||
|
void st_int_recv(void *, const unsigned char *, long);
|
||||||
/* function pointer pointing to either,
|
/* function pointer pointing to either,
|
||||||
* st_kim_recv during registration to receive fw download responses
|
* st_kim_recv during registration to receive fw download responses
|
||||||
* st_int_recv after registration to receive proto stack responses
|
* st_int_recv after registration to receive proto stack responses
|
||||||
*/
|
*/
|
||||||
void (*st_recv) (void*, const unsigned char*, long);
|
static void (*st_recv) (void *, const unsigned char *, long);
|
||||||
|
|
||||||
/********************************************************************/
|
/********************************************************************/
|
||||||
static void add_channel_to_table(struct st_data_s *st_gdata,
|
static void add_channel_to_table(struct st_data_s *st_gdata,
|
||||||
|
@ -100,7 +102,7 @@ int st_int_write(struct st_data_s *st_gdata,
|
||||||
* push the skb received to relevant
|
* push the skb received to relevant
|
||||||
* protocol stacks
|
* protocol stacks
|
||||||
*/
|
*/
|
||||||
void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
|
static void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
|
||||||
{
|
{
|
||||||
pr_debug(" %s(prot:%d) ", __func__, chnl_id);
|
pr_debug(" %s(prot:%d) ", __func__, chnl_id);
|
||||||
|
|
||||||
|
@ -140,7 +142,7 @@ void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
|
||||||
* This function is being called with spin lock held, protocol drivers are
|
* This function is being called with spin lock held, protocol drivers are
|
||||||
* only expected to complete their waits and do nothing more than that.
|
* only expected to complete their waits and do nothing more than that.
|
||||||
*/
|
*/
|
||||||
void st_reg_complete(struct st_data_s *st_gdata, char err)
|
static void st_reg_complete(struct st_data_s *st_gdata, char err)
|
||||||
{
|
{
|
||||||
unsigned char i = 0;
|
unsigned char i = 0;
|
||||||
pr_info(" %s ", __func__);
|
pr_info(" %s ", __func__);
|
||||||
|
@ -379,7 +381,7 @@ done:
|
||||||
* completely, return that skb which has the pending data.
|
* completely, return that skb which has the pending data.
|
||||||
* In normal cases, return top of txq.
|
* In normal cases, return top of txq.
|
||||||
*/
|
*/
|
||||||
struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata)
|
static struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata)
|
||||||
{
|
{
|
||||||
struct sk_buff *returning_skb;
|
struct sk_buff *returning_skb;
|
||||||
|
|
||||||
|
@ -401,7 +403,7 @@ struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata)
|
||||||
* txq and waitq needs protection since the other contexts
|
* txq and waitq needs protection since the other contexts
|
||||||
* may be sending data, waking up chip.
|
* may be sending data, waking up chip.
|
||||||
*/
|
*/
|
||||||
void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
|
static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
unsigned long flags = 0;
|
unsigned long flags = 0;
|
||||||
|
|
||||||
|
|
|
@ -63,10 +63,27 @@ static struct platform_device *st_get_plat_device(int id)
|
||||||
* in case of error don't complete so that waiting for proper
|
* in case of error don't complete so that waiting for proper
|
||||||
* response times out
|
* response times out
|
||||||
*/
|
*/
|
||||||
void validate_firmware_response(struct kim_data_s *kim_gdata)
|
static void validate_firmware_response(struct kim_data_s *kim_gdata)
|
||||||
{
|
{
|
||||||
struct sk_buff *skb = kim_gdata->rx_skb;
|
struct sk_buff *skb = kim_gdata->rx_skb;
|
||||||
if (unlikely(skb->data[5] != 0)) {
|
if (!skb)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* these magic numbers are the position in the response buffer which
|
||||||
|
* allows us to distinguish whether the response is for the read
|
||||||
|
* version info. command
|
||||||
|
*/
|
||||||
|
if (skb->data[2] == 0x01 && skb->data[3] == 0x01 &&
|
||||||
|
skb->data[4] == 0x10 && skb->data[5] == 0x00) {
|
||||||
|
/* fw version response */
|
||||||
|
memcpy(kim_gdata->resp_buffer,
|
||||||
|
kim_gdata->rx_skb->data,
|
||||||
|
kim_gdata->rx_skb->len);
|
||||||
|
complete_all(&kim_gdata->kim_rcvd);
|
||||||
|
kim_gdata->rx_state = ST_W4_PACKET_TYPE;
|
||||||
|
kim_gdata->rx_skb = NULL;
|
||||||
|
kim_gdata->rx_count = 0;
|
||||||
|
} else if (unlikely(skb->data[5] != 0)) {
|
||||||
pr_err("no proper response during fw download");
|
pr_err("no proper response during fw download");
|
||||||
pr_err("data6 %x", skb->data[5]);
|
pr_err("data6 %x", skb->data[5]);
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
@ -119,7 +136,7 @@ static inline int kim_check_data_len(struct kim_data_s *kim_gdata, int len)
|
||||||
* have been observed to come in bursts of different
|
* have been observed to come in bursts of different
|
||||||
* tty_receive and hence the logic
|
* tty_receive and hence the logic
|
||||||
*/
|
*/
|
||||||
void kim_int_recv(struct kim_data_s *kim_gdata,
|
static void kim_int_recv(struct kim_data_s *kim_gdata,
|
||||||
const unsigned char *data, long count)
|
const unsigned char *data, long count)
|
||||||
{
|
{
|
||||||
const unsigned char *ptr;
|
const unsigned char *ptr;
|
||||||
|
@ -207,16 +224,19 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wait_for_completion_timeout
|
if (!wait_for_completion_interruptible_timeout(
|
||||||
(&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
|
&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
|
||||||
pr_err(" waiting for ver info- timed out ");
|
pr_err(" waiting for ver info- timed out ");
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
INIT_COMPLETION(kim_gdata->kim_rcvd);
|
INIT_COMPLETION(kim_gdata->kim_rcvd);
|
||||||
|
/* the positions 12 & 13 in the response buffer provide with the
|
||||||
|
* chip, major & minor numbers
|
||||||
|
*/
|
||||||
|
|
||||||
version =
|
version =
|
||||||
MAKEWORD(kim_gdata->resp_buffer[13],
|
MAKEWORD(kim_gdata->resp_buffer[12],
|
||||||
kim_gdata->resp_buffer[14]);
|
kim_gdata->resp_buffer[13]);
|
||||||
chip = (version & 0x7C00) >> 10;
|
chip = (version & 0x7C00) >> 10;
|
||||||
min_ver = (version & 0x007F);
|
min_ver = (version & 0x007F);
|
||||||
maj_ver = (version & 0x0380) >> 7;
|
maj_ver = (version & 0x0380) >> 7;
|
||||||
|
@ -236,7 +256,7 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void skip_change_remote_baud(unsigned char **ptr, long *len)
|
static void skip_change_remote_baud(unsigned char **ptr, long *len)
|
||||||
{
|
{
|
||||||
unsigned char *nxt_action, *cur_action;
|
unsigned char *nxt_action, *cur_action;
|
||||||
cur_action = *ptr;
|
cur_action = *ptr;
|
||||||
|
@ -370,9 +390,9 @@ static long download_firmware(struct kim_data_s *kim_gdata)
|
||||||
break;
|
break;
|
||||||
case ACTION_WAIT_EVENT: /* wait */
|
case ACTION_WAIT_EVENT: /* wait */
|
||||||
pr_debug("W");
|
pr_debug("W");
|
||||||
if (!wait_for_completion_timeout
|
if (!wait_for_completion_interruptible_timeout(
|
||||||
(&kim_gdata->kim_rcvd,
|
&kim_gdata->kim_rcvd,
|
||||||
msecs_to_jiffies(CMD_RESP_TIME))) {
|
msecs_to_jiffies(CMD_RESP_TIME))) {
|
||||||
pr_err("response timeout during fw download ");
|
pr_err("response timeout during fw download ");
|
||||||
/* timed out */
|
/* timed out */
|
||||||
release_firmware(kim_gdata->fw_entry);
|
release_firmware(kim_gdata->fw_entry);
|
||||||
|
@ -410,16 +430,10 @@ void st_kim_recv(void *disc_data, const unsigned char *data, long count)
|
||||||
struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
|
struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
|
||||||
struct kim_data_s *kim_gdata = st_gdata->kim_data;
|
struct kim_data_s *kim_gdata = st_gdata->kim_data;
|
||||||
|
|
||||||
/* copy to local buffer */
|
/* proceed to gather all data and distinguish read fw version response
|
||||||
if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) {
|
* from other fw responses when data gathering is complete
|
||||||
/* must be the read_ver_cmd */
|
*/
|
||||||
memcpy(kim_gdata->resp_buffer, data, count);
|
kim_int_recv(kim_gdata, data, count);
|
||||||
complete_all(&kim_gdata->kim_rcvd);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
kim_int_recv(kim_gdata, data, count);
|
|
||||||
/* either completes or times out */
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,11 +468,6 @@ long st_kim_start(void *kim_data)
|
||||||
if (pdata->chip_enable)
|
if (pdata->chip_enable)
|
||||||
pdata->chip_enable(kim_gdata);
|
pdata->chip_enable(kim_gdata);
|
||||||
|
|
||||||
/* Configure BT nShutdown to HIGH state */
|
|
||||||
gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
|
|
||||||
mdelay(5); /* FIXME: a proper toggle */
|
|
||||||
gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH);
|
|
||||||
mdelay(100);
|
|
||||||
/* re-initialize the completion */
|
/* re-initialize the completion */
|
||||||
INIT_COMPLETION(kim_gdata->ldisc_installed);
|
INIT_COMPLETION(kim_gdata->ldisc_installed);
|
||||||
/* send notification to UIM */
|
/* send notification to UIM */
|
||||||
|
@ -467,8 +476,8 @@ long st_kim_start(void *kim_data)
|
||||||
sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
|
sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
|
||||||
NULL, "install");
|
NULL, "install");
|
||||||
/* wait for ldisc to be installed */
|
/* wait for ldisc to be installed */
|
||||||
err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
|
err = wait_for_completion_interruptible_timeout(
|
||||||
msecs_to_jiffies(LDISC_TIME));
|
&kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME));
|
||||||
if (!err) {
|
if (!err) {
|
||||||
/* ldisc installation timeout,
|
/* ldisc installation timeout,
|
||||||
* flush uart, power cycle BT_EN */
|
* flush uart, power cycle BT_EN */
|
||||||
|
@ -500,8 +509,7 @@ long st_kim_start(void *kim_data)
|
||||||
* (b) upon failure to either install ldisc or download firmware.
|
* (b) upon failure to either install ldisc or download firmware.
|
||||||
* The function is responsible to (a) notify UIM about un-installation,
|
* The function is responsible to (a) notify UIM about un-installation,
|
||||||
* (b) flush UART if the ldisc was installed.
|
* (b) flush UART if the ldisc was installed.
|
||||||
* (c) reset BT_EN - pull down nshutdown at the end.
|
* (c) invoke platform's chip disabling routine.
|
||||||
* (d) invoke platform's chip disabling routine.
|
|
||||||
*/
|
*/
|
||||||
long st_kim_stop(void *kim_data)
|
long st_kim_stop(void *kim_data)
|
||||||
{
|
{
|
||||||
|
@ -526,20 +534,13 @@ long st_kim_stop(void *kim_data)
|
||||||
sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, NULL, "install");
|
sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, NULL, "install");
|
||||||
|
|
||||||
/* wait for ldisc to be un-installed */
|
/* wait for ldisc to be un-installed */
|
||||||
err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
|
err = wait_for_completion_interruptible_timeout(
|
||||||
msecs_to_jiffies(LDISC_TIME));
|
&kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME));
|
||||||
if (!err) { /* timeout */
|
if (!err) { /* timeout */
|
||||||
pr_err(" timed out waiting for ldisc to be un-installed");
|
pr_err(" timed out waiting for ldisc to be un-installed");
|
||||||
return -ETIMEDOUT;
|
err = -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* By default configure BT nShutdown to LOW state */
|
|
||||||
gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
|
|
||||||
mdelay(1);
|
|
||||||
gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH);
|
|
||||||
mdelay(1);
|
|
||||||
gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
|
|
||||||
|
|
||||||
/* platform specific disable */
|
/* platform specific disable */
|
||||||
if (pdata->chip_disable)
|
if (pdata->chip_disable)
|
||||||
pdata->chip_disable(kim_gdata);
|
pdata->chip_disable(kim_gdata);
|
||||||
|
@ -701,7 +702,7 @@ static const struct file_operations list_debugfs_fops = {
|
||||||
* board-*.c file
|
* board-*.c file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct dentry *kim_debugfs_dir;
|
static struct dentry *kim_debugfs_dir;
|
||||||
static int kim_probe(struct platform_device *pdev)
|
static int kim_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
long status;
|
long status;
|
||||||
|
@ -731,20 +732,6 @@ static int kim_probe(struct platform_device *pdev)
|
||||||
/* refer to itself */
|
/* refer to itself */
|
||||||
kim_gdata->core_data->kim_data = kim_gdata;
|
kim_gdata->core_data->kim_data = kim_gdata;
|
||||||
|
|
||||||
/* Claim the chip enable nShutdown gpio from the system */
|
|
||||||
kim_gdata->nshutdown = pdata->nshutdown_gpio;
|
|
||||||
status = gpio_request(kim_gdata->nshutdown, "kim");
|
|
||||||
if (unlikely(status)) {
|
|
||||||
pr_err(" gpio %ld request failed ", kim_gdata->nshutdown);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Configure nShutdown GPIO as output=0 */
|
|
||||||
status = gpio_direction_output(kim_gdata->nshutdown, 0);
|
|
||||||
if (unlikely(status)) {
|
|
||||||
pr_err(" unable to configure gpio %ld", kim_gdata->nshutdown);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
/* get reference of pdev for request_firmware
|
/* get reference of pdev for request_firmware
|
||||||
*/
|
*/
|
||||||
kim_gdata->kim_pdev = pdev;
|
kim_gdata->kim_pdev = pdev;
|
||||||
|
@ -780,18 +767,10 @@ static int kim_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
static int kim_remove(struct platform_device *pdev)
|
static int kim_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
/* free the GPIOs requested */
|
|
||||||
struct ti_st_plat_data *pdata = pdev->dev.platform_data;
|
|
||||||
struct kim_data_s *kim_gdata;
|
struct kim_data_s *kim_gdata;
|
||||||
|
|
||||||
kim_gdata = dev_get_drvdata(&pdev->dev);
|
kim_gdata = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
/* Free the Bluetooth/FM/GPIO
|
|
||||||
* nShutdown gpio from the system
|
|
||||||
*/
|
|
||||||
gpio_free(pdata->nshutdown_gpio);
|
|
||||||
pr_info("nshutdown GPIO Freed");
|
|
||||||
|
|
||||||
debugfs_remove_recursive(kim_debugfs_dir);
|
debugfs_remove_recursive(kim_debugfs_dir);
|
||||||
sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp);
|
sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp);
|
||||||
pr_info("sysfs entries removed");
|
pr_info("sysfs entries removed");
|
||||||
|
@ -804,7 +783,7 @@ static int kim_remove(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kim_suspend(struct platform_device *pdev, pm_message_t state)
|
static int kim_suspend(struct platform_device *pdev, pm_message_t state)
|
||||||
{
|
{
|
||||||
struct ti_st_plat_data *pdata = pdev->dev.platform_data;
|
struct ti_st_plat_data *pdata = pdev->dev.platform_data;
|
||||||
|
|
||||||
|
@ -814,7 +793,7 @@ int kim_suspend(struct platform_device *pdev, pm_message_t state)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kim_resume(struct platform_device *pdev)
|
static int kim_resume(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct ti_st_plat_data *pdata = pdev->dev.platform_data;
|
struct ti_st_plat_data *pdata = pdev->dev.platform_data;
|
||||||
|
|
||||||
|
|
|
@ -434,21 +434,9 @@ static struct pci_driver tifm_7xx1_driver = {
|
||||||
.resume = tifm_7xx1_resume,
|
.resume = tifm_7xx1_resume,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init tifm_7xx1_init(void)
|
module_pci_driver(tifm_7xx1_driver);
|
||||||
{
|
|
||||||
return pci_register_driver(&tifm_7xx1_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit tifm_7xx1_exit(void)
|
|
||||||
{
|
|
||||||
pci_unregister_driver(&tifm_7xx1_driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Alex Dubov");
|
MODULE_AUTHOR("Alex Dubov");
|
||||||
MODULE_DESCRIPTION("TI FlashMedia host driver");
|
MODULE_DESCRIPTION("TI FlashMedia host driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_DEVICE_TABLE(pci, tifm_7xx1_pci_tbl);
|
MODULE_DEVICE_TABLE(pci, tifm_7xx1_pci_tbl);
|
||||||
MODULE_VERSION(DRIVER_VERSION);
|
MODULE_VERSION(DRIVER_VERSION);
|
||||||
|
|
||||||
module_init(tifm_7xx1_init);
|
|
||||||
module_exit(tifm_7xx1_exit);
|
|
||||||
|
|
|
@ -60,7 +60,6 @@ config W1_MASTER_GPIO
|
||||||
|
|
||||||
config HDQ_MASTER_OMAP
|
config HDQ_MASTER_OMAP
|
||||||
tristate "OMAP HDQ driver"
|
tristate "OMAP HDQ driver"
|
||||||
depends on ARCH_OMAP2PLUS
|
|
||||||
help
|
help
|
||||||
Say Y here if you want support for the 1-wire or HDQ Interface
|
Say Y here if you want support for the 1-wire or HDQ Interface
|
||||||
on an OMAP processor.
|
on an OMAP processor.
|
||||||
|
|
|
@ -18,9 +18,6 @@
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
|
|
||||||
#include <asm/irq.h>
|
|
||||||
#include <mach/hardware.h>
|
|
||||||
|
|
||||||
#include "../w1.h"
|
#include "../w1.h"
|
||||||
#include "../w1_int.h"
|
#include "../w1_int.h"
|
||||||
|
|
||||||
|
@ -73,11 +70,11 @@ struct hdq_data {
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __devinit omap_hdq_probe(struct platform_device *pdev);
|
static int __devinit omap_hdq_probe(struct platform_device *pdev);
|
||||||
static int omap_hdq_remove(struct platform_device *pdev);
|
static int __devexit omap_hdq_remove(struct platform_device *pdev);
|
||||||
|
|
||||||
static struct platform_driver omap_hdq_driver = {
|
static struct platform_driver omap_hdq_driver = {
|
||||||
.probe = omap_hdq_probe,
|
.probe = omap_hdq_probe,
|
||||||
.remove = omap_hdq_remove,
|
.remove = __devexit_p(omap_hdq_remove),
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "omap_hdq",
|
.name = "omap_hdq",
|
||||||
},
|
},
|
||||||
|
@ -538,39 +535,35 @@ static void omap_w1_write_byte(void *_hdq, u8 byte)
|
||||||
hdq_data->init_trans = 0;
|
hdq_data->init_trans = 0;
|
||||||
mutex_unlock(&hdq_data->hdq_mutex);
|
mutex_unlock(&hdq_data->hdq_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devinit omap_hdq_probe(struct platform_device *pdev)
|
static int __devinit omap_hdq_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
struct hdq_data *hdq_data;
|
struct hdq_data *hdq_data;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int ret, irq;
|
int ret, irq;
|
||||||
u8 rev;
|
u8 rev;
|
||||||
|
|
||||||
hdq_data = kmalloc(sizeof(*hdq_data), GFP_KERNEL);
|
hdq_data = devm_kzalloc(dev, sizeof(*hdq_data), GFP_KERNEL);
|
||||||
if (!hdq_data) {
|
if (!hdq_data) {
|
||||||
dev_dbg(&pdev->dev, "unable to allocate memory\n");
|
dev_dbg(&pdev->dev, "unable to allocate memory\n");
|
||||||
ret = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto err_kmalloc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hdq_data->dev = &pdev->dev;
|
hdq_data->dev = dev;
|
||||||
platform_set_drvdata(pdev, hdq_data);
|
platform_set_drvdata(pdev, hdq_data);
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
dev_dbg(&pdev->dev, "unable to get resource\n");
|
dev_dbg(&pdev->dev, "unable to get resource\n");
|
||||||
ret = -ENXIO;
|
return -ENXIO;
|
||||||
goto err_resource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hdq_data->hdq_base = ioremap(res->start, SZ_4K);
|
hdq_data->hdq_base = devm_request_and_ioremap(dev, res);
|
||||||
if (!hdq_data->hdq_base) {
|
if (!hdq_data->hdq_base) {
|
||||||
dev_dbg(&pdev->dev, "ioremap failed\n");
|
dev_dbg(&pdev->dev, "ioremap failed\n");
|
||||||
ret = -EINVAL;
|
return -ENOMEM;
|
||||||
goto err_ioremap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hdq_data->hdq_usecount = 0;
|
hdq_data->hdq_usecount = 0;
|
||||||
|
@ -591,7 +584,8 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev)
|
||||||
goto err_irq;
|
goto err_irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = request_irq(irq, hdq_isr, IRQF_DISABLED, "omap_hdq", hdq_data);
|
ret = devm_request_irq(dev, irq, hdq_isr, IRQF_DISABLED,
|
||||||
|
"omap_hdq", hdq_data);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_dbg(&pdev->dev, "could not request irq\n");
|
dev_dbg(&pdev->dev, "could not request irq\n");
|
||||||
goto err_irq;
|
goto err_irq;
|
||||||
|
@ -616,19 +610,10 @@ err_irq:
|
||||||
err_w1:
|
err_w1:
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
iounmap(hdq_data->hdq_base);
|
|
||||||
|
|
||||||
err_ioremap:
|
|
||||||
err_resource:
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
kfree(hdq_data);
|
|
||||||
|
|
||||||
err_kmalloc:
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int omap_hdq_remove(struct platform_device *pdev)
|
static int __devexit omap_hdq_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct hdq_data *hdq_data = platform_get_drvdata(pdev);
|
struct hdq_data *hdq_data = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
@ -644,27 +629,11 @@ static int omap_hdq_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
/* remove module dependency */
|
/* remove module dependency */
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
free_irq(INT_24XX_HDQ_IRQ, hdq_data);
|
|
||||||
platform_set_drvdata(pdev, NULL);
|
|
||||||
iounmap(hdq_data->hdq_base);
|
|
||||||
kfree(hdq_data);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init
|
module_platform_driver(omap_hdq_driver);
|
||||||
omap_hdq_init(void)
|
|
||||||
{
|
|
||||||
return platform_driver_register(&omap_hdq_driver);
|
|
||||||
}
|
|
||||||
module_init(omap_hdq_init);
|
|
||||||
|
|
||||||
static void __exit
|
|
||||||
omap_hdq_exit(void)
|
|
||||||
{
|
|
||||||
platform_driver_unregister(&omap_hdq_driver);
|
|
||||||
}
|
|
||||||
module_exit(omap_hdq_exit);
|
|
||||||
|
|
||||||
module_param(w1_id, int, S_IRUSR);
|
module_param(w1_id, int, S_IRUSR);
|
||||||
MODULE_PARM_DESC(w1_id, "1-wire id for the slave detection");
|
MODULE_PARM_DESC(w1_id, "1-wire id for the slave detection");
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/w1-gpio.h>
|
#include <linux/w1-gpio.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/of_gpio.h>
|
||||||
|
|
||||||
#include "../w1.h"
|
#include "../w1.h"
|
||||||
#include "../w1_int.h"
|
#include "../w1_int.h"
|
||||||
|
@ -42,12 +44,55 @@ static u8 w1_gpio_read_bit(void *data)
|
||||||
return gpio_get_value(pdata->pin) ? 1 : 0;
|
return gpio_get_value(pdata->pin) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static struct of_device_id w1_gpio_dt_ids[] = {
|
||||||
|
{ .compatible = "w1-gpio" },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids);
|
||||||
|
|
||||||
|
static int w1_gpio_probe_dt(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
|
||||||
|
struct device_node *np = pdev->dev.of_node;
|
||||||
|
const struct of_device_id *of_id =
|
||||||
|
of_match_device(w1_gpio_dt_ids, &pdev->dev);
|
||||||
|
|
||||||
|
if (!of_id)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||||
|
if (!pdata)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (of_get_property(np, "linux,open-drain", NULL))
|
||||||
|
pdata->is_open_drain = 1;
|
||||||
|
|
||||||
|
pdata->pin = of_get_gpio(np, 0);
|
||||||
|
pdata->ext_pullup_enable_pin = of_get_gpio(np, 1);
|
||||||
|
pdev->dev.platform_data = pdata;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int w1_gpio_probe_dt(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int __init w1_gpio_probe(struct platform_device *pdev)
|
static int __init w1_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct w1_bus_master *master;
|
struct w1_bus_master *master;
|
||||||
struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
|
struct w1_gpio_platform_data *pdata;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
err = w1_gpio_probe_dt(pdev);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
pdata = pdev->dev.platform_data;
|
||||||
|
|
||||||
if (!pdata)
|
if (!pdata)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
|
@ -59,6 +104,13 @@ static int __init w1_gpio_probe(struct platform_device *pdev)
|
||||||
if (err)
|
if (err)
|
||||||
goto free_master;
|
goto free_master;
|
||||||
|
|
||||||
|
if (gpio_is_valid(pdata->ext_pullup_enable_pin)) {
|
||||||
|
err = gpio_request_one(pdata->ext_pullup_enable_pin,
|
||||||
|
GPIOF_INIT_LOW, "w1 pullup");
|
||||||
|
if (err < 0)
|
||||||
|
goto free_gpio;
|
||||||
|
}
|
||||||
|
|
||||||
master->data = pdata;
|
master->data = pdata;
|
||||||
master->read_bit = w1_gpio_read_bit;
|
master->read_bit = w1_gpio_read_bit;
|
||||||
|
|
||||||
|
@ -72,15 +124,21 @@ static int __init w1_gpio_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
err = w1_add_master_device(master);
|
err = w1_add_master_device(master);
|
||||||
if (err)
|
if (err)
|
||||||
goto free_gpio;
|
goto free_gpio_ext_pu;
|
||||||
|
|
||||||
if (pdata->enable_external_pullup)
|
if (pdata->enable_external_pullup)
|
||||||
pdata->enable_external_pullup(1);
|
pdata->enable_external_pullup(1);
|
||||||
|
|
||||||
|
if (gpio_is_valid(pdata->ext_pullup_enable_pin))
|
||||||
|
gpio_set_value(pdata->ext_pullup_enable_pin, 1);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, master);
|
platform_set_drvdata(pdev, master);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
free_gpio_ext_pu:
|
||||||
|
if (gpio_is_valid(pdata->ext_pullup_enable_pin))
|
||||||
|
gpio_free(pdata->ext_pullup_enable_pin);
|
||||||
free_gpio:
|
free_gpio:
|
||||||
gpio_free(pdata->pin);
|
gpio_free(pdata->pin);
|
||||||
free_master:
|
free_master:
|
||||||
|
@ -97,6 +155,9 @@ static int __exit w1_gpio_remove(struct platform_device *pdev)
|
||||||
if (pdata->enable_external_pullup)
|
if (pdata->enable_external_pullup)
|
||||||
pdata->enable_external_pullup(0);
|
pdata->enable_external_pullup(0);
|
||||||
|
|
||||||
|
if (gpio_is_valid(pdata->ext_pullup_enable_pin))
|
||||||
|
gpio_set_value(pdata->ext_pullup_enable_pin, 0);
|
||||||
|
|
||||||
w1_remove_master_device(master);
|
w1_remove_master_device(master);
|
||||||
gpio_free(pdata->pin);
|
gpio_free(pdata->pin);
|
||||||
kfree(master);
|
kfree(master);
|
||||||
|
@ -135,6 +196,7 @@ static struct platform_driver w1_gpio_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "w1-gpio",
|
.name = "w1-gpio",
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
|
.of_match_table = of_match_ptr(w1_gpio_dt_ids),
|
||||||
},
|
},
|
||||||
.remove = __exit_p(w1_gpio_remove),
|
.remove = __exit_p(w1_gpio_remove),
|
||||||
.suspend = w1_gpio_suspend,
|
.suspend = w1_gpio_suspend,
|
||||||
|
|
|
@ -281,9 +281,10 @@ struct kim_data_s {
|
||||||
long st_kim_start(void *);
|
long st_kim_start(void *);
|
||||||
long st_kim_stop(void *);
|
long st_kim_stop(void *);
|
||||||
|
|
||||||
void st_kim_recv(void *, const unsigned char *, long count);
|
|
||||||
void st_kim_complete(void *);
|
void st_kim_complete(void *);
|
||||||
void kim_st_list_protocols(struct st_data_s *, void *);
|
void kim_st_list_protocols(struct st_data_s *, void *);
|
||||||
|
void st_kim_recv(void *, const unsigned char *, long);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BTS headers
|
* BTS headers
|
||||||
|
|
|
@ -19,6 +19,7 @@ struct w1_gpio_platform_data {
|
||||||
unsigned int pin;
|
unsigned int pin;
|
||||||
unsigned int is_open_drain:1;
|
unsigned int is_open_drain:1;
|
||||||
void (*enable_external_pullup)(int enable);
|
void (*enable_external_pullup)(int enable);
|
||||||
|
unsigned int ext_pullup_enable_pin;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _LINUX_W1_GPIO_H */
|
#endif /* _LINUX_W1_GPIO_H */
|
||||||
|
|
Loading…
Reference in New Issue