Commit 3aebd34b authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 2c0c86d5 5dc2db05
Atmel AT25 eeprom
EEPROMs (SPI) compatible with Atmel at25.
Required properties:
- compatible : "atmel,at25".
- reg : chip select number
- 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,addr-mode : addr-mode flags, as defined in include/linux/spi/eeprom.h
- at25,page-size : size of the eeprom page
Examples:
at25@0 {
compatible = "atmel,at25";
reg = <0>
spi-max-frequency = <5000000>;
Additional compatible properties are also allowed.
Example:
at25@0 {
compatible = "atmel,at25", "st,m95256";
reg = <0>
spi-max-frequency = <5000000>;
spi-cpha;
spi-cpol;
at25,byte-len = <0x8000>;
at25,addr-mode = <2>;
at25,page-size = <64>;
};
pagesize = <64>;
size = <32768>;
address-width = <16>;
};
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>;
};
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:
* STMicroelectronics LIS3LV02DL, LIS3LV02DQ (12 bits precision)
* STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits)
* STMicroelectronics LIS302DL, LIS3L02DQ, LIS331DL (8 bits) and
LIS331DLH (16 bits)
Authors:
Yan Burman <burman.yan@gmail.com>
......
......@@ -418,8 +418,8 @@ config APPLICOM
If unsure, say N.
config SONYPI
tristate "Sony Vaio Programmable I/O Control Device support (EXPERIMENTAL)"
depends on EXPERIMENTAL && X86 && PCI && INPUT && !64BIT
tristate "Sony Vaio Programmable I/O Control Device support"
depends on X86 && PCI && INPUT && !64BIT
---help---
This driver enables access to the Sony Programmable I/O Control
Device which can be found in many (all ?) Sony Vaio laptops.
......@@ -566,7 +566,7 @@ source "drivers/char/tpm/Kconfig"
config TELCLOCK
tristate "Telecom clock driver for ATCA SBC"
depends on EXPERIMENTAL && X86
depends on X86
default n
help
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 */
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",
MMTIMER_NAME);
goto out3;
......@@ -848,7 +848,6 @@ static int __init mmtimer_init(void)
return 0;
out3:
kfree(timers);
misc_deregister(&mmtimer_miscdev);
out2:
free_irq(SGI_MMTIMER_VECTOR, NULL);
......
......@@ -93,9 +93,9 @@ int button_del_callback (void (*callback) (void))
button_callback_list [lp].count = 0;
callback_count--;
return 0;
};
}
lp--;
};
}
return -EINVAL;
}
......
......@@ -891,6 +891,14 @@ static void rx_ready_async(MGSLPC_INFO *info, int tcd, struct tty_struct *tty)
int work = 0;
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) {
/* early termination, get FIFO count from RBCL register */
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
#endif
{
if (tty->stopped || tty->hw_stopped) {
if (tty && (tty->stopped || tty->hw_stopped)) {
tx_stop(info);
return;
}
......@@ -1000,7 +1008,7 @@ static void tx_ready(MGSLPC_INFO *info, struct tty_struct *tty)
if (!info->tx_active)
return;
} else {
if (tty->stopped || tty->hw_stopped) {
if (tty && (tty->stopped || tty->hw_stopped)) {
tx_stop(info);
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->event_wait_q);
if (info->port.flags & ASYNC_CTS_FLOW) {
if (tty && (info->port.flags & ASYNC_CTS_FLOW)) {
if (tty->hw_stopped) {
if (info->serial_signals & SerialSignal_CTS) {
if (debug_level >= DEBUG_LEVEL_ISR)
printk("CTS tx start...");
if (tty)
tty->hw_stopped = 0;
tty->hw_stopped = 0;
tx_start(info, tty);
info->pending_bh |= BH_TRANSMIT;
return;
......@@ -1065,8 +1072,7 @@ static void cts_change(MGSLPC_INFO *info, struct tty_struct *tty)
if (!(info->serial_signals & SerialSignal_CTS)) {
if (debug_level >= DEBUG_LEVEL_ISR)
printk("CTS tx stop...");
if (tty)
tty->hw_stopped = 1;
tty->hw_stopped = 1;
tx_stop(info);
}
}
......
......@@ -783,7 +783,8 @@ static int __init ppdev_init (void)
err = PTR_ERR(ppdev_class);
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");
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_SET:
return -EINVAL;
};
}
}
#endif
......
......@@ -784,8 +784,10 @@ static int __init tlclk_init(void)
}
tlclk_major = ret;
alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL);
if (!alarm_events)
if (!alarm_events) {
ret = -ENOMEM;
goto out1;
}
/* Read telecom clock IRQ number (Set by BIOS) */
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.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)
......
......@@ -105,7 +105,7 @@ config ATMEL_TCB_CLKSRC_BLOCK
config IBM_ASM
tristate "Device driver for IBM RSA service processor"
depends on X86 && PCI && INPUT && EXPERIMENTAL
depends on X86 && PCI && INPUT
---help---
This option enables device driver support for in-band access to the
IBM RSA (Condor) service processor in eServer xSeries systems.
......@@ -162,8 +162,8 @@ config SGI_IOC4
Otherwise say N.
config TIFM_CORE
tristate "TI Flash Media interface support (EXPERIMENTAL)"
depends on EXPERIMENTAL && PCI
tristate "TI Flash Media interface support"
depends on PCI
help
If you want support for Texas Instruments(R) Flash Media adapters
you should select this option and then also choose an appropriate
......@@ -178,8 +178,8 @@ config TIFM_CORE
be called tifm_core.
config TIFM_7XX1
tristate "TI Flash Media PCI74xx/PCI76xx host adapter support (EXPERIMENTAL)"
depends on PCI && TIFM_CORE && EXPERIMENTAL
tristate "TI Flash Media PCI74xx/PCI76xx host adapter support"
depends on PCI && TIFM_CORE
default TIFM_CORE
help
This option enables support for Texas Instruments(R) PCI74xx and
......@@ -192,7 +192,7 @@ config TIFM_7XX1
config ICS932S401
tristate "Integrated Circuits ICS932S401"
depends on I2C && EXPERIMENTAL
depends on I2C
help
If you say yes here you get support for the Integrated Circuits
ICS932S401 clock control chips.
......@@ -398,7 +398,7 @@ config EP93XX_PWM
config DS1682
tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
depends on I2C && EXPERIMENTAL
depends on I2C
help
If you say yes here you get support for Dallas Semiconductor
DS1682 Total Elapsed Time Recorder.
......
......@@ -57,12 +57,6 @@ static int bmp085_i2c_remove(struct i2c_client *client)
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[] = {
{ BMP085_NAME, 0 },
{ "bmp180", 0 },
......@@ -74,7 +68,6 @@ static struct i2c_driver bmp085_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = BMP085_NAME,
.of_match_table = bmp085_of_match
},
.id_table = bmp085_id,
.probe = bmp085_i2c_probe,
......
......@@ -73,19 +73,8 @@ static struct spi_driver bmp085_spi_driver = {
.remove = __devexit_p(bmp085_spi_remove)
};
static int __init bmp085_spi_init(void)
{
return spi_register_driver(&bmp085_spi_driver);
}
static void __exit bmp085_spi_exit(void)
{
spi_unregister_driver(&bmp085_spi_driver);
}
module_spi_driver(bmp085_spi_driver);
MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
MODULE_DESCRIPTION("BMP085 SPI bus driver");
MODULE_LICENSE("GPL");
module_init(bmp085_spi_init);
module_exit(bmp085_spi_exit);
......@@ -3,8 +3,7 @@
#
menuconfig C2PORT
tristate "Silicon Labs C2 port support (EXPERIMENTAL)"
depends on EXPERIMENTAL
tristate "Silicon Labs C2 port support"
default n
help
This option enables support for Silicon Labs C2 port used to
......@@ -22,7 +21,7 @@ menuconfig C2PORT
if C2PORT
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
default n
help
......
......@@ -978,7 +978,6 @@ static int fpga_of_probe(struct platform_device *op)
dev_set_drvdata(priv->dev, priv);
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
dma_cap_set(DMA_INTERRUPT, mask);
dma_cap_set(DMA_SLAVE, 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;
tx = chan->device->device_prep_dma_memcpy(chan, dst, src,
REG_BLOCK_SIZE,
DMA_PREP_INTERRUPT);
0);
if (!tx) {
dev_err(priv->dev, "unable to prep SYS-FPGA DMA\n");
return -ENOMEM;
......
......@@ -50,7 +50,7 @@ config EEPROM_LEGACY
config EEPROM_MAX6875
tristate "Maxim MAX6874/5 power supply supervisor"
depends on I2C && EXPERIMENTAL
depends on I2C
help
If you say yes here you get read-only support for the user EEPROM of
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)
{
struct at25_data *at25 = NULL;
......@@ -314,33 +369,11 @@ static int at25_probe(struct spi_device *spi)
/* Chip description */
if (!spi->dev.platform_data) {
if (np) {
u32 val;
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;
}
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");
err = at25_np_to_chip(&spi->dev, np, &chip);
if (err)
goto fail;
}
chip.page_size = (u16)val;
} else {
dev_dbg(&spi->dev, "no chip description\n");
dev_err(&spi->dev, "Error: no chip description\n");
err = -ENODEV;
goto fail;
}
......
......@@ -736,7 +736,14 @@ static void ilo_remove(struct pci_dev *pdev)
free_irq(pdev->irq, ilo_hw);
ilo_unmap_device(pdev, ilo_hw);
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);
ilo_hwdev[(minor / max_ccb)] = 0;
}
......@@ -826,7 +833,7 @@ static int __devinit ilo_probe(struct pci_dev *pdev,
free_regions:
pci_release_regions(pdev);
disable:
pci_disable_device(pdev);
/* pci_disable_device(pdev); see comment in ilo_remove */
free:
kfree(ilo_hw);
out:
......
......@@ -39,6 +39,7 @@
#include <linux/miscdevice.h>
#include <linux/pm_runtime.h>
#include <linux/atomic.h>
#include <linux/of_device.h>
#include "lis3lv02d.h"
#define DRIVER_NAME "lis3lv02d"
......@@ -80,6 +81,15 @@
#define LIS3_SENSITIVITY_12B ((LIS3_ACCURACY * 1000) / 1024)
#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_FLAT_12B 3
#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);
}
/* 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
* @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_8_rates[2] = {100, 400};
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 */
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));
}
if (lis3->whoami == WAI_3DC) {
if ((lis3->whoami == WAI_3DC) || (lis3->whoami == WAI_3DLH)) {
ctlreg = CTRL_REG4;
selftest = CTRL4_ST0;
} else {
......@@ -398,9 +422,17 @@ int lis3lv02d_poweron(struct lis3lv02d *lis3)
lis3->read(lis3, CTRL_REG2, &reg);
if (lis3->whoami == WAI_12B)
reg |= CTRL2_BDU | CTRL2_BOOT;
else if (lis3->whoami == WAI_3DLH)
reg |= CTRL2_BOOT_3DLH;
else
reg |= CTRL2_BOOT_8B;
lis3->write(lis3, CTRL_REG2, reg);
if (lis3->whoami == WAI_3DLH) {
lis3->read(lis3, CTRL_REG4, &reg);
reg |= CTRL4_BDU;
lis3->write(lis3, CTRL_REG4, reg);
}
}
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.
* 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->scale = LIS3_SENSITIVITY_8B;
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:
pr_err("unknown sensor type 0x%X\n", lis3->whoami);
return -EINVAL;
......
......@@ -26,12 +26,12 @@
/*
* This driver tries to support the "digital" accelerometer chips from
* STMicroelectronics such as LIS3LV02DL, LIS302DL, LIS3L02DQ, LIS331DL,
* LIS35DE, or LIS202DL. They are very similar in terms of programming, with
* almost the same registers. In addition to differing on physical properties,
* they differ on the number of axes (2/3), precision (8/12 bits), and special
* features (freefall detection, click...). Unfortunately, not all the
* differences can be probed via a register.
* They can be connected either via I²C or SPI.
* LIS331DLH, LIS35DE, or LIS202DL. They are very similar in terms of
* programming, with almost the same registers. In addition to differing
* on physical properties, they differ on the number of axes (2/3),
* precision (8/12 bits), and special features (freefall detection,
* click...). Unfortunately, not all the differences can be probed via
* a register. They can be connected either via I²C or SPI.
*/
#include <linux/lis3lv02d.h>
......@@ -96,12 +96,22 @@ enum lis3lv02d_reg {
};
enum lis3_who_am_i {
WAI_3DLH = 0x32, /* 16 bits: LIS331DLH */
WAI_3DC = 0x33, /* 8 bits: LIS3DC, HP3DC */
WAI_12B = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */
WAI_8B = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */
WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */
};
enum lis3_type {
LIS3LV02D,
LIS3DC,
HP3DC,
LIS2302D,
LIS331DLF,
LIS331DLH,
};
enum lis3lv02d_ctrl1_12b {
CTRL1_Xen = 0x01,
CTRL1_Yen = 0x02,
......@@ -129,6 +139,27 @@ enum lis3lv02d_ctrl1_3dc {
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 {
CTRL2_DAS = 0x01,
CTRL2_SIM = 0x02,
......@@ -279,9 +310,14 @@ struct lis3lv02d {
int data_ready_count[2];
atomic_t wake_thread;
unsigned char irq_cfg;
unsigned int shift_adj;
struct lis3lv02d_platform_data *pdata; /* for passing board config */
struct mutex mutex; /* Serialize poll and selftest */
#ifdef CONFIG_OF
struct device_node *of_node;
#endif
};
int lis3lv02d_init_device(struct lis3lv02d *lis3);
......@@ -290,5 +326,6 @@ void lis3lv02d_joystick_disable(struct lis3lv02d *lis3);
void lis3lv02d_poweroff(struct lis3lv02d *lis3);
int lis3lv02d_poweron(struct lis3lv02d *lis3);
int lis3lv02d_remove_fs(struct lis3lv02d *lis3);
int lis3lv02d_init_dt(struct lis3lv02d *lis3);
extern struct lis3lv02d lis3_dev;
......@@ -31,6 +31,10 @@
#include <linux/i2c.h>
#include <linux/pm_runtime.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include "lis3lv02d.h"
#define DRV_NAME "lis3lv02d_i2c"
......@@ -90,7 +94,11 @@ static int lis3_i2c_init(struct lis3lv02d *lis3)
if (ret < 0)
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);
}
......@@ -98,12 +106,30 @@ static int lis3_i2c_init(struct lis3lv02d *lis3)
static union axis_conversion lis3lv02d_axis_map =
{ .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,
const struct i2c_device_id *id)
{
int ret = 0;
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->driver_features & LIS3_USE_BLOCK_READ) &&
(i2c_check_functionality(client->adapter,
......@@ -231,7 +257,8 @@ static int lis3_i2c_runtime_resume(struct device *dev)
#endif /* CONFIG_PM_RUNTIME */
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,
.owner = THIS_MODULE,
.pm = &lis3_pm_ops,
.of_match_table = of_match_ptr(lis3lv02d_i2c_dt_ids),
},
.probe = lis3lv02d_i2c_probe,
.remove = __devexit_p(lis3lv02d_i2c_remove),
......
......@@ -17,6 +17,9 @@
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
#include <linux/pm.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include "lis3lv02d.h"
......@@ -58,6 +61,14 @@ static int lis3_spi_init(struct lis3lv02d *lis3)
static union axis_conversion lis3lv02d_axis_normal =
{ .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)
{
int ret;
......@@ -75,6 +86,15 @@ static int __devinit lis302dl_spi_probe(struct spi_device *spi)
lis3_dev.irq = spi->irq;
lis3_dev.ac = lis3lv02d_axis_normal;
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);
return lis3lv02d_init_device(&lis3_dev);
......@@ -121,6 +141,7 @@ static struct spi_driver lis302dl_spi_driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.pm = &lis3lv02d_spi_pm,
.of_match_table = of_match_ptr(lis302dl_spi_dt_ids),
},
.probe = lis302dl_spi_probe,
.remove = __devexit_p(lis302dl_spi_remove),
......
config INTEL_MEI
tristate "Intel Management Engine Interface (Intel MEI)"
depends on X86 && PCI && EXPERIMENTAL && WATCHDOG_CORE
depends on X86 && PCI && WATCHDOG_CORE
help
The Intel Management Engine (Intel ME) provides Manageability,
Security and Media services for system containing Intel chipsets.
......
......@@ -40,47 +40,48 @@
/*
* MEI device IDs
*/
#define MEI_DEV_ID_82946GZ 0x2974 /* 82946GZ/GL */
#define MEI_DEV_ID_82G35 0x2984 /* 82G35 Express */
#define MEI_DEV_ID_82Q965 0x2994 /* 82Q963/Q965 */
#define MEI_DEV_ID_82G965 0x29A4 /* 82P965/G965 */
#define MEI_DEV_ID_82GM965 0x2A04 /* Mobile PM965/GM965 */
#define MEI_DEV_ID_82GME965 0x2A14 /* Mobile GME965/GLE960 */
#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_82Q33 0x29D4 /* 82Q33 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_6 0x28B4 /* Bearlake */
#define MEI_DEV_ID_ICH9_7 0x28C4 /* Bearlake */
#define MEI_DEV_ID_ICH9_8 0x28D4 /* Bearlake */
#define MEI_DEV_ID_ICH9_9 0x28E4 /* Bearlake */
#define MEI_DEV_ID_ICH9_10 0x28F4 /* Bearlake */
#define MEI_DEV_ID_ICH9M_1 0x2A44 /* Cantiga */
#define MEI_DEV_ID_ICH9M_2 0x2A54 /* Cantiga */
#define MEI_DEV_ID_ICH9M_3 0x2A64 /* Cantiga */
#define MEI_DEV_ID_ICH9M_4 0x2A74 /* Cantiga */
#define MEI_DEV_ID_ICH10_1 0x2E04 /* Eaglelake */
#define MEI_DEV_ID_ICH10_2 0x2E14 /* Eaglelake */
#define MEI_DEV_ID_ICH10_3 0x2E24 /* Eaglelake */
#define MEI_DEV_ID_ICH10_4 0x2E34 /* Eaglelake */
#define MEI_DEV_ID_IBXPK_1 0x3B64 /* Calpella */
#define MEI_DEV_ID_IBXPK_2 0x3B65 /* Calpella */
#define MEI_DEV_ID_CPT_1 0x1C3A /* Cougerpoint */
#define MEI_DEV_ID_PBG_1 0x1D3A /* PBG */
#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_82946GZ 0x2974 /* 82946GZ/GL */
#define MEI_DEV_ID_82G35 0x2984 /* 82G35 Express */
#define MEI_DEV_ID_82Q965 0x2994 /* 82Q963/Q965 */
#define MEI_DEV_ID_82G965 0x29A4 /* 82P965/G965 */
#define MEI_DEV_ID_82GM965 0x2A04 /* Mobile PM965/GM965 */
#define MEI_DEV_ID_82GME965 0x2A14 /* Mobile GME965/GLE960 */
#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_82Q33 0x29D4 /* 82Q33 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_6 0x28B4 /* Bearlake */
#define MEI_DEV_ID_ICH9_7 0x28C4 /* Bearlake */
#define MEI_DEV_ID_ICH9_8 0x28D4 /* Bearlake */
#define MEI_DEV_ID_ICH9_9 0x28E4 /* Bearlake */
#define MEI_DEV_ID_ICH9_10 0x28F4 /* Bearlake */
#define MEI_DEV_ID_ICH9M_1 0x2A44 /* Cantiga */
#define MEI_DEV_ID_ICH9M_2 0x2A54 /* Cantiga */
#define MEI_DEV_ID_ICH9M_3 0x2A64 /* Cantiga */
#define MEI_DEV_ID_ICH9M_4 0x2A74 /* Cantiga */
#define MEI_DEV_ID_ICH10_1 0x2E04 /* Eaglelake */
#define MEI_DEV_ID_ICH10_2 0x2E14 /* Eaglelake */
#define MEI_DEV_ID_ICH10_3 0x2E24 /* Eaglelake */
#define MEI_DEV_ID_ICH10_4 0x2E34 /* Eaglelake */
#define MEI_DEV_ID_IBXPK_1 0x3B64 /* Calpella */
#define MEI_DEV_ID_IBXPK_2 0x3B65 /* Calpella */
#define MEI_DEV_ID_CPT_1 0x1C3A /* Couger Point */
#define MEI_DEV_ID_PBG_1 0x1D3A /* C600/X79 Patsburg */
#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
*/
......
......@@ -24,6 +24,25 @@
#include "interface.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,
0xa8, 0x46, 0xe0, 0xff, 0x65,
0x81, 0x4c);
......@@ -123,7 +142,7 @@ struct mei_device *mei_device_init(struct pci_dev *pdev)
mutex_init(&dev->device_lock);
init_waitqueue_head(&dev->wait_recvd_msg);
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->wd_interface_reg = false;
......@@ -182,7 +201,7 @@ int mei_hw_init(struct mei_device *dev)
}
if (err <= 0 && !dev->recvd_msg) {
dev->mei_state = MEI_DISABLED;
dev->dev_state = MEI_DEV_DISABLED;
dev_dbg(&dev->pdev->dev,
"wait_event_interruptible_timeout failed"
"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) &&
((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,
"host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
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;
bool unexpected;
if (dev->mei_state == MEI_RECOVERING_FROM_RESET) {
if (dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
dev->need_reset = true;
return;
}
unexpected = (dev->mei_state != MEI_INITIALIZING &&
dev->mei_state != MEI_DISABLED &&
dev->mei_state != MEI_POWER_DOWN &&
dev->mei_state != MEI_POWER_UP);
unexpected = (dev->dev_state != MEI_DEV_INITIALIZING &&
dev->dev_state != MEI_DEV_DISABLED &&
dev->dev_state != MEI_DEV_POWER_DOWN &&
dev->dev_state != MEI_DEV_POWER_UP);
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;
if (dev->mei_state != MEI_INITIALIZING) {
if (dev->mei_state != MEI_DISABLED &&
dev->mei_state != MEI_POWER_DOWN)
dev->mei_state = MEI_RESETING;
if (dev->dev_state != MEI_DEV_INITIALIZING) {
if (dev->dev_state != MEI_DEV_DISABLED &&
dev->dev_state != MEI_DEV_POWER_DOWN)
dev->dev_state = MEI_DEV_RESETING;
list_for_each_entry_safe(cl_pos,
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->rd_msg_hdr = 0;
dev->stop = false;
dev->wd_pending = false;
/* 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);
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 */
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,
mei_hdr->length)) {
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);
}
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;
if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req,
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");
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);
if (!clients) {
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);
return ;
}
......@@ -490,7 +509,7 @@ int mei_host_client_properties(struct mei_device *dev)
if (mei_write_message(dev, mei_header,
(unsigned char *)host_cli_req,
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");
mei_reset(dev, 1);
return -EIO;
......@@ -522,12 +541,12 @@ void mei_cl_init(struct mei_cl *priv, struct mei_device *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)
if (uuid_le_cmp(cuuid,
if (uuid_le_cmp(*cuuid,
dev->me_clients[i].props.protocol_name) == 0) {
res = i;
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
* @dev: the device structure
* @priv: private file structure to set client_id in
* @cguid: searched guid of ME client
* @cl: private file structure to set client_id in
* @cuuid: searched uuid of ME client
* @client_id: id of host client to be set in file private structure
*
* returns ME client index
*/
u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv,
const uuid_le *cguid, u8 client_id)
int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl,
const uuid_le *cuuid, u8 host_cl_id)
{
int i;
if (!dev || !priv || !cguid)
return 0;
if (!dev || !cl || !cuuid)
return -EINVAL;
/* check for valid client id */
i = mei_find_me_client_index(dev, *cguid);
i = mei_me_cl_by_uuid(dev, cuuid);
if (i >= 0) {
priv->me_client_id = dev->me_clients[i].client_id;
priv->state = MEI_FILE_CONNECTING;
priv->host_client_id = client_id;
cl->me_client_id = dev->me_clients[i].client_id;
cl->state = MEI_FILE_CONNECTING;
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 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)
{
u8 i;
int i;
unsigned char *msg_buf;
mei_cl_init(&dev->iamthif_cl, dev);
dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
/* 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);
if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) {
if (i < 0) {
dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n");
return;
}
......
......@@ -23,14 +23,6 @@
#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,
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_stop(struct mei_device *dev, bool preserve);
int mei_wd_stop(struct mei_device *dev);
int mei_wd_host_init(struct mei_device *dev);
/*
* 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;
list_del(&cb_pos->cb_list);
dev_dbg(&dev->pdev->dev,
"completed read host client = %d,"
"ME client = %d, "
"data length = %lu\n",
"completed read H cl = %d, ME cl = %d, length = %lu\n",
cl->host_client_id,
cl->me_client_id,
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,
&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) {
dev->version.major_version = HBM_MAJOR_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_timer = 0;
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
= props_res->client_properties;
if (dev->mei_state == MEI_INIT_CLIENTS &&
if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
dev->init_clients_state ==
MEI_CLIENT_PROPERTIES_MESSAGE) {
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
*/
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,
* 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:
enum_res = (struct hbm_host_enum_response *) mei_msg;
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_timer = 0;
dev->me_client_presentation_num = 0;
......@@ -776,7 +769,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
break;
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");
mei_reset(dev, 1);
break;
......@@ -1224,10 +1217,9 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
}
}
if (dev->stop && !dev->wd_pending) {
dev->wd_stopped = true;
if (dev->wd_state == MEI_WD_STOPPING) {
dev->wd_state = MEI_WD_IDLE;
wake_up_interruptible(&dev->wait_stop_wd);
return 0;
}
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;
dev->extra_write_index = 0;
}
if (dev->mei_state == MEI_ENABLED) {
if (dev->dev_state == MEI_DEV_ENABLED) {
if (dev->wd_pending &&
mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
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;
if (dev->wd_timeout)
*slots -= mei_data2slots(MEI_START_WD_DATA_SIZE);
if (dev->wd_state == MEI_WD_RUNNING)
*slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
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 */
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);
if (dev->mei_state != MEI_ENABLED) {
if (dev->mei_state == MEI_INIT_CLIENTS) {
if (dev->dev_state != MEI_DEV_ENABLED) {
if (dev->dev_state == MEI_DEV_INIT_CLIENTS) {
if (dev->init_clients_timer) {
if (--dev->init_clients_timer == 0) {
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 */
if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
dev->mei_state != MEI_RESETING &&
dev->mei_state != MEI_INITIALIZING) {
dev->dev_state != MEI_DEV_RESETING &&
dev->dev_state != MEI_DEV_INITIALIZING) {
dev_dbg(&dev->pdev->dev, "FW not ready.\n");
mei_reset(dev, 1);
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->host_hw_state |= (H_IE | H_IG | H_RDY);
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");
/* link is established
* start sending messages.
......
......@@ -38,7 +38,31 @@
#include <linux/mei.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
......@@ -84,7 +108,7 @@ int mei_ioctl_connect_client(struct file *file,
cb->major_file_operations = MEI_IOCTL;
if (dev->mei_state != MEI_ENABLED) {
if (dev->dev_state != MEI_DEV_ENABLED) {
rets = -ENODEV;
goto end;
}
......@@ -95,7 +119,7 @@ int mei_ioctl_connect_client(struct file *file,
}
/* 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) {
cl->me_client_id = dev->me_clients[i].client_id;
cl->state = MEI_FILE_CONNECTING;
......@@ -273,19 +297,12 @@ int amthi_read(struct mei_device *dev, struct file *file,
return -ETIMEDOUT;
}
for (i = 0; i < dev->me_clients_num; i++) {
if (dev->me_clients[i].client_id ==
dev->iamthif_cl.me_client_id)
break;
}
i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
if (i == dev->me_clients_num) {
if (i < 0) {
dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
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");
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;
if (cb) {
timeout = cb->read_time +
msecs_to_jiffies(IAMTHIF_READ_TIMER);
timeout = cb->read_time + msecs_to_jiffies(IAMTHIF_READ_TIMER);
dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n",
timeout);
......@@ -386,7 +402,7 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
if (cl->state != MEI_FILE_CONNECTED)
return -ENODEV;
if (dev->mei_state != MEI_ENABLED)
if (dev->dev_state != MEI_DEV_ENABLED)
return -ENODEV;
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",
cl->host_client_id, cl->me_client_id);
for (i = 0; i < dev->me_clients_num; i++) {
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) {
i = mei_me_cl_by_id(dev, cl->me_client_id);
if (i < 0) {
rets = -ENODEV;
goto unlock;
}
......
......@@ -41,11 +41,8 @@
#include <linux/mei.h>
#include "interface.h"
static const char mei_driver_name[] = "mei";
/* The device pointer */
/* Currently this driver works as long as there is only a single AMT device. */
struct pci_dev *mei_device;
/* AMT device is a singleton on the platform */
static struct pci_dev *mei_pdev;
/* mei_pci_tbl - PCI Device ID Table */
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_2)},
{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 */
{0, }
......@@ -220,10 +219,10 @@ static int mei_open(struct inode *inode, struct file *file)
int err;
err = -ENODEV;
if (!mei_device)
if (!mei_pdev)
goto out;
dev = pci_get_drvdata(mei_device);
dev = pci_get_drvdata(mei_pdev);
if (!dev)
goto out;
......@@ -234,18 +233,24 @@ static int mei_open(struct inode *inode, struct file *file)
goto out_unlock;
err = -ENODEV;
if (dev->mei_state != MEI_ENABLED) {
dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED mei_state= %d\n",
dev->mei_state);
if (dev->dev_state != MEI_DEV_ENABLED) {
dev_dbg(&dev->pdev->dev, "dev_state != MEI_ENABLED dev_state = %s\n",
mei_dev_state_str(dev->dev_state));
goto out_unlock;
}
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;
}
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;
}
cl->host_client_id = cl_id;
......@@ -386,17 +391,16 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
dev = cl->dev;
mutex_lock(&dev->device_lock);
if (dev->mei_state != MEI_ENABLED) {
if (dev->dev_state != MEI_DEV_ENABLED) {
rets = -ENODEV;
goto out;
}
if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
/* 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) {
struct mei_me_client *me_client = &dev->me_clients[i];
if (cl->me_client_id == me_client->client_id) {
rets = -EBADF;
goto out;
......@@ -541,7 +545,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
mutex_lock(&dev->device_lock);
if (dev->mei_state != MEI_ENABLED) {
if (dev->dev_state != MEI_DEV_ENABLED) {
mutex_unlock(&dev->device_lock);
return -ENODEV;
}
......@@ -616,26 +620,16 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
rets = -ENOMEM;
goto unlock_dev;
}
if (dev->mei_state != MEI_ENABLED) {
if (dev->dev_state != MEI_DEV_ENABLED) {
rets = -ENODEV;
goto unlock_dev;
}
for (i = 0; i < dev->me_clients_num; i++) {
if (dev->me_clients[i].client_id ==
dev->iamthif_cl.me_client_id)
break;
}
if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
if (i < 0) {
rets = -ENODEV;
goto unlock_dev;
}
if (i == dev->me_clients_num ||
(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 ||
if (length > dev->me_clients[i].props.max_msg_length ||
length <= 0) {
rets = -EMSGSIZE;
goto unlock_dev;
......@@ -688,16 +682,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
cl->me_client_id);
goto unlock_dev;
}
for (i = 0; i < dev->me_clients_num; i++) {
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_dev;
}
if (i == dev->me_clients_num) {
i = mei_me_cl_by_id(dev, cl->me_client_id);
if (i < 0) {
rets = -ENODEV;
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);
mutex_lock(&dev->device_lock);
if (dev->mei_state != MEI_ENABLED) {
if (dev->dev_state != MEI_DEV_ENABLED) {
rets = -ENODEV;
goto out;
}
......@@ -869,7 +855,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
mutex_lock(&dev->device_lock);
if (dev->mei_state != MEI_ENABLED)
if (dev->dev_state != MEI_DEV_ENABLED)
goto out;
......@@ -966,7 +952,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
goto end;
}
if (mei_device) {
if (mei_pdev) {
err = -EEXIST;
goto end;
}
......@@ -979,7 +965,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
/* set PCI host mastering */
pci_set_master(pdev);
/* pci request regions for mei driver */
err = pci_request_regions(pdev, mei_driver_name);
err = pci_request_regions(pdev, KBUILD_MODNAME);
if (err) {
dev_err(&pdev->dev, "failed to get pci regions.\n");
goto disable_device;
......@@ -1004,12 +990,12 @@ static int __devinit mei_probe(struct pci_dev *pdev,
err = request_threaded_irq(pdev->irq,
NULL,
mei_interrupt_thread_handler,
IRQF_ONESHOT, mei_driver_name, dev);
IRQF_ONESHOT, KBUILD_MODNAME, dev);
else
err = request_threaded_irq(pdev->irq,
mei_interrupt_quick_handler,
mei_interrupt_thread_handler,
IRQF_SHARED, mei_driver_name, dev);
IRQF_SHARED, KBUILD_MODNAME, dev);
if (err) {
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)
goto release_irq;
mei_device = pdev;
mei_pdev = pdev;
pci_set_drvdata(pdev, dev);
......@@ -1072,7 +1058,7 @@ static void __devexit mei_remove(struct pci_dev *pdev)
{
struct mei_device *dev;
if (mei_device != pdev)
if (mei_pdev != pdev)
return;
dev = pci_get_drvdata(pdev);
......@@ -1081,9 +1067,11 @@ static void __devexit mei_remove(struct pci_dev *pdev)
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) {
dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
......@@ -1136,12 +1124,15 @@ static int mei_pci_suspend(struct device *device)
if (!dev)
return -ENODEV;
mutex_lock(&dev->device_lock);
cancel_delayed_work(&dev->timer_work);
/* Stop watchdog if exists */
err = mei_wd_stop(dev, true);
err = mei_wd_stop(dev);
/* Set new mei state */
if (dev->mei_state == MEI_ENABLED ||
dev->mei_state == MEI_RECOVERING_FROM_RESET) {
dev->mei_state = MEI_POWER_DOWN;
if (dev->dev_state == MEI_DEV_ENABLED ||
dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
dev->dev_state = MEI_DEV_POWER_DOWN;
mei_reset(dev, 0);
}
mutex_unlock(&dev->device_lock);
......@@ -1169,12 +1160,12 @@ static int mei_pci_resume(struct device *device)
err = request_threaded_irq(pdev->irq,
NULL,
mei_interrupt_thread_handler,
IRQF_ONESHOT, mei_driver_name, dev);
IRQF_ONESHOT, KBUILD_MODNAME, dev);
else
err = request_threaded_irq(pdev->irq,
mei_interrupt_quick_handler,
mei_interrupt_thread_handler,
IRQF_SHARED, mei_driver_name, dev);
IRQF_SHARED, KBUILD_MODNAME, dev);
if (err) {
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);
dev->mei_state = MEI_POWER_UP;
dev->dev_state = MEI_DEV_POWER_UP;
mei_reset(dev, 1);
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
*/
static struct pci_driver mei_driver = {
.name = mei_driver_name,
.name = KBUILD_MODNAME,
.id_table = mei_pci_tbl,
.probe = mei_probe,
.remove = __devexit_p(mei_remove),
......
......@@ -25,18 +25,20 @@
/*
* watch dog definition
*/
#define MEI_WATCHDOG_DATA_SIZE 16
#define MEI_START_WD_DATA_SIZE 20
#define MEI_WD_PARAMS_SIZE 4
#define MEI_WD_HDR_SIZE 4
#define MEI_WD_STOP_MSG_SIZE MEI_WD_HDR_SIZE
#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_RD_MSG_BUF_SIZE (128 * sizeof(u32))
/*
* MEI PCI Device object
*/
extern struct pci_dev *mei_device;
/*
* AMTHI Client UUID
......@@ -53,20 +55,22 @@ extern const uuid_le mei_wd_guid;
*/
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
* 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 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 */
enum file_state {
......@@ -78,17 +82,19 @@ enum file_state {
};
/* MEI device states */
enum mei_states {
MEI_INITIALIZING = 0,
MEI_INIT_CLIENTS,
MEI_ENABLED,
MEI_RESETING,
MEI_DISABLED,
MEI_RECOVERING_FROM_RESET,
MEI_POWER_DOWN,
MEI_POWER_UP
enum mei_dev_state {
MEI_DEV_INITIALIZING = 0,
MEI_DEV_INIT_CLIENTS,
MEI_DEV_ENABLED,
MEI_DEV_RESETING,
MEI_DEV_DISABLED,
MEI_DEV_RECOVERING_FROM_RESET,
MEI_DEV_POWER_DOWN,
MEI_DEV_POWER_UP
};
const char *mei_dev_state_str(int state);
/* init clients states*/
enum mei_init_clients_states {
MEI_START_MESSAGE = 0,
......@@ -113,6 +119,12 @@ enum mei_file_transaction_states {
MEI_READ_COMPLETE
};
enum mei_wd_states {
MEI_WD_IDLE,
MEI_WD_RUNNING,
MEI_WD_STOPPING,
};
/* MEI CB */
enum mei_cb_major_types {
MEI_READ = 0,
......@@ -128,7 +140,7 @@ enum mei_cb_major_types {
struct mei_message_data {
u32 size;
unsigned char *data;
} __packed;
};
struct mei_cl_cb {
......@@ -218,10 +230,9 @@ struct mei_device {
/*
* mei device states
*/
enum mei_states mei_state;
enum mei_dev_state dev_state;
enum mei_init_clients_states init_clients_state;
u16 init_clients_timer;
bool stop;
bool need_reset;
u32 extra_write_index;
......@@ -241,12 +252,11 @@ struct mei_device {
bool mei_host_buffer_is_empty;
struct mei_cl wd_cl;
enum mei_wd_states wd_state;
bool wd_interface_reg;
bool wd_pending;
bool wd_stopped;
bool wd_bypass; /* if false, don't refresh watchdog ME client */
u16 wd_timeout; /* seconds ((wd_data[1] << 8) + wd_data[0]) */
unsigned char wd_data[MEI_START_WD_DATA_SIZE];
u16 wd_timeout;
unsigned char wd_data[MEI_WD_START_MSG_SIZE];
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);
u8 mei_find_me_client_update_filext(struct mei_device *dev,
struct mei_cl *priv,
const uuid_le *cguid, u8 client_id);
int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl,
const uuid_le *cguid, u8 host_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
......@@ -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);
int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid);
/*
* 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)
{
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_WD_PARAMS_SIZE, &timeout, sizeof(u16));
memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE);
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 */
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 */
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);
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->reserved = 0;
if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE))
mei_hdr->length = MEI_START_WD_DATA_SIZE;
else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE))
mei_hdr->length = MEI_WD_PARAMS_SIZE;
if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE))
mei_hdr->length = MEI_WD_START_MSG_SIZE;
else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
mei_hdr->length = MEI_WD_STOP_MSG_SIZE;
else
return -EINVAL;
......@@ -128,18 +129,17 @@ int mei_wd_send(struct mei_device *dev)
* -EIO when message send fails
* -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;
u16 wd_timeout = dev->wd_timeout;
cancel_delayed_work(&dev->timer_work);
if (dev->wd_cl.state != MEI_FILE_CONNECTED || !dev->wd_timeout)
if (dev->wd_cl.state != MEI_FILE_CONNECTED ||
dev->wd_state != MEI_WD_RUNNING)
return 0;
dev->wd_timeout = 0;
memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE);
dev->stop = true;
memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_STOP_MSG_SIZE);
dev->wd_state = MEI_WD_STOPPING;
ret = mei_flow_ctrl_creds(dev, &dev->wd_cl);
if (ret < 0)
......@@ -161,13 +161,14 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
} else {
dev->wd_pending = true;
}
dev->wd_stopped = false;
mutex_unlock(&dev->device_lock);
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);
if (dev->wd_stopped) {
if (dev->wd_state == MEI_WD_IDLE) {
dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
ret = 0;
} else {
......@@ -177,9 +178,6 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
"wd: stop failed to complete ret=%d.\n", ret);
}
if (preserve)
dev->wd_timeout = wd_timeout;
out:
return ret;
}
......@@ -196,16 +194,16 @@ static int mei_wd_ops_start(struct watchdog_device *wd_dev)
int err = -ENODEV;
struct mei_device *dev;
dev = pci_get_drvdata(mei_device);
dev = watchdog_get_drvdata(wd_dev);
if (!dev)
return -ENODEV;
mutex_lock(&dev->device_lock);
if (dev->mei_state != MEI_ENABLED) {
if (dev->dev_state != MEI_DEV_ENABLED) {
dev_dbg(&dev->pdev->dev,
"wd: mei_state != MEI_ENABLED mei_state = %d\n",
dev->mei_state);
"wd: dev_state != MEI_DEV_ENABLED dev_state = %s\n",
mei_dev_state_str(dev->dev_state));
goto end_unlock;
}
......@@ -233,13 +231,13 @@ static int mei_wd_ops_start(struct watchdog_device *wd_dev)
static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
{
struct mei_device *dev;
dev = pci_get_drvdata(mei_device);
dev = watchdog_get_drvdata(wd_dev);
if (!dev)
return -ENODEV;
mutex_lock(&dev->device_lock);
mei_wd_stop(dev, false);
mei_wd_stop(dev);
mutex_unlock(&dev->device_lock);
return 0;
......@@ -256,8 +254,8 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
{
int ret = 0;
struct mei_device *dev;
dev = pci_get_drvdata(mei_device);
dev = watchdog_get_drvdata(wd_dev);
if (!dev)
return -ENODEV;
......@@ -269,6 +267,8 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
goto end;
}
dev->wd_state = MEI_WD_RUNNING;
/* Check if we can send the ping to HW*/
if (dev->mei_host_buffer_is_empty &&
mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
......@@ -309,13 +309,13 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout)
{
struct mei_device *dev;
dev = pci_get_drvdata(mei_device);
dev = watchdog_get_drvdata(wd_dev);
if (!dev)
return -ENODEV;
/* 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;
mutex_lock(&dev->device_lock);
......@@ -341,37 +341,42 @@ static const struct watchdog_ops wd_ops = {
};
static const struct watchdog_info wd_info = {
.identity = INTEL_AMT_WATCHDOG_ID,
.options = WDIOF_KEEPALIVEPING | WDIOF_ALARMONLY,
.options = WDIOF_KEEPALIVEPING |
WDIOF_SETTIMEOUT |
WDIOF_ALARMONLY,
};
static struct watchdog_device amt_wd_dev = {
.info = &wd_info,
.ops = &wd_ops,
.timeout = AMT_WD_DEFAULT_TIMEOUT,
.min_timeout = AMT_WD_MIN_TIMEOUT,
.max_timeout = AMT_WD_MAX_TIMEOUT,
.timeout = MEI_WD_DEFAULT_TIMEOUT,
.min_timeout = MEI_WD_MIN_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)) {
dev_err(&dev->pdev->dev,
"wd: unable to register watchdog device.\n");
dev->wd_interface_reg = false;
} else {
dev_dbg(&dev->pdev->dev,
"wd: successfully register watchdog interface.\n");
dev->wd_interface_reg = true;
return;
}
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)
{
if (dev->wd_interface_reg)
watchdog_unregister_device(&amt_wd_dev);
if (!dev->wd_interface_reg)
return;
watchdog_set_drvdata(&amt_wd_dev, NULL);
watchdog_unregister_device(&amt_wd_dev);
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);
if (chip->pch_phub_base_address == 0) {
if (chip->pch_phub_base_address == NULL) {
dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__);
ret = -ENOMEM;
goto err_pci_iomap;
......@@ -893,18 +893,7 @@ static struct pci_driver pch_phub_driver = {
.resume = pch_phub_resume
};
static int __init pch_phub_pci_init(void)
{
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_pci_driver(pch_phub_driver);
MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7223) PHUB");
MODULE_LICENSE("GPL");
......@@ -30,11 +30,13 @@
#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,
* st_kim_recv during registration to receive fw download 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,
......@@ -100,7 +102,7 @@ int st_int_write(struct st_data_s *st_gdata,
* push the skb received to relevant
* 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);
......@@ -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
* 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;
pr_info(" %s ", __func__);
......@@ -379,7 +381,7 @@ void st_int_recv(void *disc_data,
* completely, return that skb which has the pending data.
* 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;
......@@ -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
* 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;
......
......@@ -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
* 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;
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("data6 %x", skb->data[5]);
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
* 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 *ptr;
......@@ -207,16 +224,19 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
return -EIO;
}
if (!wait_for_completion_timeout
(&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
if (!wait_for_completion_interruptible_timeout(
&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
pr_err(" waiting for ver info- timed out ");
return -ETIMEDOUT;
}
INIT_COMPLETION(kim_gdata->kim_rcvd);
/* the positions 12 & 13 in the response buffer provide with the
* chip, major & minor numbers
*/
version =
MAKEWORD(kim_gdata->resp_buffer[13],
kim_gdata->resp_buffer[14]);
MAKEWORD(kim_gdata->resp_buffer[12],
kim_gdata->resp_buffer[13]);
chip = (version & 0x7C00) >> 10;
min_ver = (version & 0x007F);
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;
}
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;
cur_action = *ptr;
......@@ -370,9 +390,9 @@ static long download_firmware(struct kim_data_s *kim_gdata)
break;
case ACTION_WAIT_EVENT: /* wait */
pr_debug("W");
if (!wait_for_completion_timeout
(&kim_gdata->kim_rcvd,
msecs_to_jiffies(CMD_RESP_TIME))) {
if (!wait_for_completion_interruptible_timeout(
&kim_gdata->kim_rcvd,
msecs_to_jiffies(CMD_RESP_TIME))) {
pr_err("response timeout during fw download ");
/* timed out */
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 kim_data_s *kim_gdata = st_gdata->kim_data;
/* copy to local buffer */
if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) {
/* must be the read_ver_cmd */
memcpy(kim_gdata->resp_buffer, data, count);
complete_all(&kim_gdata->kim_rcvd);
return;
} else {
kim_int_recv(kim_gdata, data, count);
/* either completes or times out */
}
/* proceed to gather all data and distinguish read fw version response
* from other fw responses when data gathering is complete
*/
kim_int_recv(kim_gdata, data, count);
return;
}
......@@ -454,11 +468,6 @@ long st_kim_start(void *kim_data)
if (pdata->chip_enable)
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 */
INIT_COMPLETION(kim_gdata->ldisc_installed);
/* send notification to UIM */
......@@ -467,8 +476,8 @@ long st_kim_start(void *kim_data)
sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
NULL, "install");
/* wait for ldisc to be installed */
err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
msecs_to_jiffies(LDISC_TIME));
err = wait_for_completion_interruptible_timeout(
&kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME));
if (!err) {
/* ldisc installation timeout,
* 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.
* The function is responsible to (a) notify UIM about un-installation,
* (b) flush UART if the ldisc was installed.
* (c) reset BT_EN - pull down nshutdown at the end.
* (d) invoke platform's chip disabling routine.
* (c) invoke platform's chip disabling routine.
*/
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");
/* wait for ldisc to be un-installed */
err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
msecs_to_jiffies(LDISC_TIME));
err = wait_for_completion_interruptible_timeout(
&kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME));
if (!err) { /* timeout */
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 */
if (pdata->chip_disable)
pdata->chip_disable(kim_gdata);
......@@ -701,7 +702,7 @@ static const struct file_operations list_debugfs_fops = {
* board-*.c file
*/
struct dentry *kim_debugfs_dir;
static struct dentry *kim_debugfs_dir;
static int kim_probe(struct platform_device *pdev)
{
long status;
......@@ -731,20 +732,6 @@ static int kim_probe(struct platform_device *pdev)
/* refer to itself */
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
*/
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)
{
/* free the GPIOs requested */
struct ti_st_plat_data *pdata = pdev->dev.platform_data;
struct kim_data_s *kim_gdata;
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);
sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp);
pr_info("sysfs entries removed");
......@@ -804,7 +783,7 @@ static int kim_remove(struct platform_device *pdev)
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;
......@@ -814,7 +793,7 @@ int kim_suspend(struct platform_device *pdev, pm_message_t state)
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;
......
......@@ -434,21 +434,9 @@ static struct pci_driver tifm_7xx1_driver = {
.resume = tifm_7xx1_resume,
};
static int __init tifm_7xx1_init(void)
{
return pci_register_driver(&tifm_7xx1_driver);
}
static void __exit tifm_7xx1_exit(void)
{
pci_unregister_driver(&tifm_7xx1_driver);
}
module_pci_driver(tifm_7xx1_driver);
MODULE_AUTHOR("Alex Dubov");
MODULE_DESCRIPTION("TI FlashMedia host driver");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, tifm_7xx1_pci_tbl);
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
tristate "OMAP HDQ driver"
depends on ARCH_OMAP2PLUS
help
Say Y here if you want support for the 1-wire or HDQ Interface
on an OMAP processor.
......
......@@ -18,9 +18,6 @@
#include <linux/sched.h>
#include <linux/pm_runtime.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include "../w1.h"
#include "../w1_int.h"
......@@ -73,11 +70,11 @@ struct hdq_data {
};
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 = {
.probe = omap_hdq_probe,
.remove = omap_hdq_remove,
.remove = __devexit_p(omap_hdq_remove),
.driver = {
.name = "omap_hdq",
},
......@@ -538,39 +535,35 @@ static void omap_w1_write_byte(void *_hdq, u8 byte)
hdq_data->init_trans = 0;
mutex_unlock(&hdq_data->hdq_mutex);
}
return;
}
static int __devinit omap_hdq_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct hdq_data *hdq_data;
struct resource *res;
int ret, irq;
u8 rev;
hdq_data = kmalloc(sizeof(*hdq_data), GFP_KERNEL);
hdq_data = devm_kzalloc(dev, sizeof(*hdq_data), GFP_KERNEL);
if (!hdq_data) {
dev_dbg(&pdev->dev, "unable to allocate memory\n");
ret = -ENOMEM;
goto err_kmalloc;
return -ENOMEM;
}
hdq_data->dev = &pdev->dev;
hdq_data->dev = dev;
platform_set_drvdata(pdev, hdq_data);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_dbg(&pdev->dev, "unable to get resource\n");
ret = -ENXIO;
goto err_resource;
return -ENXIO;
}
hdq_data->hdq_base = ioremap(res->start, SZ_4K);
hdq_data->hdq_base = devm_request_and_ioremap(dev, res);
if (!hdq_data->hdq_base) {
dev_dbg(&pdev->dev, "ioremap failed\n");
ret = -EINVAL;
goto err_ioremap;
return -ENOMEM;
}
hdq_data->hdq_usecount = 0;
......@@ -591,7 +584,8 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev)
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) {
dev_dbg(&pdev->dev, "could not request irq\n");
goto err_irq;
......@@ -616,19 +610,10 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev)
err_w1:
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;
}
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);
......@@ -644,27 +629,11 @@ static int omap_hdq_remove(struct platform_device *pdev)
/* remove module dependency */
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;
}
static int __init
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_platform_driver(omap_hdq_driver);
module_param(w1_id, int, S_IRUSR);
MODULE_PARM_DESC(w1_id, "1-wire id for the slave detection");
......
......@@ -14,6 +14,8 @@
#include <linux/slab.h>
#include <linux/w1-gpio.h>
#include <linux/gpio.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include "../w1.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;
}
#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)
{
struct w1_bus_master *master;
struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
struct w1_gpio_platform_data *pdata;
int err;
err = w1_gpio_probe_dt(pdev);
if (err < 0)
return err;
pdata = pdev->dev.platform_data;
if (!pdata)
return -ENXIO;
......@@ -59,6 +104,13 @@ static int __init w1_gpio_probe(struct platform_device *pdev)
if (err)
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->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);
if (err)
goto free_gpio;
goto free_gpio_ext_pu;
if (pdata->enable_external_pullup)
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);
return 0;
free_gpio_ext_pu:
if (gpio_is_valid(pdata->ext_pullup_enable_pin))
gpio_free(pdata->ext_pullup_enable_pin);
free_gpio:
gpio_free(pdata->pin);
free_master:
......@@ -97,6 +155,9 @@ static int __exit w1_gpio_remove(struct platform_device *pdev)
if (pdata->enable_external_pullup)
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);
gpio_free(pdata->pin);
kfree(master);
......@@ -135,6 +196,7 @@ static struct platform_driver w1_gpio_driver = {
.driver = {
.name = "w1-gpio",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(w1_gpio_dt_ids),
},
.remove = __exit_p(w1_gpio_remove),
.suspend = w1_gpio_suspend,
......
......@@ -281,9 +281,10 @@ struct kim_data_s {
long st_kim_start(void *);
long st_kim_stop(void *);
void st_kim_recv(void *, const unsigned char *, long count);
void st_kim_complete(void *);
void kim_st_list_protocols(struct st_data_s *, void *);
void st_kim_recv(void *, const unsigned char *, long);
/*
* BTS headers
......
......@@ -19,6 +19,7 @@ struct w1_gpio_platform_data {
unsigned int pin;
unsigned int is_open_drain:1;
void (*enable_external_pullup)(int enable);
unsigned int ext_pullup_enable_pin;
};
#endif /* _LINUX_W1_GPIO_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment