Commit 9f67627a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'char-misc-3.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull char/misc driver patches from Greg KH:
 "Here's the big char/misc driver patches for 3.14-rc1.

  Lots of little things, and a new "big" driver, genwqe.  Full details
  are in the shortlog"

* tag 'char-misc-3.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (90 commits)
  mei: limit the number of consecutive resets
  mei: revamp mei reset state machine
  drivers/char: don't use module_init in non-modular ttyprintk.c
  VMCI: fix error handling path when registering guest driver
  extcon: gpio: Add power resume support
  Documentation: HOWTO: Updates on subsystem trees, patchwork, -next (vs. -mm) in ko_KR
  Documentation: HOWTO: update for 2.6.x -> 3.x versioning in ko_KR
  Documentation: HOWTO: update stable address in ko_KR
  Documentation: HOWTO: update LXR web link in ko_KR
  char: nwbutton: open-code interruptible_sleep_on
  mei: fix syntax in comments and debug output
  mei: nfc: mei_nfc_free has to be called under lock
  mei: use hbm idle state to prevent spurious resets
  mei: do not run reset flow from the interrupt thread
  misc: genwqe: fix return value check in genwqe_device_create()
  GenWQE: Fix warnings for sparc
  GenWQE: Fix compile problems for Alpha
  Documentation/misc-devices/mei/mei-amt-version.c: remove unneeded call of mei_deinit()
  GenWQE: Rework return code for flash-update ioctl
  sgi-xp: open-code interruptible_sleep_on_timeout
  ...
parents 82b51734 6adb8efb
What: /sys/kernel/debug/genwqe/genwqe<n>_card/ddcb_info
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: DDCB queue dump used for debugging queueing problems.
What: /sys/kernel/debug/genwqe/genwqe<n>_card/curr_regs
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Dump of the current error registers.
Only available for PF.
What: /sys/kernel/debug/genwqe/genwqe<n>_card/curr_dbg_uid0
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Internal chip state of UID0 (unit id 0).
Only available for PF.
What: /sys/kernel/debug/genwqe/genwqe<n>_card/curr_dbg_uid1
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Internal chip state of UID1.
Only available for PF.
What: /sys/kernel/debug/genwqe/genwqe<n>_card/curr_dbg_uid2
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Internal chip state of UID2.
Only available for PF.
What: /sys/kernel/debug/genwqe/genwqe<n>_card/prev_regs
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Dump of the error registers before the last reset of
the card occured.
Only available for PF.
What: /sys/kernel/debug/genwqe/genwqe<n>_card/prev_dbg_uid0
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Internal chip state of UID0 before card was reset.
Only available for PF.
What: /sys/kernel/debug/genwqe/genwqe<n>_card/prev_dbg_uid1
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Internal chip state of UID1 before card was reset.
Only available for PF.
What: /sys/kernel/debug/genwqe/genwqe<n>_card/prev_dbg_uid2
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Internal chip state of UID2 before card was reset.
Only available for PF.
What: /sys/kernel/debug/genwqe/genwqe<n>_card/info
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Comprehensive summary of bitstream version and software
version. Used bitstream and bitstream clocking information.
What: /sys/kernel/debug/genwqe/genwqe<n>_card/err_inject
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Possibility to inject error cases to ensure that the drivers
error handling code works well.
What: /sys/kernel/debug/genwqe/genwqe<n>_card/vf<0..14>_jobtimeout_msec
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Default VF timeout 250ms. Testing might require 1000ms.
Using 0 will use the cards default value (whatever that is).
The timeout depends on the max number of available cards
in the system and the maximum allowed queue size.
The driver ensures that the settings are done just before
the VFs get enabled. Changing the timeouts in flight is not
possible.
Only available for PF.
What: /sys/kernel/debug/genwqe/genwqe<n>_card/jobtimer
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Dump job timeout register values for PF and VFs.
Only available for PF.
What: /sys/kernel/debug/genwqe/genwqe<n>_card/queue_working_time
Date: Dec 2013
Contact: haver@linux.vnet.ibm.com
Description: Dump queue working time register values for PF and VFs.
Only available for PF.
What: /sys/class/genwqe/genwqe<n>_card/version
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Unique bitstream identification e.g.
'0000000330336283.00000000475a4950'.
What: /sys/class/genwqe/genwqe<n>_card/appid
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Identifies the currently active card application e.g. 'GZIP'
for compression/decompression.
What: /sys/class/genwqe/genwqe<n>_card/type
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Type of the card e.g. 'GenWQE5-A7'.
What: /sys/class/genwqe/genwqe<n>_card/curr_bitstream
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Currently active bitstream. 1 is default, 0 is backup.
What: /sys/class/genwqe/genwqe<n>_card/next_bitstream
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Interface to set the next bitstream to be used.
What: /sys/class/genwqe/genwqe<n>_card/tempsens
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Interface to read the cards temperature sense register.
What: /sys/class/genwqe/genwqe<n>_card/freerunning_timer
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Interface to read the cards free running timer.
Used for performance and utilization measurements.
What: /sys/class/genwqe/genwqe<n>_card/queue_working_time
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Interface to read queue working time.
Used for performance and utilization measurements.
What: /sys/class/genwqe/genwqe<n>_card/state
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: State of the card: "unused", "used", "error".
What: /sys/class/genwqe/genwqe<n>_card/base_clock
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Base clock frequency of the card.
What: /sys/class/genwqe/genwqe<n>_card/device/sriov_numvfs
Date: Oct 2013
Contact: haver@linux.vnet.ibm.com
Description: Enable VFs (1..15):
sudo sh -c 'echo 15 > \
/sys/bus/pci/devices/0000\:1b\:00.0/sriov_numvfs'
Disable VFs:
Write a 0 into the same sysfs entry.
...@@ -112,7 +112,7 @@ required reading: ...@@ -112,7 +112,7 @@ required reading:
Other excellent descriptions of how to create patches properly are: Other excellent descriptions of how to create patches properly are:
"The Perfect Patch" "The Perfect Patch"
http://kerneltrap.org/node/3737 http://www.ozlabs.org/~akpm/stuff/tpp.txt
"Linux kernel patch submission format" "Linux kernel patch submission format"
http://linux.yyz.us/patch-format.html http://linux.yyz.us/patch-format.html
...@@ -579,7 +579,7 @@ all time. It should describe the patch completely, containing: ...@@ -579,7 +579,7 @@ all time. It should describe the patch completely, containing:
For more details on what this should all look like, please see the For more details on what this should all look like, please see the
ChangeLog section of the document: ChangeLog section of the document:
"The Perfect Patch" "The Perfect Patch"
http://userweb.kernel.org/~akpm/stuff/tpp.txt http://www.ozlabs.org/~akpm/stuff/tpp.txt
......
...@@ -20,6 +20,10 @@ TC/TCLIB Timer required properties: ...@@ -20,6 +20,10 @@ TC/TCLIB Timer required properties:
- interrupts: Should contain all interrupts for the TC block - interrupts: Should contain all interrupts for the TC block
Note that you can specify several interrupt cells if the TC Note that you can specify several interrupt cells if the TC
block has one interrupt per channel. block has one interrupt per channel.
- clock-names: tuple listing input clock names.
Required elements: "t0_clk"
Optional elements: "t1_clk", "t2_clk"
- clocks: phandles to input clocks.
Examples: Examples:
...@@ -28,6 +32,8 @@ One interrupt per TC block: ...@@ -28,6 +32,8 @@ One interrupt per TC block:
compatible = "atmel,at91rm9200-tcb"; compatible = "atmel,at91rm9200-tcb";
reg = <0xfff7c000 0x100>; reg = <0xfff7c000 0x100>;
interrupts = <18 4>; interrupts = <18 4>;
clocks = <&tcb0_clk>;
clock-names = "t0_clk";
}; };
One interrupt per TC channel in a TC block: One interrupt per TC channel in a TC block:
...@@ -35,6 +41,8 @@ One interrupt per TC channel in a TC block: ...@@ -35,6 +41,8 @@ One interrupt per TC channel in a TC block:
compatible = "atmel,at91rm9200-tcb"; compatible = "atmel,at91rm9200-tcb";
reg = <0xfffdc000 0x100>; reg = <0xfffdc000 0x100>;
interrupts = <26 4 27 4 28 4>; interrupts = <26 4 27 4 28 4>;
clocks = <&tcb1_clk>;
clock-names = "t0_clk";
}; };
RSTC Reset Controller required properties: RSTC Reset Controller required properties:
......
...@@ -2,7 +2,11 @@ EXTCON FOR PALMAS/TWL CHIPS ...@@ -2,7 +2,11 @@ EXTCON FOR PALMAS/TWL CHIPS
PALMAS USB COMPARATOR PALMAS USB COMPARATOR
Required Properties: Required Properties:
- compatible : Should be "ti,palmas-usb" or "ti,twl6035-usb" - compatible: should contain one of:
* "ti,palmas-usb-vid".
* "ti,twl6035-usb-vid".
* "ti,palmas-usb" (DEPRECATED - use "ti,palmas-usb-vid").
* "ti,twl6035-usb" (DEPRECATED - use "ti,twl6035-usb-vid").
Optional Properties: Optional Properties:
- ti,wakeup : To enable the wakeup comparator in probe - ti,wakeup : To enable the wakeup comparator in probe
......
...@@ -6,6 +6,9 @@ Required properties: ...@@ -6,6 +6,9 @@ Required properties:
- atmel,at91sam9g45-ssc: support dma transfer - atmel,at91sam9g45-ssc: support dma transfer
- reg: Should contain SSC registers location and length - reg: Should contain SSC registers location and length
- interrupts: Should contain SSC interrupt - interrupts: Should contain SSC interrupt
- clock-names: tuple listing input clock names.
Required elements: "pclk"
- clocks: phandles to input clocks.
Required properties for devices compatible with "atmel,at91sam9g45-ssc": Required properties for devices compatible with "atmel,at91sam9g45-ssc":
...@@ -20,6 +23,8 @@ ssc0: ssc@fffbc000 { ...@@ -20,6 +23,8 @@ ssc0: ssc@fffbc000 {
compatible = "atmel,at91rm9200-ssc"; compatible = "atmel,at91rm9200-ssc";
reg = <0xfffbc000 0x4000>; reg = <0xfffbc000 0x4000>;
interrupts = <14 4 5>; interrupts = <14 4 5>;
clocks = <&ssc0_clk>;
clock-names = "pclk";
}; };
- DMA transfer: - DMA transfer:
......
...@@ -8,6 +8,8 @@ Optional properties: ...@@ -8,6 +8,8 @@ Optional properties:
- temp-measurement-period: temperature measurement period (milliseconds) - temp-measurement-period: temperature measurement period (milliseconds)
- default-oversampling: default oversampling value to be used at startup, - default-oversampling: default oversampling value to be used at startup,
value range is 0-3 with rising sensitivity. value range is 0-3 with rising sensitivity.
- interrupt-parent: should be the phandle for the interrupt controller
- interrupts: interrupt mapping for IRQ
Example: Example:
...@@ -17,4 +19,6 @@ pressure@77 { ...@@ -17,4 +19,6 @@ pressure@77 {
chip-id = <10>; chip-id = <10>;
temp-measurement-period = <100>; temp-measurement-period = <100>;
default-oversampling = <2>; default-oversampling = <2>;
interrupt-parent = <&gpio0>;
interrupts = <25 IRQ_TYPE_EDGE_RISING>;
}; };
...@@ -50,7 +50,7 @@ so that they are still compatible with legacy userspace processes. ...@@ -50,7 +50,7 @@ so that they are still compatible with legacy userspace processes.
Extcon's extended features for switch device drivers with Extcon's extended features for switch device drivers with
complex features usually required magic numbers in state complex features usually required magic numbers in state
value of switch_dev. With extcon, such magic numbers that value of switch_dev. With extcon, such magic numbers that
support multiple cables ( support multiple cables are no more required or supported.
1. Define cable names at edev->supported_cable. 1. Define cable names at edev->supported_cable.
2. (Recommended) remove print_state callback. 2. (Recommended) remove print_state callback.
...@@ -114,11 +114,8 @@ exclusive, the two cables cannot be in ATTACHED state simulteneously. ...@@ -114,11 +114,8 @@ exclusive, the two cables cannot be in ATTACHED state simulteneously.
****** ABI Location ****** ABI Location
If "CONFIG_ANDROID" is enabled and "CONFIG_ANDROID_SWITCH" is If "CONFIG_ANDROID" is enabled, /sys/class/switch/* are created
disabled, /sys/class/switch/* are created as symbolic links to as symbolic links to /sys/class/extcon/*.
/sys/class/extcon/*. Because CONFIG_ANDROID_SWITCH creates
/sys/class/switch directory, we disable symboling linking if
CONFIG_ANDROID_SWITCH is enabled.
The two files of switch class, name and state, are provided with The two files of switch class, name and state, are provided with
extcon, too. When the multistate support (STEP 2 of CHAPTER 1.) is extcon, too. When the multistate support (STEP 2 of CHAPTER 1.) is
......
...@@ -149,7 +149,7 @@ linux-api@ver.kernel.org に送ることを勧めます。 ...@@ -149,7 +149,7 @@ linux-api@ver.kernel.org に送ることを勧めます。
この他にパッチを作る方法についてのよくできた記述は- この他にパッチを作る方法についてのよくできた記述は-
"The Perfect Patch" "The Perfect Patch"
http://userweb.kernel.org/~akpm/stuff/tpp.txt http://www.ozlabs.org/~akpm/stuff/tpp.txt
"Linux kernel patch submission format" "Linux kernel patch submission format"
http://linux.yyz.us/patch-format.html http://linux.yyz.us/patch-format.html
...@@ -622,7 +622,7 @@ Linux カーネルコミュニティは、一度に大量のコードの塊を ...@@ -622,7 +622,7 @@ Linux カーネルコミュニティは、一度に大量のコードの塊を
これについて全てがどのようにあるべきかについての詳細は、以下のドキュメ これについて全てがどのようにあるべきかについての詳細は、以下のドキュメ
ントの ChangeLog セクションを見てください- ントの ChangeLog セクションを見てください-
"The Perfect Patch" "The Perfect Patch"
http://userweb.kernel.org/~akpm/stuff/tpp.txt http://www.ozlabs.org/~akpm/stuff/tpp.txt
これらのどれもが、時にはとても困難です。これらの慣例を完璧に実施するに これらのどれもが、時にはとても困難です。これらの慣例を完璧に実施するに
は数年かかるかもしれません。これは継続的な改善のプロセスであり、そのた は数年かかるかもしれません。これは継続的な改善のプロセスであり、そのた
......
This diff is collapsed.
...@@ -115,8 +115,6 @@ static bool mei_init(struct mei *me, const uuid_le *guid, ...@@ -115,8 +115,6 @@ static bool mei_init(struct mei *me, const uuid_le *guid,
struct mei_client *cl; struct mei_client *cl;
struct mei_connect_client_data data; struct mei_connect_client_data data;
mei_deinit(me);
me->verbose = verbose; me->verbose = verbose;
me->fd = open("/dev/mei", O_RDWR); me->fd = open("/dev/mei", O_RDWR);
......
...@@ -112,7 +112,7 @@ Linux内核代码中包含有大量的文档。这些文档对于学习如何与 ...@@ -112,7 +112,7 @@ Linux内核代码中包含有大量的文档。这些文档对于学习如何与
其他关于如何正确地生成补丁的优秀文档包括: 其他关于如何正确地生成补丁的优秀文档包括:
"The Perfect Patch" "The Perfect Patch"
http://userweb.kernel.org/~akpm/stuff/tpp.txt http://www.ozlabs.org/~akpm/stuff/tpp.txt
"Linux kernel patch submission format" "Linux kernel patch submission format"
http://linux.yyz.us/patch-format.html http://linux.yyz.us/patch-format.html
...@@ -515,7 +515,7 @@ Linux内核社区并不喜欢一下接收大段的代码。修改需要被恰当 ...@@ -515,7 +515,7 @@ Linux内核社区并不喜欢一下接收大段的代码。修改需要被恰当
想了解它具体应该看起来像什么,请查阅以下文档中的“ChangeLog”章节: 想了解它具体应该看起来像什么,请查阅以下文档中的“ChangeLog”章节:
“The Perfect Patch” “The Perfect Patch”
http://userweb.kernel.org/~akpm/stuff/tpp.txt http://www.ozlabs.org/~akpm/stuff/tpp.txt
这些事情有时候做起来很难。要在任何方面都做到完美可能需要好几年时间。这是 这些事情有时候做起来很难。要在任何方面都做到完美可能需要好几年时间。这是
......
...@@ -2619,7 +2619,7 @@ S: Maintained ...@@ -2619,7 +2619,7 @@ S: Maintained
F: drivers/platform/x86/dell-laptop.c F: drivers/platform/x86/dell-laptop.c
DELL LAPTOP SMM DRIVER DELL LAPTOP SMM DRIVER
S: Orphan M: Guenter Roeck <linux@roeck-us.net>
F: drivers/char/i8k.c F: drivers/char/i8k.c
F: include/uapi/linux/i8k.h F: include/uapi/linux/i8k.h
...@@ -3335,6 +3335,7 @@ EXTERNAL CONNECTOR SUBSYSTEM (EXTCON) ...@@ -3335,6 +3335,7 @@ EXTERNAL CONNECTOR SUBSYSTEM (EXTCON)
M: MyungJoo Ham <myungjoo.ham@samsung.com> M: MyungJoo Ham <myungjoo.ham@samsung.com>
M: Chanwoo Choi <cw00.choi@samsung.com> M: Chanwoo Choi <cw00.choi@samsung.com>
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/extcon.git
S: Maintained S: Maintained
F: drivers/extcon/ F: drivers/extcon/
F: Documentation/extcon/ F: Documentation/extcon/
......
...@@ -735,7 +735,7 @@ static struct pci_device_id agp_amd64_pci_table[] = { ...@@ -735,7 +735,7 @@ static struct pci_device_id agp_amd64_pci_table[] = {
MODULE_DEVICE_TABLE(pci, agp_amd64_pci_table); MODULE_DEVICE_TABLE(pci, agp_amd64_pci_table);
static DEFINE_PCI_DEVICE_TABLE(agp_amd64_pci_promisc_table) = { static const struct pci_device_id agp_amd64_pci_promisc_table[] = {
{ PCI_DEVICE_CLASS(0, 0) }, { PCI_DEVICE_CLASS(0, 0) },
{ } { }
}; };
......
This diff is collapsed.
...@@ -587,6 +587,8 @@ static int lp_do_ioctl(unsigned int minor, unsigned int cmd, ...@@ -587,6 +587,8 @@ static int lp_do_ioctl(unsigned int minor, unsigned int cmd,
return -ENODEV; return -ENODEV;
switch ( cmd ) { switch ( cmd ) {
case LPTIME: case LPTIME:
if (arg > UINT_MAX / HZ)
return -EINVAL;
LP_TIME(minor) = arg * HZ/100; LP_TIME(minor) = arg * HZ/100;
break; break;
case LPCHAR: case LPCHAR:
......
...@@ -168,7 +168,10 @@ static irqreturn_t button_handler (int irq, void *dev_id) ...@@ -168,7 +168,10 @@ static irqreturn_t button_handler (int irq, void *dev_id)
static int button_read (struct file *filp, char __user *buffer, static int button_read (struct file *filp, char __user *buffer,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
interruptible_sleep_on (&button_wait_queue); DEFINE_WAIT(wait);
prepare_to_wait(&button_wait_queue, &wait, TASK_INTERRUPTIBLE);
schedule();
finish_wait(&button_wait_queue, &wait);
return (copy_to_user (buffer, &button_output_buffer, bcount)) return (copy_to_user (buffer, &button_output_buffer, bcount))
? -EFAULT : bcount; ? -EFAULT : bcount;
} }
......
...@@ -216,4 +216,4 @@ static int __init ttyprintk_init(void) ...@@ -216,4 +216,4 @@ static int __init ttyprintk_init(void)
ttyprintk_driver = NULL; ttyprintk_driver = NULL;
return ret; return ret;
} }
module_init(ttyprintk_init); device_initcall(ttyprintk_init);
...@@ -31,6 +31,16 @@ config EXTCON_ADC_JACK ...@@ -31,6 +31,16 @@ config EXTCON_ADC_JACK
help help
Say Y here to enable extcon device driver based on ADC values. Say Y here to enable extcon device driver based on ADC values.
config EXTCON_MAX14577
tristate "MAX14577 EXTCON Support"
depends on MFD_MAX14577
select IRQ_DOMAIN
select REGMAP_I2C
help
If you say yes here you get support for the MUIC device of
Maxim MAX14577 PMIC. The MAX14577 MUIC is a USB port accessory
detector and switch.
config EXTCON_MAX77693 config EXTCON_MAX77693
tristate "MAX77693 EXTCON Support" tristate "MAX77693 EXTCON Support"
depends on MFD_MAX77693 && INPUT depends on MFD_MAX77693 && INPUT
......
...@@ -7,6 +7,7 @@ obj-$(CONFIG_OF_EXTCON) += of_extcon.o ...@@ -7,6 +7,7 @@ obj-$(CONFIG_OF_EXTCON) += of_extcon.o
obj-$(CONFIG_EXTCON) += extcon-class.o obj-$(CONFIG_EXTCON) += extcon-class.o
obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o
obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
......
...@@ -44,6 +44,15 @@ ...@@ -44,6 +44,15 @@
#define HPDET_DEBOUNCE 500 #define HPDET_DEBOUNCE 500
#define DEFAULT_MICD_TIMEOUT 2000 #define DEFAULT_MICD_TIMEOUT 2000
#define MICD_LVL_1_TO_7 (ARIZONA_MICD_LVL_1 | ARIZONA_MICD_LVL_2 | \
ARIZONA_MICD_LVL_3 | ARIZONA_MICD_LVL_4 | \
ARIZONA_MICD_LVL_5 | ARIZONA_MICD_LVL_6 | \
ARIZONA_MICD_LVL_7)
#define MICD_LVL_0_TO_7 (ARIZONA_MICD_LVL_0 | MICD_LVL_1_TO_7)
#define MICD_LVL_0_TO_8 (MICD_LVL_0_TO_7 | ARIZONA_MICD_LVL_8)
struct arizona_extcon_info { struct arizona_extcon_info {
struct device *dev; struct device *dev;
struct arizona *arizona; struct arizona *arizona;
...@@ -426,26 +435,15 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) ...@@ -426,26 +435,15 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
} }
val &= ARIZONA_HP_LVL_B_MASK; val &= ARIZONA_HP_LVL_B_MASK;
/* Convert to ohms, the value is in 0.5 ohm increments */
val /= 2;
regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1, regmap_read(arizona->regmap, ARIZONA_HEADPHONE_DETECT_1,
&range); &range);
range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK) range = (range & ARIZONA_HP_IMPEDANCE_RANGE_MASK)
>> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT; >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT;
/* Skip up or down a range? */ /* Skip up a range, or report? */
if (range && (val < arizona_hpdet_c_ranges[range].min)) {
range--;
dev_dbg(arizona->dev, "Moving to HPDET range %d-%d\n",
arizona_hpdet_c_ranges[range].min,
arizona_hpdet_c_ranges[range].max);
regmap_update_bits(arizona->regmap,
ARIZONA_HEADPHONE_DETECT_1,
ARIZONA_HP_IMPEDANCE_RANGE_MASK,
range <<
ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
return -EAGAIN;
}
if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 && if (range < ARRAY_SIZE(arizona_hpdet_c_ranges) - 1 &&
(val >= arizona_hpdet_c_ranges[range].max)) { (val >= arizona_hpdet_c_ranges[range].max)) {
range++; range++;
...@@ -459,6 +457,12 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) ...@@ -459,6 +457,12 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
ARIZONA_HP_IMPEDANCE_RANGE_SHIFT); ARIZONA_HP_IMPEDANCE_RANGE_SHIFT);
return -EAGAIN; return -EAGAIN;
} }
if (range && (val < arizona_hpdet_c_ranges[range].min)) {
dev_dbg(arizona->dev, "Reporting range boundary %d\n",
arizona_hpdet_c_ranges[range].min);
val = arizona_hpdet_c_ranges[range].min;
}
} }
dev_dbg(arizona->dev, "HP impedance %d ohms\n", val); dev_dbg(arizona->dev, "HP impedance %d ohms\n", val);
...@@ -594,9 +598,15 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) ...@@ -594,9 +598,15 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
dev_err(arizona->dev, "Failed to report HP/line: %d\n", dev_err(arizona->dev, "Failed to report HP/line: %d\n",
ret); ret);
done:
/* Reset back to starting range */
regmap_update_bits(arizona->regmap,
ARIZONA_HEADPHONE_DETECT_1,
ARIZONA_HP_IMPEDANCE_RANGE_MASK | ARIZONA_HP_POLL,
0);
arizona_extcon_do_magic(info, 0); arizona_extcon_do_magic(info, 0);
done:
if (id_gpio) if (id_gpio)
gpio_set_value_cansleep(id_gpio, 0); gpio_set_value_cansleep(id_gpio, 0);
...@@ -765,7 +775,20 @@ static void arizona_micd_detect(struct work_struct *work) ...@@ -765,7 +775,20 @@ static void arizona_micd_detect(struct work_struct *work)
mutex_lock(&info->lock); mutex_lock(&info->lock);
for (i = 0; i < 10 && !(val & 0x7fc); i++) { /* If the cable was removed while measuring ignore the result */
ret = extcon_get_cable_state_(&info->edev, ARIZONA_CABLE_MECHANICAL);
if (ret < 0) {
dev_err(arizona->dev, "Failed to check cable state: %d\n",
ret);
mutex_unlock(&info->lock);
return;
} else if (!ret) {
dev_dbg(arizona->dev, "Ignoring MICDET for removed cable\n");
mutex_unlock(&info->lock);
return;
}
for (i = 0; i < 10 && !(val & MICD_LVL_0_TO_8); i++) {
ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val);
if (ret != 0) { if (ret != 0) {
dev_err(arizona->dev, dev_err(arizona->dev,
...@@ -784,7 +807,7 @@ static void arizona_micd_detect(struct work_struct *work) ...@@ -784,7 +807,7 @@ static void arizona_micd_detect(struct work_struct *work)
} }
} }
if (i == 10 && !(val & 0x7fc)) { if (i == 10 && !(val & MICD_LVL_0_TO_8)) {
dev_err(arizona->dev, "Failed to get valid MICDET value\n"); dev_err(arizona->dev, "Failed to get valid MICDET value\n");
mutex_unlock(&info->lock); mutex_unlock(&info->lock);
return; return;
...@@ -798,7 +821,7 @@ static void arizona_micd_detect(struct work_struct *work) ...@@ -798,7 +821,7 @@ static void arizona_micd_detect(struct work_struct *work)
} }
/* If we got a high impedence we should have a headset, report it. */ /* If we got a high impedence we should have a headset, report it. */
if (info->detecting && (val & 0x400)) { if (info->detecting && (val & ARIZONA_MICD_LVL_8)) {
arizona_identify_headphone(info); arizona_identify_headphone(info);
ret = extcon_update_state(&info->edev, ret = extcon_update_state(&info->edev,
...@@ -827,7 +850,7 @@ static void arizona_micd_detect(struct work_struct *work) ...@@ -827,7 +850,7 @@ static void arizona_micd_detect(struct work_struct *work)
* plain headphones. If both polarities report a low * plain headphones. If both polarities report a low
* impedence then give up and report headphones. * impedence then give up and report headphones.
*/ */
if (info->detecting && (val & 0x3f8)) { if (info->detecting && (val & MICD_LVL_1_TO_7)) {
if (info->jack_flips >= info->micd_num_modes * 10) { if (info->jack_flips >= info->micd_num_modes * 10) {
dev_dbg(arizona->dev, "Detected HP/line\n"); dev_dbg(arizona->dev, "Detected HP/line\n");
arizona_identify_headphone(info); arizona_identify_headphone(info);
...@@ -851,7 +874,7 @@ static void arizona_micd_detect(struct work_struct *work) ...@@ -851,7 +874,7 @@ static void arizona_micd_detect(struct work_struct *work)
* If we're still detecting and we detect a short then we've * If we're still detecting and we detect a short then we've
* got a headphone. Otherwise it's a button press. * got a headphone. Otherwise it's a button press.
*/ */
if (val & 0x3fc) { if (val & MICD_LVL_0_TO_7) {
if (info->mic) { if (info->mic) {
dev_dbg(arizona->dev, "Mic button detected\n"); dev_dbg(arizona->dev, "Mic button detected\n");
...@@ -1126,6 +1149,16 @@ static int arizona_extcon_probe(struct platform_device *pdev) ...@@ -1126,6 +1149,16 @@ static int arizona_extcon_probe(struct platform_device *pdev)
break; break;
} }
break; break;
case WM5110:
switch (arizona->rev) {
case 0 ... 2:
break;
default:
info->micd_clamp = true;
info->hpdet_ip = 2;
break;
}
break;
default: default:
break; break;
} }
......
...@@ -40,6 +40,7 @@ struct gpio_extcon_data { ...@@ -40,6 +40,7 @@ struct gpio_extcon_data {
int irq; int irq;
struct delayed_work work; struct delayed_work work;
unsigned long debounce_jiffies; unsigned long debounce_jiffies;
bool check_on_resume;
}; };
static void gpio_extcon_work(struct work_struct *work) static void gpio_extcon_work(struct work_struct *work)
...@@ -103,8 +104,15 @@ static int gpio_extcon_probe(struct platform_device *pdev) ...@@ -103,8 +104,15 @@ static int gpio_extcon_probe(struct platform_device *pdev)
extcon_data->gpio_active_low = pdata->gpio_active_low; extcon_data->gpio_active_low = pdata->gpio_active_low;
extcon_data->state_on = pdata->state_on; extcon_data->state_on = pdata->state_on;
extcon_data->state_off = pdata->state_off; extcon_data->state_off = pdata->state_off;
extcon_data->check_on_resume = pdata->check_on_resume;
if (pdata->state_on && pdata->state_off) if (pdata->state_on && pdata->state_off)
extcon_data->edev.print_state = extcon_gpio_print_state; extcon_data->edev.print_state = extcon_gpio_print_state;
ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN,
pdev->name);
if (ret < 0)
return ret;
if (pdata->debounce) { if (pdata->debounce) {
ret = gpio_set_debounce(extcon_data->gpio, ret = gpio_set_debounce(extcon_data->gpio,
pdata->debounce * 1000); pdata->debounce * 1000);
...@@ -117,11 +125,6 @@ static int gpio_extcon_probe(struct platform_device *pdev) ...@@ -117,11 +125,6 @@ static int gpio_extcon_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN,
pdev->name);
if (ret < 0)
goto err;
INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work); INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work);
extcon_data->irq = gpio_to_irq(extcon_data->gpio); extcon_data->irq = gpio_to_irq(extcon_data->gpio);
...@@ -159,12 +162,31 @@ static int gpio_extcon_remove(struct platform_device *pdev) ...@@ -159,12 +162,31 @@ static int gpio_extcon_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP
static int gpio_extcon_resume(struct device *dev)
{
struct gpio_extcon_data *extcon_data;
extcon_data = dev_get_drvdata(dev);
if (extcon_data->check_on_resume)
queue_delayed_work(system_power_efficient_wq,
&extcon_data->work, extcon_data->debounce_jiffies);
return 0;
}
#endif
static const struct dev_pm_ops gpio_extcon_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(NULL, gpio_extcon_resume)
};
static struct platform_driver gpio_extcon_driver = { static struct platform_driver gpio_extcon_driver = {
.probe = gpio_extcon_probe, .probe = gpio_extcon_probe,
.remove = gpio_extcon_remove, .remove = gpio_extcon_remove,
.driver = { .driver = {
.name = "extcon-gpio", .name = "extcon-gpio",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = &gpio_extcon_pm_ops,
}, },
}; };
......
This diff is collapsed.
...@@ -78,20 +78,24 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb) ...@@ -78,20 +78,24 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb) static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
{ {
unsigned int set; unsigned int set, id_src;
struct palmas_usb *palmas_usb = _palmas_usb; struct palmas_usb *palmas_usb = _palmas_usb;
palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE, palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
PALMAS_USB_ID_INT_LATCH_SET, &set); PALMAS_USB_ID_INT_LATCH_SET, &set);
palmas_read(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
PALMAS_USB_ID_INT_SRC, &id_src);
if (set & PALMAS_USB_ID_INT_SRC_ID_GND) { if ((set & PALMAS_USB_ID_INT_SRC_ID_GND) &&
(id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) {
palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
PALMAS_USB_ID_INT_LATCH_CLR, PALMAS_USB_ID_INT_LATCH_CLR,
PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND); PALMAS_USB_ID_INT_EN_HI_CLR_ID_GND);
palmas_usb->linkstat = PALMAS_USB_STATE_ID; palmas_usb->linkstat = PALMAS_USB_STATE_ID;
extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true); extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true);
dev_info(palmas_usb->dev, "USB-HOST cable is attached\n"); dev_info(palmas_usb->dev, "USB-HOST cable is attached\n");
} else if (set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) { } else if ((set & PALMAS_USB_ID_INT_SRC_ID_FLOAT) &&
(id_src & PALMAS_USB_ID_INT_SRC_ID_FLOAT)) {
palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE, palmas_write(palmas_usb->palmas, PALMAS_USB_OTG_BASE,
PALMAS_USB_ID_INT_LATCH_CLR, PALMAS_USB_ID_INT_LATCH_CLR,
PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT); PALMAS_USB_ID_INT_EN_HI_CLR_ID_FLOAT);
...@@ -103,6 +107,11 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb) ...@@ -103,6 +107,11 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT; palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false); extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", false);
dev_info(palmas_usb->dev, "USB-HOST cable is detached\n"); dev_info(palmas_usb->dev, "USB-HOST cable is detached\n");
} else if ((palmas_usb->linkstat == PALMAS_USB_STATE_DISCONNECT) &&
(id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) {
palmas_usb->linkstat = PALMAS_USB_STATE_ID;
extcon_set_cable_state(&palmas_usb->edev, "USB-HOST", true);
dev_info(palmas_usb->dev, " USB-HOST cable is attached\n");
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -269,7 +278,9 @@ static const struct dev_pm_ops palmas_pm_ops = { ...@@ -269,7 +278,9 @@ static const struct dev_pm_ops palmas_pm_ops = {
static struct of_device_id of_palmas_match_tbl[] = { static struct of_device_id of_palmas_match_tbl[] = {
{ .compatible = "ti,palmas-usb", }, { .compatible = "ti,palmas-usb", },
{ .compatible = "ti,palmas-usb-vid", },
{ .compatible = "ti,twl6035-usb", }, { .compatible = "ti,twl6035-usb", },
{ .compatible = "ti,twl6035-usb-vid", },
{ /* end */ } { /* end */ }
}; };
......
...@@ -301,7 +301,7 @@ int hv_synic_alloc(void) ...@@ -301,7 +301,7 @@ int hv_synic_alloc(void)
return -ENOMEM; return -ENOMEM;
} }
void hv_synic_free_cpu(int cpu) static void hv_synic_free_cpu(int cpu)
{ {
kfree(hv_context.event_dpc[cpu]); kfree(hv_context.event_dpc[cpu]);
if (hv_context.synic_event_page[cpu]) if (hv_context.synic_event_page[cpu])
......
...@@ -525,4 +525,5 @@ source "drivers/misc/altera-stapl/Kconfig" ...@@ -525,4 +525,5 @@ source "drivers/misc/altera-stapl/Kconfig"
source "drivers/misc/mei/Kconfig" source "drivers/misc/mei/Kconfig"
source "drivers/misc/vmw_vmci/Kconfig" source "drivers/misc/vmw_vmci/Kconfig"
source "drivers/misc/mic/Kconfig" source "drivers/misc/mic/Kconfig"
source "drivers/misc/genwqe/Kconfig"
endmenu endmenu
...@@ -53,3 +53,4 @@ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ ...@@ -53,3 +53,4 @@ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
obj-$(CONFIG_SRAM) += sram.o obj-$(CONFIG_SRAM) += sram.o
obj-y += mic/ obj-y += mic/
obj-$(CONFIG_GENWQE) += genwqe/
...@@ -641,7 +641,7 @@ static const struct attribute_group ad525x_group_commands = { ...@@ -641,7 +641,7 @@ static const struct attribute_group ad525x_group_commands = {
.attrs = ad525x_attributes_commands, .attrs = ad525x_attributes_commands,
}; };
int ad_dpot_add_files(struct device *dev, static int ad_dpot_add_files(struct device *dev,
unsigned features, unsigned rdac) unsigned features, unsigned rdac)
{ {
int err = sysfs_create_file(&dev->kobj, int err = sysfs_create_file(&dev->kobj,
...@@ -666,7 +666,7 @@ int ad_dpot_add_files(struct device *dev, ...@@ -666,7 +666,7 @@ int ad_dpot_add_files(struct device *dev,
return err; return err;
} }
inline void ad_dpot_remove_files(struct device *dev, static inline void ad_dpot_remove_files(struct device *dev,
unsigned features, unsigned rdac) unsigned features, unsigned rdac)
{ {
sysfs_remove_file(&dev->kobj, sysfs_remove_file(&dev->kobj,
......
...@@ -49,7 +49,7 @@ static int bmp085_i2c_probe(struct i2c_client *client, ...@@ -49,7 +49,7 @@ static int bmp085_i2c_probe(struct i2c_client *client,
return err; return err;
} }
return bmp085_probe(&client->dev, regmap); return bmp085_probe(&client->dev, regmap, client->irq);
} }
static int bmp085_i2c_remove(struct i2c_client *client) static int bmp085_i2c_remove(struct i2c_client *client)
......
...@@ -41,7 +41,7 @@ static int bmp085_spi_probe(struct spi_device *client) ...@@ -41,7 +41,7 @@ static int bmp085_spi_probe(struct spi_device *client)
return err; return err;
} }
return bmp085_probe(&client->dev, regmap); return bmp085_probe(&client->dev, regmap, client->irq);
} }
static int bmp085_spi_remove(struct spi_device *client) static int bmp085_spi_remove(struct spi_device *client)
......
...@@ -49,9 +49,11 @@ ...@@ -49,9 +49,11 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h>
#include <linux/of.h> #include <linux/of.h>
#include "bmp085.h" #include "bmp085.h"
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/gpio.h>
#define BMP085_CHIP_ID 0x55 #define BMP085_CHIP_ID 0x55
#define BMP085_CALIBRATION_DATA_START 0xAA #define BMP085_CALIBRATION_DATA_START 0xAA
...@@ -84,8 +86,19 @@ struct bmp085_data { ...@@ -84,8 +86,19 @@ struct bmp085_data {
unsigned long last_temp_measurement; unsigned long last_temp_measurement;
u8 chip_id; u8 chip_id;
s32 b6; /* calculated temperature correction coefficient */ s32 b6; /* calculated temperature correction coefficient */
int irq;
struct completion done;
}; };
static irqreturn_t bmp085_eoc_isr(int irq, void *devid)
{
struct bmp085_data *data = devid;
complete(&data->done);
return IRQ_HANDLED;
}
static s32 bmp085_read_calibration_data(struct bmp085_data *data) static s32 bmp085_read_calibration_data(struct bmp085_data *data)
{ {
u16 tmp[BMP085_CALIBRATION_DATA_LENGTH]; u16 tmp[BMP085_CALIBRATION_DATA_LENGTH];
...@@ -116,6 +129,9 @@ static s32 bmp085_update_raw_temperature(struct bmp085_data *data) ...@@ -116,6 +129,9 @@ static s32 bmp085_update_raw_temperature(struct bmp085_data *data)
s32 status; s32 status;
mutex_lock(&data->lock); mutex_lock(&data->lock);
init_completion(&data->done);
status = regmap_write(data->regmap, BMP085_CTRL_REG, status = regmap_write(data->regmap, BMP085_CTRL_REG,
BMP085_TEMP_MEASUREMENT); BMP085_TEMP_MEASUREMENT);
if (status < 0) { if (status < 0) {
...@@ -123,7 +139,8 @@ static s32 bmp085_update_raw_temperature(struct bmp085_data *data) ...@@ -123,7 +139,8 @@ static s32 bmp085_update_raw_temperature(struct bmp085_data *data)
"Error while requesting temperature measurement.\n"); "Error while requesting temperature measurement.\n");
goto exit; goto exit;
} }
msleep(BMP085_TEMP_CONVERSION_TIME); wait_for_completion_timeout(&data->done, 1 + msecs_to_jiffies(
BMP085_TEMP_CONVERSION_TIME));
status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB, status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB,
&tmp, sizeof(tmp)); &tmp, sizeof(tmp));
...@@ -147,6 +164,9 @@ static s32 bmp085_update_raw_pressure(struct bmp085_data *data) ...@@ -147,6 +164,9 @@ static s32 bmp085_update_raw_pressure(struct bmp085_data *data)
s32 status; s32 status;
mutex_lock(&data->lock); mutex_lock(&data->lock);
init_completion(&data->done);
status = regmap_write(data->regmap, BMP085_CTRL_REG, status = regmap_write(data->regmap, BMP085_CTRL_REG,
BMP085_PRESSURE_MEASUREMENT + BMP085_PRESSURE_MEASUREMENT +
(data->oversampling_setting << 6)); (data->oversampling_setting << 6));
...@@ -157,8 +177,8 @@ static s32 bmp085_update_raw_pressure(struct bmp085_data *data) ...@@ -157,8 +177,8 @@ static s32 bmp085_update_raw_pressure(struct bmp085_data *data)
} }
/* wait for the end of conversion */ /* wait for the end of conversion */
msleep(2+(3 << data->oversampling_setting)); wait_for_completion_timeout(&data->done, 1 + msecs_to_jiffies(
2+(3 << data->oversampling_setting)));
/* copy data into a u32 (4 bytes), but skip the first byte. */ /* copy data into a u32 (4 bytes), but skip the first byte. */
status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB, status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB,
((u8 *)&tmp)+1, 3); ((u8 *)&tmp)+1, 3);
...@@ -420,7 +440,7 @@ struct regmap_config bmp085_regmap_config = { ...@@ -420,7 +440,7 @@ struct regmap_config bmp085_regmap_config = {
}; };
EXPORT_SYMBOL_GPL(bmp085_regmap_config); EXPORT_SYMBOL_GPL(bmp085_regmap_config);
int bmp085_probe(struct device *dev, struct regmap *regmap) int bmp085_probe(struct device *dev, struct regmap *regmap, int irq)
{ {
struct bmp085_data *data; struct bmp085_data *data;
int err = 0; int err = 0;
...@@ -434,6 +454,15 @@ int bmp085_probe(struct device *dev, struct regmap *regmap) ...@@ -434,6 +454,15 @@ int bmp085_probe(struct device *dev, struct regmap *regmap)
dev_set_drvdata(dev, data); dev_set_drvdata(dev, data);
data->dev = dev; data->dev = dev;
data->regmap = regmap; data->regmap = regmap;
data->irq = irq;
if (data->irq > 0) {
err = devm_request_irq(dev, data->irq, bmp085_eoc_isr,
IRQF_TRIGGER_RISING, "bmp085",
data);
if (err < 0)
goto exit_free;
}
/* Initialize the BMP085 chip */ /* Initialize the BMP085 chip */
err = bmp085_init_client(data); err = bmp085_init_client(data);
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
extern struct regmap_config bmp085_regmap_config; extern struct regmap_config bmp085_regmap_config;
int bmp085_probe(struct device *dev, struct regmap *regmap); int bmp085_probe(struct device *dev, struct regmap *regmap, int irq);
int bmp085_remove(struct device *dev); int bmp085_remove(struct device *dev);
int bmp085_detect(struct device *dev); int bmp085_detect(struct device *dev);
......
...@@ -378,7 +378,6 @@ static int eeprom_93xx46_remove(struct spi_device *spi) ...@@ -378,7 +378,6 @@ static int eeprom_93xx46_remove(struct spi_device *spi)
device_remove_file(&spi->dev, &dev_attr_erase); device_remove_file(&spi->dev, &dev_attr_erase);
sysfs_remove_bin_file(&spi->dev.kobj, &edev->bin); sysfs_remove_bin_file(&spi->dev.kobj, &edev->bin);
spi_set_drvdata(spi, NULL);
kfree(edev); kfree(edev);
return 0; return 0;
} }
......
#
# IBM Accelerator Family 'GenWQE'
#
menuconfig GENWQE
tristate "GenWQE PCIe Accelerator"
depends on PCI && 64BIT
select CRC_ITU_T
default n
help
Enables PCIe card driver for IBM GenWQE accelerators.
The user-space interface is described in
include/linux/genwqe/genwqe_card.h.
#
# Makefile for GenWQE driver
#
obj-$(CONFIG_GENWQE) := genwqe_card.o
genwqe_card-objs := card_base.o card_dev.o card_ddcb.o card_sysfs.o \
card_debugfs.o card_utils.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#ifndef __CARD_DDCB_H__
#define __CARD_DDCB_H__
/**
* IBM Accelerator Family 'GenWQE'
*
* (C) Copyright IBM Corp. 2013
*
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com>
* Author: Michael Ruettger <michael@ibmra.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/types.h>
#include <asm/byteorder.h>
#include "genwqe_driver.h"
#include "card_base.h"
/**
* struct ddcb - Device Driver Control Block DDCB
* @hsi: Hardware software interlock
* @shi: Software hardware interlock. Hsi and shi are used to interlock
* software and hardware activities. We are using a compare and
* swap operation to ensure that there are no races when
* activating new DDCBs on the queue, or when we need to
* purge a DDCB from a running queue.
* @acfunc: Accelerator function addresses a unit within the chip
* @cmd: Command to work on
* @cmdopts_16: Options for the command
* @asiv: Input data
* @asv: Output data
*
* The DDCB data format is big endian. Multiple consequtive DDBCs form
* a DDCB queue.
*/
#define ASIV_LENGTH 104 /* Old specification without ATS field */
#define ASIV_LENGTH_ATS 96 /* New specification with ATS field */
#define ASV_LENGTH 64
struct ddcb {
union {
__be32 icrc_hsi_shi_32; /* iCRC, Hardware/SW interlock */
struct {
__be16 icrc_16;
u8 hsi;
u8 shi;
};
};
u8 pre; /* Preamble */
u8 xdir; /* Execution Directives */
__be16 seqnum_16; /* Sequence Number */
u8 acfunc; /* Accelerator Function.. */
u8 cmd; /* Command. */
__be16 cmdopts_16; /* Command Options */
u8 sur; /* Status Update Rate */
u8 psp; /* Protection Section Pointer */
__be16 rsvd_0e_16; /* Reserved invariant */
__be64 fwiv_64; /* Firmware Invariant. */
union {
struct {
__be64 ats_64; /* Address Translation Spec */
u8 asiv[ASIV_LENGTH_ATS]; /* New ASIV */
} n;
u8 __asiv[ASIV_LENGTH]; /* obsolete */
};
u8 asv[ASV_LENGTH]; /* Appl Spec Variant */
__be16 rsvd_c0_16; /* Reserved Variant */
__be16 vcrc_16; /* Variant CRC */
__be32 rsvd_32; /* Reserved unprotected */
__be64 deque_ts_64; /* Deque Time Stamp. */
__be16 retc_16; /* Return Code */
__be16 attn_16; /* Attention/Extended Error Codes */
__be32 progress_32; /* Progress indicator. */
__be64 cmplt_ts_64; /* Completion Time Stamp. */
/* The following layout matches the new service layer format */
__be32 ibdc_32; /* Inbound Data Count (* 256) */
__be32 obdc_32; /* Outbound Data Count (* 256) */
__be64 rsvd_SLH_64; /* Reserved for hardware */
union { /* private data for driver */
u8 priv[8];
__be64 priv_64;
};
__be64 disp_ts_64; /* Dispatch TimeStamp */
} __attribute__((__packed__));
/* CRC polynomials for DDCB */
#define CRC16_POLYNOMIAL 0x1021
/*
* SHI: Software to Hardware Interlock
* This 1 byte field is written by software to interlock the
* movement of one queue entry to another with the hardware in the
* chip.
*/
#define DDCB_SHI_INTR 0x04 /* Bit 2 */
#define DDCB_SHI_PURGE 0x02 /* Bit 1 */
#define DDCB_SHI_NEXT 0x01 /* Bit 0 */
/*
* HSI: Hardware to Software interlock
* This 1 byte field is written by hardware to interlock the movement
* of one queue entry to another with the software in the chip.
*/
#define DDCB_HSI_COMPLETED 0x40 /* Bit 6 */
#define DDCB_HSI_FETCHED 0x04 /* Bit 2 */
/*
* Accessing HSI/SHI is done 32-bit wide
* Normally 16-bit access would work too, but on some platforms the
* 16 compare and swap operation is not supported. Therefore
* switching to 32-bit such that those platforms will work too.
*
* iCRC HSI/SHI
*/
#define DDCB_INTR_BE32 cpu_to_be32(0x00000004)
#define DDCB_PURGE_BE32 cpu_to_be32(0x00000002)
#define DDCB_NEXT_BE32 cpu_to_be32(0x00000001)
#define DDCB_COMPLETED_BE32 cpu_to_be32(0x00004000)
#define DDCB_FETCHED_BE32 cpu_to_be32(0x00000400)
/* Definitions of DDCB presets */
#define DDCB_PRESET_PRE 0x80
#define ICRC_LENGTH(n) ((n) + 8 + 8 + 8) /* used ASIV + hdr fields */
#define VCRC_LENGTH(n) ((n)) /* used ASV */
/*
* Genwqe Scatter Gather list
* Each element has up to 8 entries.
* The chaining element is element 0 cause of prefetching needs.
*/
/*
* 0b0110 Chained descriptor. The descriptor is describing the next
* descriptor list.
*/
#define SG_CHAINED (0x6)
/*
* 0b0010 First entry of a descriptor list. Start from a Buffer-Empty
* condition.
*/
#define SG_DATA (0x2)
/*
* 0b0000 Early terminator. This is the last entry on the list
* irregardless of the length indicated.
*/
#define SG_END_LIST (0x0)
/**
* struct sglist - Scatter gather list
* @target_addr: Either a dma addr of memory to work on or a
* dma addr or a subsequent sglist block.
* @len: Length of the data block.
* @flags: See above.
*
* Depending on the command the GenWQE card can use a scatter gather
* list to describe the memory it works on. Always 8 sg_entry's form
* a block.
*/
struct sg_entry {
__be64 target_addr;
__be32 len;
__be32 flags;
};
#endif /* __CARD_DDCB_H__ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#ifndef __GENWQE_DRIVER_H__
#define __GENWQE_DRIVER_H__
/**
* IBM Accelerator Family 'GenWQE'
*
* (C) Copyright IBM Corp. 2013
*
* Author: Frank Haverkamp <haver@linux.vnet.ibm.com>
* Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com>
* Author: Michael Jung <mijung@de.ibm.com>
* Author: Michael Ruettger <michael@ibmra.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License (version 2 only)
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/cdev.h>
#include <linux/list.h>
#include <linux/kthread.h>
#include <linux/scatterlist.h>
#include <linux/iommu.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
#include <asm/byteorder.h>
#include <linux/genwqe/genwqe_card.h>
#define DRV_VERS_STRING "2.0.0"
/*
* Static minor number assignement, until we decide/implement
* something dynamic.
*/
#define GENWQE_MAX_MINOR 128 /* up to 128 possible genwqe devices */
/**
* genwqe_requ_alloc() - Allocate a new DDCB execution request
*
* This data structure contains the user visiable fields of the DDCB
* to be executed.
*
* Return: ptr to genwqe_ddcb_cmd data structure
*/
struct genwqe_ddcb_cmd *ddcb_requ_alloc(void);
/**
* ddcb_requ_free() - Free DDCB execution request.
* @req: ptr to genwqe_ddcb_cmd data structure.
*/
void ddcb_requ_free(struct genwqe_ddcb_cmd *req);
u32 genwqe_crc32(u8 *buff, size_t len, u32 init);
static inline void genwqe_hexdump(struct pci_dev *pci_dev,
const void *buff, unsigned int size)
{
char prefix[32];
scnprintf(prefix, sizeof(prefix), "%s %s: ",
GENWQE_DEVNAME, pci_name(pci_dev));
print_hex_dump_debug(prefix, DUMP_PREFIX_OFFSET, 16, 1, buff,
size, true);
}
#endif /* __GENWQE_DRIVER_H__ */
...@@ -224,7 +224,7 @@ static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd) ...@@ -224,7 +224,7 @@ static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
} }
#ifdef CONFIG_IDE #ifdef CONFIG_IDE
int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file, static int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file,
struct block_device *bdev, unsigned int cmd, struct block_device *bdev, unsigned int cmd,
unsigned long arg) unsigned long arg)
{ {
...@@ -334,9 +334,10 @@ static void execute_location(void *dst) ...@@ -334,9 +334,10 @@ static void execute_location(void *dst)
static void execute_user_location(void *dst) static void execute_user_location(void *dst)
{ {
/* Intentionally crossing kernel/user memory boundary. */
void (*func)(void) = dst; void (*func)(void) = dst;
if (copy_to_user(dst, do_nothing, EXEC_SIZE)) if (copy_to_user((void __user *)dst, do_nothing, EXEC_SIZE))
return; return;
func(); func();
} }
...@@ -408,6 +409,8 @@ static void lkdtm_do_action(enum ctype which) ...@@ -408,6 +409,8 @@ static void lkdtm_do_action(enum ctype which)
case CT_SPINLOCKUP: case CT_SPINLOCKUP:
/* Must be called twice to trigger. */ /* Must be called twice to trigger. */
spin_lock(&lock_me_up); spin_lock(&lock_me_up);
/* Let sparse know we intended to exit holding the lock. */
__release(&lock_me_up);
break; break;
case CT_HUNG_TASK: case CT_HUNG_TASK:
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
......
...@@ -177,7 +177,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file, ...@@ -177,7 +177,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
unsigned long timeout; unsigned long timeout;
int i; int i;
/* Only Posible if we are in timeout */ /* Only possible if we are in timeout */
if (!cl || cl != &dev->iamthif_cl) { if (!cl || cl != &dev->iamthif_cl) {
dev_dbg(&dev->pdev->dev, "bad file ext.\n"); dev_dbg(&dev->pdev->dev, "bad file ext.\n");
return -ETIMEDOUT; return -ETIMEDOUT;
...@@ -249,7 +249,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file, ...@@ -249,7 +249,7 @@ int mei_amthif_read(struct mei_device *dev, struct file *file,
cb->response_buffer.size); cb->response_buffer.size);
dev_dbg(&dev->pdev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx); dev_dbg(&dev->pdev->dev, "amthif cb->buf_idx - %lu\n", cb->buf_idx);
/* length is being turncated to PAGE_SIZE, however, /* length is being truncated to PAGE_SIZE, however,
* the buf_idx may point beyond */ * the buf_idx may point beyond */
length = min_t(size_t, length, (cb->buf_idx - *offset)); length = min_t(size_t, length, (cb->buf_idx - *offset));
...@@ -316,6 +316,7 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) ...@@ -316,6 +316,7 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb)
mei_hdr.host_addr = dev->iamthif_cl.host_client_id; mei_hdr.host_addr = dev->iamthif_cl.host_client_id;
mei_hdr.me_addr = dev->iamthif_cl.me_client_id; mei_hdr.me_addr = dev->iamthif_cl.me_client_id;
mei_hdr.reserved = 0; mei_hdr.reserved = 0;
mei_hdr.internal = 0;
dev->iamthif_msg_buf_index += mei_hdr.length; dev->iamthif_msg_buf_index += mei_hdr.length;
ret = mei_write_message(dev, &mei_hdr, dev->iamthif_msg_buf); ret = mei_write_message(dev, &mei_hdr, dev->iamthif_msg_buf);
if (ret) if (ret)
...@@ -477,6 +478,7 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, ...@@ -477,6 +478,7 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
mei_hdr.host_addr = cl->host_client_id; mei_hdr.host_addr = cl->host_client_id;
mei_hdr.me_addr = cl->me_client_id; mei_hdr.me_addr = cl->me_client_id;
mei_hdr.reserved = 0; mei_hdr.reserved = 0;
mei_hdr.internal = 0;
if (*slots >= msg_slots) { if (*slots >= msg_slots) {
mei_hdr.length = len; mei_hdr.length = len;
......
...@@ -154,7 +154,7 @@ int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) ...@@ -154,7 +154,7 @@ int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length)
return 0; return 0;
} }
/** /**
* mei_io_cb_alloc_resp_buf - allocate respose buffer * mei_io_cb_alloc_resp_buf - allocate response buffer
* *
* @cb: io callback structure * @cb: io callback structure
* @length: size of the buffer * @length: size of the buffer
...@@ -207,7 +207,7 @@ int mei_cl_flush_queues(struct mei_cl *cl) ...@@ -207,7 +207,7 @@ int mei_cl_flush_queues(struct mei_cl *cl)
/** /**
* mei_cl_init - initializes intialize cl. * mei_cl_init - initializes cl.
* *
* @cl: host client to be initialized * @cl: host client to be initialized
* @dev: mei device * @dev: mei device
...@@ -263,10 +263,10 @@ struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl) ...@@ -263,10 +263,10 @@ struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl)
return NULL; return NULL;
} }
/** mei_cl_link: allocte host id in the host map /** mei_cl_link: allocate host id in the host map
* *
* @cl - host client * @cl - host client
* @id - fixed host id or -1 for genereting one * @id - fixed host id or -1 for generic one
* *
* returns 0 on success * returns 0 on success
* -EINVAL on incorrect values * -EINVAL on incorrect values
...@@ -282,19 +282,19 @@ int mei_cl_link(struct mei_cl *cl, int id) ...@@ -282,19 +282,19 @@ int mei_cl_link(struct mei_cl *cl, int id)
dev = cl->dev; dev = cl->dev;
/* If Id is not asigned get one*/ /* If Id is not assigned get one*/
if (id == MEI_HOST_CLIENT_ID_ANY) if (id == MEI_HOST_CLIENT_ID_ANY)
id = find_first_zero_bit(dev->host_clients_map, id = find_first_zero_bit(dev->host_clients_map,
MEI_CLIENTS_MAX); MEI_CLIENTS_MAX);
if (id >= MEI_CLIENTS_MAX) { if (id >= MEI_CLIENTS_MAX) {
dev_err(&dev->pdev->dev, "id exceded %d", MEI_CLIENTS_MAX) ; dev_err(&dev->pdev->dev, "id exceeded %d", MEI_CLIENTS_MAX);
return -EMFILE; return -EMFILE;
} }
open_handle_count = dev->open_handle_count + dev->iamthif_open_count; open_handle_count = dev->open_handle_count + dev->iamthif_open_count;
if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) {
dev_err(&dev->pdev->dev, "open_handle_count exceded %d", dev_err(&dev->pdev->dev, "open_handle_count exceeded %d",
MEI_MAX_OPEN_HANDLE_COUNT); MEI_MAX_OPEN_HANDLE_COUNT);
return -EMFILE; return -EMFILE;
} }
...@@ -344,8 +344,6 @@ int mei_cl_unlink(struct mei_cl *cl) ...@@ -344,8 +344,6 @@ int mei_cl_unlink(struct mei_cl *cl)
cl->state = MEI_FILE_INITIALIZING; cl->state = MEI_FILE_INITIALIZING;
list_del_init(&cl->link);
return 0; return 0;
} }
...@@ -372,13 +370,14 @@ void mei_host_client_init(struct work_struct *work) ...@@ -372,13 +370,14 @@ void mei_host_client_init(struct work_struct *work)
} }
dev->dev_state = MEI_DEV_ENABLED; dev->dev_state = MEI_DEV_ENABLED;
dev->reset_count = 0;
mutex_unlock(&dev->device_lock); mutex_unlock(&dev->device_lock);
} }
/** /**
* mei_cl_disconnect - disconnect host clinet form the me one * mei_cl_disconnect - disconnect host client from the me one
* *
* @cl: host client * @cl: host client
* *
...@@ -457,7 +456,7 @@ int mei_cl_disconnect(struct mei_cl *cl) ...@@ -457,7 +456,7 @@ int mei_cl_disconnect(struct mei_cl *cl)
* *
* @cl: private data of the file object * @cl: private data of the file object
* *
* returns ture if other client is connected, 0 - otherwise. * returns true if other client is connected, false - otherwise.
*/ */
bool mei_cl_is_other_connecting(struct mei_cl *cl) bool mei_cl_is_other_connecting(struct mei_cl *cl)
{ {
...@@ -481,7 +480,7 @@ bool mei_cl_is_other_connecting(struct mei_cl *cl) ...@@ -481,7 +480,7 @@ bool mei_cl_is_other_connecting(struct mei_cl *cl)
} }
/** /**
* mei_cl_connect - connect host clinet to the me one * mei_cl_connect - connect host client to the me one
* *
* @cl: host client * @cl: host client
* *
...@@ -729,6 +728,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, ...@@ -729,6 +728,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
mei_hdr.host_addr = cl->host_client_id; mei_hdr.host_addr = cl->host_client_id;
mei_hdr.me_addr = cl->me_client_id; mei_hdr.me_addr = cl->me_client_id;
mei_hdr.reserved = 0; mei_hdr.reserved = 0;
mei_hdr.internal = cb->internal;
if (*slots >= msg_slots) { if (*slots >= msg_slots) {
mei_hdr.length = len; mei_hdr.length = len;
...@@ -775,7 +775,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, ...@@ -775,7 +775,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb,
* @cl: host client * @cl: host client
* @cl: write callback with filled data * @cl: write callback with filled data
* *
* returns numbe of bytes sent on success, <0 on failure. * returns number of bytes sent on success, <0 on failure.
*/ */
int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
{ {
...@@ -828,6 +828,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) ...@@ -828,6 +828,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
mei_hdr.host_addr = cl->host_client_id; mei_hdr.host_addr = cl->host_client_id;
mei_hdr.me_addr = cl->me_client_id; mei_hdr.me_addr = cl->me_client_id;
mei_hdr.reserved = 0; mei_hdr.reserved = 0;
mei_hdr.internal = cb->internal;
rets = mei_write_message(dev, &mei_hdr, buf->data); rets = mei_write_message(dev, &mei_hdr, buf->data);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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