提交 d8782381 编写于 作者: L Linus Torvalds

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

Pull char/misc driver updates from Greg KH:
 "Here's the big char/misc driver pull request for 4.2-rc1.

  Lots of mei, extcon, coresight, uio, mic, and other driver updates in
  here.  Full details in the shortlog.  All of these have been in
  linux-next for some time with no reported problems"

* tag 'char-misc-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (176 commits)
  mei: me: wait for power gating exit confirmation
  mei: reset flow control on the last client disconnection
  MAINTAINERS: mei: add mei_cl_bus.h to maintained file list
  misc: sram: sort and clean up included headers
  misc: sram: move reserved block logic out of probe function
  misc: sram: add private struct device and virt_base members
  misc: sram: report correct SRAM pool size
  misc: sram: bump error message level on unclean driver unbinding
  misc: sram: fix device node reference leak on error
  misc: sram: fix enabled clock leak on error path
  misc: mic: Fix reported static checker warning
  misc: mic: Fix randconfig build error by including errno.h
  uio: pruss: Drop depends on ARCH_DAVINCI_DA850 from config
  uio: pruss: Add CONFIG_HAS_IOMEM dependence
  uio: pruss: Include <linux/sizes.h>
  extcon: Redefine the unique id of supported external connectors without 'enum extcon' type
  char:xilinx_hwicap:buffer_icap - change 1/0 to true/false for bool type variable in function buffer_icap_set_configuration().
  Drivers: hv: vmbus: Allocate ring buffer memory in NUMA aware fashion
  parport: check exclusive access before register
  w1: use correct lock on error in w1_seq_show()
  ...
What: /sys/bus/w1/devices/.../w1_master_timeout_us
Date: April 2015
Contact: Dmitry Khromov <dk@icelogic.net>
Description: Bus scanning interval, microseconds component.
Some of 1-Wire devices commonly associated with physical access
control systems are attached/generate presence for as short as
100 ms - hence the tens-to-hundreds milliseconds scan intervals
are required.
see Documentation/w1/w1.generic for detailed information.
Users: any user space application which wants to know bus scanning
interval
What: /sys/bus/w1/devices/.../w1_seq
Date: Apr 2015
Contact: Matt Campbell <mattrcampbell@gmail.com>
Description: Support for the DS28EA00 chain sequence function
see Documentation/w1/slaves/w1_therm for detailed information
Users: any user space application which wants to communicate with DS28EA00
What: /sys/bus/coresight/devices/<memory_map>.etm/enable_source
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Enable/disable tracing on this specific trace entiry.
Enabling a source implies the source has been configured
properly and a sink has been identidifed for it. The path
of coresight components linking the source to the sink is
configured and managed automatically by the coresight framework.
What: /sys/bus/coresight/devices/<memory_map>.etm/cpu
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) The CPU this tracing entity is associated with.
What: /sys/bus/coresight/devices/<memory_map>.etm/nr_pe_cmp
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Indicates the number of PE comparator inputs that are
available for tracing.
What: /sys/bus/coresight/devices/<memory_map>.etm/nr_addr_cmp
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Indicates the number of address comparator pairs that are
available for tracing.
What: /sys/bus/coresight/devices/<memory_map>.etm/nr_cntr
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Indicates the number of counters that are available for
tracing.
What: /sys/bus/coresight/devices/<memory_map>.etm/nr_ext_inp
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Indicates how many external inputs are implemented.
What: /sys/bus/coresight/devices/<memory_map>.etm/numcidc
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Indicates the number of Context ID comparators that are
available for tracing.
What: /sys/bus/coresight/devices/<memory_map>.etm/numvmidc
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Indicates the number of VMID comparators that are available
for tracing.
What: /sys/bus/coresight/devices/<memory_map>.etm/nrseqstate
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Indicates the number of sequencer states that are
implemented.
What: /sys/bus/coresight/devices/<memory_map>.etm/nr_resource
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Indicates the number of resource selection pairs that are
available for tracing.
What: /sys/bus/coresight/devices/<memory_map>.etm/nr_ss_cmp
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Indicates the number of single-shot comparator controls that
are available for tracing.
What: /sys/bus/coresight/devices/<memory_map>.etm/reset
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (W) Cancels all configuration on a trace unit and set it back
to its boot configuration.
What: /sys/bus/coresight/devices/<memory_map>.etm/mode
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Controls various modes supported by this ETM, for example
P0 instruction tracing, branch broadcast, cycle counting and
context ID tracing.
What: /sys/bus/coresight/devices/<memory_map>.etm/pe
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Controls which PE to trace.
What: /sys/bus/coresight/devices/<memory_map>.etm/event
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Controls the tracing of arbitrary events from bank 0 to 3.
What: /sys/bus/coresight/devices/<memory_map>.etm/event_instren
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Controls the behavior of the events in bank 0 to 3.
What: /sys/bus/coresight/devices/<memory_map>.etm/event_ts
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Controls the insertion of global timestamps in the trace
streams.
What: /sys/bus/coresight/devices/<memory_map>.etm/syncfreq
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Controls how often trace synchronization requests occur.
What: /sys/bus/coresight/devices/<memory_map>.etm/cyc_threshold
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Sets the threshold value for cycle counting.
What: /sys/bus/coresight/devices/<memory_map>.etm/bb_ctrl
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Controls which regions in the memory map are enabled to
use branch broadcasting.
What: /sys/bus/coresight/devices/<memory_map>.etm/event_vinst
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Controls instruction trace filtering.
What: /sys/bus/coresight/devices/<memory_map>.etm/s_exlevel_vinst
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) In Secure state, each bit controls whether instruction
tracing is enabled for the corresponding exception level.
What: /sys/bus/coresight/devices/<memory_map>.etm/ns_exlevel_vinst
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) In non-secure state, each bit controls whether instruction
tracing is enabled for the corresponding exception level.
What: /sys/bus/coresight/devices/<memory_map>.etm/addr_idx
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Select which address comparator or pair (of comparators) to
work with.
What: /sys/bus/coresight/devices/<memory_map>.etm/addr_instdatatype
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Controls what type of comparison the trace unit performs.
What: /sys/bus/coresight/devices/<memory_map>.etm/addr_single
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Used to setup single address comparator values.
What: /sys/bus/coresight/devices/<memory_map>.etm/addr_range
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Used to setup address range comparator values.
What: /sys/bus/coresight/devices/<memory_map>.etm/seq_idx
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Select which sequensor.
What: /sys/bus/coresight/devices/<memory_map>.etm/seq_state
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Use this to set, or read, the sequencer state.
What: /sys/bus/coresight/devices/<memory_map>.etm/seq_event
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Moves the sequencer state to a specific state.
What: /sys/bus/coresight/devices/<memory_map>.etm/seq_reset_event
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Moves the sequencer to state 0 when a programmed event
occurs.
What: /sys/bus/coresight/devices/<memory_map>.etm/cntr_idx
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Select which counter unit to work with.
What: /sys/bus/coresight/devices/<memory_map>.etm/cntrldvr
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) This sets or returns the reload count value of the
specific counter.
What: /sys/bus/coresight/devices/<memory_map>.etm/cntr_val
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) This sets or returns the current count value of the
specific counter.
What: /sys/bus/coresight/devices/<memory_map>.etm/cntr_ctrl
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Controls the operation of the selected counter.
What: /sys/bus/coresight/devices/<memory_map>.etm/res_idx
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Select which resource selection unit to work with.
What: /sys/bus/coresight/devices/<memory_map>.etm/res_ctrl
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Controls the selection of the resources in the trace unit.
What: /sys/bus/coresight/devices/<memory_map>.etm/ctxid_idx
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Select which context ID comparator to work with.
What: /sys/bus/coresight/devices/<memory_map>.etm/ctxid_val
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Get/Set the context ID comparator value to trigger on.
What: /sys/bus/coresight/devices/<memory_map>.etm/ctxid_masks
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Mask for all 8 context ID comparator value
registers (if implemented).
What: /sys/bus/coresight/devices/<memory_map>.etm/vmid_idx
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Select which virtual machine ID comparator to work with.
What: /sys/bus/coresight/devices/<memory_map>.etm/vmid_val
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Get/Set the virtual machine ID comparator value to
trigger on.
What: /sys/bus/coresight/devices/<memory_map>.etm/vmid_masks
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (RW) Mask for all 8 virtual machine ID comparator value
registers (if implemented).
What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcoslsr
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the OS Lock Status Register (0x304).
The value it taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpdcr
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the Power Down Control Register
(0x310). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpdsr
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the Power Down Status Register
(0x314). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trclsr
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the SW Lock Status Register
(0xFB4). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcauthstatus
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the Authentication Status Register
(0xFB8). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcdevid
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the Device ID Register
(0xFC8). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcdevtype
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the Device Type Register
(0xFCC). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpidr0
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the Peripheral ID0 Register
(0xFE0). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpidr1
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the Peripheral ID1 Register
(0xFE4). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpidr2
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the Peripheral ID2 Register
(0xFE8). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/mgmt/trcpidr3
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Print the content of the Peripheral ID3 Register
(0xFEC). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr0
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Returns the tracing capabilities of the trace unit (0x1E0).
The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr1
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Returns the tracing capabilities of the trace unit (0x1E4).
The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr2
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Returns the maximum size of the data value, data address,
VMID, context ID and instuction address in the trace unit
(0x1E8). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr3
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Returns the value associated with various resources
available to the trace unit. See the Trace Macrocell
architecture specification for more details (0x1E8).
The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr4
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Returns how many resources the trace unit supports (0x1F0).
The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr5
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Returns how many resources the trace unit supports (0x1F4).
The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr8
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Returns the maximum speculation depth of the instruction
trace stream. (0x180). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr9
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Returns the number of P0 right-hand keys that the trace unit
can use (0x184). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr10
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Returns the number of P1 right-hand keys that the trace unit
can use (0x188). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr11
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Returns the number of special P1 right-hand keys that the
trace unit can use (0x18C). The value is taken directly from
the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr12
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Returns the number of conditional P1 right-hand keys that
the trace unit can use (0x190). The value is taken directly
from the HW.
What: /sys/bus/coresight/devices/<memory_map>.etm/trcidr/trcidr13
Date: April 2015
KernelVersion: 4.01
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (R) Returns the number of special conditional P1 right-hand keys
that the trace unit can use (0x194). The value is taken
directly from the HW.
...@@ -4,4 +4,18 @@ KernelVersion: 3.10 ...@@ -4,4 +4,18 @@ KernelVersion: 3.10
Contact: Samuel Ortiz <sameo@linux.intel.com> Contact: Samuel Ortiz <sameo@linux.intel.com>
linux-mei@linux.intel.com linux-mei@linux.intel.com
Description: Stores the same MODALIAS value emitted by uevent Description: Stores the same MODALIAS value emitted by uevent
Format: mei:<mei device name> Format: mei:<mei device name>:<device uuid>:
What: /sys/bus/mei/devices/.../name
Date: May 2015
KernelVersion: 4.2
Contact: Tomas Winkler <tomas.winkler@intel.com>
Description: Stores mei client device name
Format: string
What: /sys/bus/mei/devices/.../uuid
Date: May 2015
KernelVersion: 4.2
Contact: Tomas Winkler <tomas.winkler@intel.com>
Description: Stores mei client device uuid
Format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
...@@ -17,15 +17,19 @@ its hardware characteristcs. ...@@ -17,15 +17,19 @@ its hardware characteristcs.
- "arm,coresight-tmc", "arm,primecell"; - "arm,coresight-tmc", "arm,primecell";
- "arm,coresight-funnel", "arm,primecell"; - "arm,coresight-funnel", "arm,primecell";
- "arm,coresight-etm3x", "arm,primecell"; - "arm,coresight-etm3x", "arm,primecell";
- "qcom,coresight-replicator1x", "arm,primecell";
* reg: physical base address and length of the register * reg: physical base address and length of the register
set(s) of the component. set(s) of the component.
* clocks: the clock associated to this component. * clocks: the clocks associated to this component.
* clock-names: the name of the clock as referenced by the code. * clock-names: the name of the clocks referenced by the code.
Since we are using the AMBA framework, the name should be Since we are using the AMBA framework, the name of the clock
"apb_pclk". providing the interconnect should be "apb_pclk", and some
coresight blocks also have an additional clock "atclk", which
clocks the core of that coresight component. The latter clock
is optional.
* port or ports: The representation of the component's port * port or ports: The representation of the component's port
layout using the generic DT graph presentation found in layout using the generic DT graph presentation found in
......
...@@ -67,6 +67,12 @@ Optional properties: ...@@ -67,6 +67,12 @@ Optional properties:
present, the number of values should be less than or equal to the present, the number of values should be less than or equal to the
number of inputs, unspecified inputs will use the chip default. number of inputs, unspecified inputs will use the chip default.
- wlf,hpdet-channel : Headphone detection channel.
ARIZONA_ACCDET_MODE_HPL or 1 - Headphone detect mode is set to HPDETL
ARIZONA_ACCDET_MODE_HPR or 2 - Headphone detect mode is set to HPDETR
If this node is not mentioned or if the value is unknown, then
headphone detection mode is set to HPDETL.
- DCVDD-supply, MICVDD-supply : Power supplies, only need to be specified if - DCVDD-supply, MICVDD-supply : Power supplies, only need to be specified if
they are being externally supplied. As covered in they are being externally supplied. As covered in
Documentation/devicetree/bindings/regulator/regulator.txt Documentation/devicetree/bindings/regulator/regulator.txt
......
...@@ -24,6 +24,10 @@ a virtual bus called mic bus is created and virtual dma devices are ...@@ -24,6 +24,10 @@ a virtual bus called mic bus is created and virtual dma devices are
created on it by the host/card drivers. On host the channels are private created on it by the host/card drivers. On host the channels are private
and used only by the host driver to transfer data for the virtio devices. and used only by the host driver to transfer data for the virtio devices.
The Symmetric Communication Interface (SCIF (pronounced as skiff)) is a
low level communications API across PCIe currently implemented for MIC.
More details are available at scif_overview.txt.
Here is a block diagram of the various components described above. The Here is a block diagram of the various components described above. The
virtio backends are situated on the host rather than the card given better virtio backends are situated on the host rather than the card given better
single threaded performance for the host compared to MIC, the ability of single threaded performance for the host compared to MIC, the ability of
...@@ -47,18 +51,18 @@ the fact that the virtio block storage backend can only be on the host. ...@@ -47,18 +51,18 @@ the fact that the virtio block storage backend can only be on the host.
| | | Virtio over PCIe IOCTLs | | | | Virtio over PCIe IOCTLs |
| | +--------------------------+ | | +--------------------------+
+-----------+ | | | +-----------+ +-----------+ | | | +-----------+
| MIC DMA | | | | | MIC DMA | | MIC DMA | | +----------+ | +-----------+ | | MIC DMA |
| Driver | | | | | Driver | | Driver | | | SCIF | | | SCIF | | | Driver |
+-----------+ | | | +-----------+ +-----------+ | +----------+ | +-----------+ | +-----------+
| | | | | | | | | | | |
+---------------+ | | | +----------------+ +---------------+ | +-----+-----+ | +-----+-----+ | +---------------+
|MIC virtual Bus| | | | |MIC virtual Bus | |MIC virtual Bus| | |SCIF HW Bus| | |SCIF HW BUS| | |MIC virtual Bus|
+---------------+ | | | +----------------+ +---------------+ | +-----------+ | +-----+-----+ | +---------------+
| | | | | | | | | | | |
| +--------------+ | +---------------+ | | +--------------+ | | | +---------------+ |
| |Intel MIC | | |Intel MIC | | | |Intel MIC | | | | |Intel MIC | |
+---|Card Driver | | |Host Driver | | +---|Card Driver +----+ | | |Host Driver | |
+--------------+ | +---------------+-----+ +--------------+ | +----+---------------+-----+
| | | | | |
+-------------------------------------------------------------+ +-------------------------------------------------------------+
| | | |
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
exec=/usr/sbin/mpssd exec=/usr/sbin/mpssd
sysfs="/sys/class/mic" sysfs="/sys/class/mic"
mic_modules="mic_host mic_x100_dma scif"
start() start()
{ {
...@@ -48,18 +49,15 @@ start() ...@@ -48,18 +49,15 @@ start()
fi fi
echo -e $"Starting MPSS Stack" echo -e $"Starting MPSS Stack"
echo -e $"Loading MIC_X100_DMA & MIC_HOST Modules" echo -e $"Loading MIC drivers:" $mic_modules
for f in "mic_host" "mic_x100_dma" modprobe -a $mic_modules
do RETVAL=$?
modprobe $f if [ $RETVAL -ne 0 ]; then
RETVAL=$? failure
if [ $RETVAL -ne 0 ]; then echo
failure return $RETVAL
echo fi
return $RETVAL
fi
done
# Start the daemon # Start the daemon
echo -n $"Starting MPSSD " echo -n $"Starting MPSSD "
...@@ -170,8 +168,8 @@ unload() ...@@ -170,8 +168,8 @@ unload()
stop stop
sleep 5 sleep 5
echo -n $"Removing MIC_HOST & MIC_X100_DMA Modules: " echo -n $"Removing MIC drivers:" $mic_modules
modprobe -r mic_host mic_x100_dma modprobe -r $mic_modules
RETVAL=$? RETVAL=$?
[ $RETVAL -ne 0 ] && failure || success [ $RETVAL -ne 0 ] && failure || success
echo echo
......
The Symmetric Communication Interface (SCIF (pronounced as skiff)) is a low
level communications API across PCIe currently implemented for MIC. Currently
SCIF provides inter-node communication within a single host platform, where a
node is a MIC Coprocessor or Xeon based host. SCIF abstracts the details of
communicating over the PCIe bus while providing an API that is symmetric
across all the nodes in the PCIe network. An important design objective for SCIF
is to deliver the maximum possible performance given the communication
abilities of the hardware. SCIF has been used to implement an offload compiler
runtime and OFED support for MPI implementations for MIC coprocessors.
==== SCIF API Components ====
The SCIF API has the following parts:
1. Connection establishment using a client server model
2. Byte stream messaging intended for short messages
3. Node enumeration to determine online nodes
4. Poll semantics for detection of incoming connections and messages
5. Memory registration to pin down pages
6. Remote memory mapping for low latency CPU accesses via mmap
7. Remote DMA (RDMA) for high bandwidth DMA transfers
8. Fence APIs for RDMA synchronization
SCIF exposes the notion of a connection which can be used by peer processes on
nodes in a SCIF PCIe "network" to share memory "windows" and to communicate. A
process in a SCIF node initiates a SCIF connection to a peer process on a
different node via a SCIF "endpoint". SCIF endpoints support messaging APIs
which are similar to connection oriented socket APIs. Connected SCIF endpoints
can also register local memory which is followed by data transfer using either
DMA, CPU copies or remote memory mapping via mmap. SCIF supports both user and
kernel mode clients which are functionally equivalent.
==== SCIF Performance for MIC ====
DMA bandwidth comparison between the TCP (over ethernet over PCIe) stack versus
SCIF shows the performance advantages of SCIF for HPC applications and runtimes.
Comparison of TCP and SCIF based BW
Throughput (GB/sec)
8 + PCIe Bandwidth ******
+ TCP ######
7 + ************************************** SCIF %%%%%%
| %%%%%%%%%%%%%%%%%%%
6 + %%%%
| %%
| %%%
5 + %%
| %%
4 + %%
| %%
3 + %%
| %
2 + %%
| %%
| %
1 +
+ ######################################
0 +++---+++--+--+-+--+--+-++-+--+-++-+--+-++-+-
1 10 100 1000 10000 100000
Transfer Size (KBytes)
SCIF allows memory sharing via mmap(..) between processes on different PCIe
nodes and thus provides bare-metal PCIe latency. The round trip SCIF mmap
latency from the host to an x100 MIC for an 8 byte message is 0.44 usecs.
SCIF has a user space library which is a thin IOCTL wrapper providing a user
space API similar to the kernel API in scif.h. The SCIF user space library
is distributed @ https://software.intel.com/en-us/mic-developer
Here is some pseudo code for an example of how two applications on two PCIe
nodes would typically use the SCIF API:
Process A (on node A) Process B (on node B)
/* get online node information */
scif_get_node_ids(..) scif_get_node_ids(..)
scif_open(..) scif_open(..)
scif_bind(..) scif_bind(..)
scif_listen(..)
scif_accept(..) scif_connect(..)
/* SCIF connection established */
/* Send and receive short messages */
scif_send(..)/scif_recv(..) scif_send(..)/scif_recv(..)
/* Register memory */
scif_register(..) scif_register(..)
/* RDMA */
scif_readfrom(..)/scif_writeto(..) scif_readfrom(..)/scif_writeto(..)
/* Fence DMAs */
scif_fence_signal(..) scif_fence_signal(..)
mmap(..) mmap(..)
/* Access remote registered memory */
/* Close the endpoints */
scif_close(..) scif_close(..)
...@@ -11,12 +11,14 @@ Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru> ...@@ -11,12 +11,14 @@ Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Description Description
----------- -----------
w1_therm provides basic temperature conversion for ds18*20 devices. w1_therm provides basic temperature conversion for ds18*20 devices, and the
ds28ea00 device.
supported family codes: supported family codes:
W1_THERM_DS18S20 0x10 W1_THERM_DS18S20 0x10
W1_THERM_DS1822 0x22 W1_THERM_DS1822 0x22
W1_THERM_DS18B20 0x28 W1_THERM_DS18B20 0x28
W1_THERM_DS1825 0x3B W1_THERM_DS1825 0x3B
W1_THERM_DS28EA00 0x42
Support is provided through the sysfs w1_slave file. Each open and Support is provided through the sysfs w1_slave file. Each open and
read sequence will initiate a temperature conversion then provide two read sequence will initiate a temperature conversion then provide two
...@@ -48,3 +50,10 @@ resistor). The DS18b20 temperature sensor specification lists a ...@@ -48,3 +50,10 @@ resistor). The DS18b20 temperature sensor specification lists a
maximum current draw of 1.5mA and that a 5k pullup resistor is not maximum current draw of 1.5mA and that a 5k pullup resistor is not
sufficient. The strong pullup is designed to provide the additional sufficient. The strong pullup is designed to provide the additional
current required. current required.
The DS28EA00 provides an additional two pins for implementing a sequence
detection algorithm. This feature allows you to determine the physical
location of the chip in the 1-wire bus without needing pre-existing
knowledge of the bus ordering. Support is provided through the sysfs
w1_seq file. The file will contain a single line with an integer value
representing the device index in the bus starting at 0.
...@@ -76,21 +76,24 @@ See struct w1_bus_master definition in w1.h for details. ...@@ -76,21 +76,24 @@ See struct w1_bus_master definition in w1.h for details.
w1 master sysfs interface w1 master sysfs interface
------------------------------------------------------------------ ------------------------------------------------------------------
<xx-xxxxxxxxxxxxx> - a directory for a found device. The format is family-serial <xx-xxxxxxxxxxxxx> - A directory for a found device. The format is family-serial
bus - (standard) symlink to the w1 bus bus - (standard) symlink to the w1 bus
driver - (standard) symlink to the w1 driver driver - (standard) symlink to the w1 driver
w1_master_add - Manually register a slave device w1_master_add - (rw) manually register a slave device
w1_master_attempts - the number of times a search was attempted w1_master_attempts - (ro) the number of times a search was attempted
w1_master_max_slave_count w1_master_max_slave_count
- maximum number of slaves to search for at a time - (rw) maximum number of slaves to search for at a time
w1_master_name - the name of the device (w1_bus_masterX) w1_master_name - (ro) the name of the device (w1_bus_masterX)
w1_master_pullup - 5V strong pullup 0 enabled, 1 disabled w1_master_pullup - (rw) 5V strong pullup 0 enabled, 1 disabled
w1_master_remove - Manually remove a slave device w1_master_remove - (rw) manually remove a slave device
w1_master_search - the number of searches left to do, -1=continual (default) w1_master_search - (rw) the number of searches left to do,
-1=continual (default)
w1_master_slave_count w1_master_slave_count
- the number of slaves found - (ro) the number of slaves found
w1_master_slaves - the names of the slaves, one per line w1_master_slaves - (ro) the names of the slaves, one per line
w1_master_timeout - the delay in seconds between searches w1_master_timeout - (ro) the delay in seconds between searches
w1_master_timeout_us
- (ro) the delay in microseconds beetwen searches
If you have a w1 bus that never changes (you don't add or remove devices), If you have a w1 bus that never changes (you don't add or remove devices),
you can set the module parameter search_count to a small positive number you can set the module parameter search_count to a small positive number
...@@ -101,6 +104,11 @@ generally only make sense when searching is disabled, as a search will ...@@ -101,6 +104,11 @@ generally only make sense when searching is disabled, as a search will
redetect manually removed devices that are present and timeout manually redetect manually removed devices that are present and timeout manually
added devices that aren't on the bus. added devices that aren't on the bus.
Bus searches occur at an interval, specified as a summ of timeout and
timeout_us module parameters (either of which may be 0) for as long as
w1_master_search remains greater than 0 or is -1. Each search attempt
decrements w1_master_search by 1 (down to 0) and increments
w1_master_attempts by 1.
w1 slave sysfs interface w1 slave sysfs interface
------------------------------------------------------------------ ------------------------------------------------------------------
......
...@@ -732,7 +732,7 @@ ANDROID DRIVERS ...@@ -732,7 +732,7 @@ ANDROID DRIVERS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
M: Arve Hjønnevåg <arve@android.com> M: Arve Hjønnevåg <arve@android.com>
M: Riley Andrews <riandrews@android.com> M: Riley Andrews <riandrews@android.com>
T: git git://git.kernel.org/pub/scm/linux/kernel/gregkh/staging.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
L: devel@driverdev.osuosl.org L: devel@driverdev.osuosl.org
S: Supported S: Supported
F: drivers/android/ F: drivers/android/
...@@ -3207,9 +3207,9 @@ S: Maintained ...@@ -3207,9 +3207,9 @@ S: Maintained
F: drivers/platform/x86/dell-smo8800.c F: drivers/platform/x86/dell-smo8800.c
DELL LAPTOP SMM DRIVER DELL LAPTOP SMM DRIVER
M: Guenter Roeck <linux@roeck-us.net> M: Pali Rohár <pali.rohar@gmail.com>
S: Maintained S: Maintained
F: drivers/char/i8k.c F: drivers/hwmon/dell-smm-hwmon.c
F: include/uapi/linux/i8k.h F: include/uapi/linux/i8k.h
DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas) DELL SYSTEMS MANAGEMENT BASE DRIVER (dcdbas)
...@@ -5444,6 +5444,7 @@ M: Tomas Winkler <tomas.winkler@intel.com> ...@@ -5444,6 +5444,7 @@ M: Tomas Winkler <tomas.winkler@intel.com>
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
S: Supported S: Supported
F: include/uapi/linux/mei.h F: include/uapi/linux/mei.h
F: include/linux/mei_cl_bus.h
F: drivers/misc/mei/* F: drivers/misc/mei/*
F: Documentation/misc-devices/mei/* F: Documentation/misc-devices/mei/*
...@@ -7572,13 +7573,16 @@ S: Maintained ...@@ -7572,13 +7573,16 @@ S: Maintained
F: Documentation/mn10300/ F: Documentation/mn10300/
F: arch/mn10300/ F: arch/mn10300/
PARALLEL PORT SUPPORT PARALLEL PORT SUBSYSTEM
M: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
M: Sudip Mukherjee <sudip@vectorindia.org>
L: linux-parport@lists.infradead.org (subscribers-only) L: linux-parport@lists.infradead.org (subscribers-only)
S: Orphan S: Maintained
F: drivers/parport/ F: drivers/parport/
F: include/linux/parport*.h F: include/linux/parport*.h
F: drivers/char/ppdev.c F: drivers/char/ppdev.c
F: include/uapi/linux/ppdev.h F: include/uapi/linux/ppdev.h
F: Documentation/parport*.txt
PARAVIRT_OPS INTERFACE PARAVIRT_OPS INTERFACE
M: Jeremy Fitzhardinge <jeremy@goop.org> M: Jeremy Fitzhardinge <jeremy@goop.org>
......
...@@ -105,7 +105,7 @@ static int etap_tramp(char *dev, char *gate, int control_me, ...@@ -105,7 +105,7 @@ static int etap_tramp(char *dev, char *gate, int control_me,
sprintf(data_fd_buf, "%d", data_remote); sprintf(data_fd_buf, "%d", data_remote);
sprintf(version_buf, "%d", UML_NET_VERSION); sprintf(version_buf, "%d", UML_NET_VERSION);
if (gate != NULL) { if (gate != NULL) {
strcpy(gate_buf, gate); strncpy(gate_buf, gate, 15);
args = setup_args; args = setup_args;
} }
else args = nosetup_args; else args = nosetup_args;
......
...@@ -1055,24 +1055,19 @@ config TOSHIBA ...@@ -1055,24 +1055,19 @@ config TOSHIBA
Say N otherwise. Say N otherwise.
config I8K config I8K
tristate "Dell laptop support" tristate "Dell i8k legacy laptop support"
select HWMON select HWMON
select SENSORS_DELL_SMM
---help--- ---help---
This adds a driver to safely access the System Management Mode This option enables legacy /proc/i8k userspace interface in hwmon
of the CPU on the Dell Inspiron 8000. The System Management Mode dell-smm-hwmon driver. Character file /proc/i8k reports bios version,
is used to read cpu temperature and cooling fan status and to temperature and allows controlling fan speeds of Dell laptops via
control the fans on the I8K portables. System Management Mode. For old Dell laptops (like Dell Inspiron 8000)
it reports also power and hotkey status. For fan speed control is
needed userspace package i8kutils.
This driver has been tested only on the Inspiron 8000 but it may Say Y if you intend to run this kernel on old Dell laptops or want to
also work with other Dell laptops. You can force loading on other use userspace package i8kutils.
models by passing the parameter `force=1' to the module. Use at
your own risk.
For information on utilities to make use of this driver see the
I8K Linux utilities web site at:
<http://people.debian.org/~dz/i8k/>
Say Y if you intend to run this kernel on a Dell Inspiron 8000.
Say N otherwise. Say N otherwise.
config X86_REBOOTFIXUPS config X86_REBOOTFIXUPS
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/sched.h> /* TASK_* */ #include <linux/sched.h> /* TASK_* */
#include <linux/parport.h> #include <linux/parport.h>
#include <linux/slab.h>
#include "paride.h" #include "paride.h"
...@@ -244,17 +245,19 @@ void paride_unregister(PIP * pr) ...@@ -244,17 +245,19 @@ void paride_unregister(PIP * pr)
EXPORT_SYMBOL(paride_unregister); EXPORT_SYMBOL(paride_unregister);
static int pi_register_parport(PIA * pi, int verbose) static int pi_register_parport(PIA *pi, int verbose, int unit)
{ {
struct parport *port; struct parport *port;
struct pardev_cb par_cb;
port = parport_find_base(pi->port); port = parport_find_base(pi->port);
if (!port) if (!port)
return 0; return 0;
memset(&par_cb, 0, sizeof(par_cb));
pi->pardev = parport_register_device(port, par_cb.wakeup = pi_wake_up;
pi->device, NULL, par_cb.private = (void *)pi;
pi_wake_up, NULL, 0, (void *) pi); pi->pardev = parport_register_dev_model(port, pi->device, &par_cb,
unit);
parport_put_port(port); parport_put_port(port);
if (!pi->pardev) if (!pi->pardev)
return 0; return 0;
...@@ -311,7 +314,7 @@ static int pi_probe_unit(PIA * pi, int unit, char *scratch, int verbose) ...@@ -311,7 +314,7 @@ static int pi_probe_unit(PIA * pi, int unit, char *scratch, int verbose)
e = pi->proto->max_units; e = pi->proto->max_units;
} }
if (!pi_register_parport(pi, verbose)) if (!pi_register_parport(pi, verbose, s))
return 0; return 0;
if (pi->proto->test_port) { if (pi->proto->test_port) {
...@@ -432,3 +435,45 @@ int pi_init(PIA * pi, int autoprobe, int port, int mode, ...@@ -432,3 +435,45 @@ int pi_init(PIA * pi, int autoprobe, int port, int mode,
} }
EXPORT_SYMBOL(pi_init); EXPORT_SYMBOL(pi_init);
static int pi_probe(struct pardevice *par_dev)
{
struct device_driver *drv = par_dev->dev.driver;
int len = strlen(drv->name);
if (strncmp(par_dev->name, drv->name, len))
return -ENODEV;
return 0;
}
void *pi_register_driver(char *name)
{
struct parport_driver *parp_drv;
int ret;
parp_drv = kzalloc(sizeof(*parp_drv), GFP_KERNEL);
if (!parp_drv)
return NULL;
parp_drv->name = name;
parp_drv->probe = pi_probe;
parp_drv->devmodel = true;
ret = parport_register_driver(parp_drv);
if (ret) {
kfree(parp_drv);
return NULL;
}
return (void *)parp_drv;
}
EXPORT_SYMBOL(pi_register_driver);
void pi_unregister_driver(void *_drv)
{
struct parport_driver *drv = _drv;
parport_unregister_driver(drv);
kfree(drv);
}
EXPORT_SYMBOL(pi_unregister_driver);
...@@ -165,6 +165,8 @@ typedef struct pi_protocol PIP; ...@@ -165,6 +165,8 @@ typedef struct pi_protocol PIP;
extern int paride_register( PIP * ); extern int paride_register( PIP * );
extern void paride_unregister ( PIP * ); extern void paride_unregister ( PIP * );
void *pi_register_driver(char *);
void pi_unregister_driver(void *);
#endif /* __DRIVERS_PARIDE_H__ */ #endif /* __DRIVERS_PARIDE_H__ */
/* end of paride.h */ /* end of paride.h */
...@@ -221,6 +221,7 @@ static int pcd_busy; /* request being processed ? */ ...@@ -221,6 +221,7 @@ static int pcd_busy; /* request being processed ? */
static int pcd_sector; /* address of next requested sector */ static int pcd_sector; /* address of next requested sector */
static int pcd_count; /* number of blocks still to do */ static int pcd_count; /* number of blocks still to do */
static char *pcd_buf; /* buffer for request in progress */ static char *pcd_buf; /* buffer for request in progress */
static void *par_drv; /* reference of parport driver */
/* kernel glue structures */ /* kernel glue structures */
...@@ -690,6 +691,12 @@ static int pcd_detect(void) ...@@ -690,6 +691,12 @@ static int pcd_detect(void)
printk("%s: %s version %s, major %d, nice %d\n", printk("%s: %s version %s, major %d, nice %d\n",
name, name, PCD_VERSION, major, nice); name, name, PCD_VERSION, major, nice);
par_drv = pi_register_driver(name);
if (!par_drv) {
pr_err("failed to register %s driver\n", name);
return -1;
}
k = 0; k = 0;
if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */ if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
cd = pcd; cd = pcd;
...@@ -723,6 +730,7 @@ static int pcd_detect(void) ...@@ -723,6 +730,7 @@ static int pcd_detect(void)
printk("%s: No CD-ROM drive found\n", name); printk("%s: No CD-ROM drive found\n", name);
for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++)
put_disk(cd->disk); put_disk(cd->disk);
pi_unregister_driver(par_drv);
return -1; return -1;
} }
...@@ -984,6 +992,7 @@ static void __exit pcd_exit(void) ...@@ -984,6 +992,7 @@ static void __exit pcd_exit(void)
} }
blk_cleanup_queue(pcd_queue); blk_cleanup_queue(pcd_queue);
unregister_blkdev(major, name); unregister_blkdev(major, name);
pi_unregister_driver(par_drv);
} }
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -247,6 +247,8 @@ static char *pd_errs[17] = { "ERR", "INDEX", "ECC", "DRQ", "SEEK", "WRERR", ...@@ -247,6 +247,8 @@ static char *pd_errs[17] = { "ERR", "INDEX", "ECC", "DRQ", "SEEK", "WRERR",
"IDNF", "MC", "UNC", "???", "TMO" "IDNF", "MC", "UNC", "???", "TMO"
}; };
static void *par_drv; /* reference of parport driver */
static inline int status_reg(struct pd_unit *disk) static inline int status_reg(struct pd_unit *disk)
{ {
return pi_read_regr(disk->pi, 1, 6); return pi_read_regr(disk->pi, 1, 6);
...@@ -872,6 +874,12 @@ static int pd_detect(void) ...@@ -872,6 +874,12 @@ static int pd_detect(void)
pd_drive_count++; pd_drive_count++;
} }
par_drv = pi_register_driver(name);
if (!par_drv) {
pr_err("failed to register %s driver\n", name);
return -1;
}
if (pd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */ if (pd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
disk = pd; disk = pd;
if (pi_init(disk->pi, 1, -1, -1, -1, -1, -1, pd_scratch, if (pi_init(disk->pi, 1, -1, -1, -1, -1, -1, pd_scratch,
...@@ -902,8 +910,10 @@ static int pd_detect(void) ...@@ -902,8 +910,10 @@ static int pd_detect(void)
found = 1; found = 1;
} }
} }
if (!found) if (!found) {
printk("%s: no valid drive found\n", name); printk("%s: no valid drive found\n", name);
pi_unregister_driver(par_drv);
}
return found; return found;
} }
......
...@@ -264,6 +264,7 @@ static int pf_cmd; /* current command READ/WRITE */ ...@@ -264,6 +264,7 @@ static int pf_cmd; /* current command READ/WRITE */
static struct pf_unit *pf_current;/* unit of current request */ static struct pf_unit *pf_current;/* unit of current request */
static int pf_mask; /* stopper for pseudo-int */ static int pf_mask; /* stopper for pseudo-int */
static char *pf_buf; /* buffer for request in progress */ static char *pf_buf; /* buffer for request in progress */
static void *par_drv; /* reference of parport driver */
/* kernel glue structures */ /* kernel glue structures */
...@@ -703,6 +704,11 @@ static int pf_detect(void) ...@@ -703,6 +704,11 @@ static int pf_detect(void)
printk("%s: %s version %s, major %d, cluster %d, nice %d\n", printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
name, name, PF_VERSION, major, cluster, nice); name, name, PF_VERSION, major, cluster, nice);
par_drv = pi_register_driver(name);
if (!par_drv) {
pr_err("failed to register %s driver\n", name);
return -1;
}
k = 0; k = 0;
if (pf_drive_count == 0) { if (pf_drive_count == 0) {
if (pi_init(pf->pi, 1, -1, -1, -1, -1, -1, pf_scratch, PI_PF, if (pi_init(pf->pi, 1, -1, -1, -1, -1, -1, pf_scratch, PI_PF,
...@@ -735,6 +741,7 @@ static int pf_detect(void) ...@@ -735,6 +741,7 @@ static int pf_detect(void)
printk("%s: No ATAPI disk detected\n", name); printk("%s: No ATAPI disk detected\n", name);
for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++)
put_disk(pf->disk); put_disk(pf->disk);
pi_unregister_driver(par_drv);
return -1; return -1;
} }
......
...@@ -227,6 +227,7 @@ static int pg_identify(struct pg *dev, int log); ...@@ -227,6 +227,7 @@ static int pg_identify(struct pg *dev, int log);
static char pg_scratch[512]; /* scratch block buffer */ static char pg_scratch[512]; /* scratch block buffer */
static struct class *pg_class; static struct class *pg_class;
static void *par_drv; /* reference of parport driver */
/* kernel glue structures */ /* kernel glue structures */
...@@ -481,6 +482,12 @@ static int pg_detect(void) ...@@ -481,6 +482,12 @@ static int pg_detect(void)
printk("%s: %s version %s, major %d\n", name, name, PG_VERSION, major); printk("%s: %s version %s, major %d\n", name, name, PG_VERSION, major);
par_drv = pi_register_driver(name);
if (!par_drv) {
pr_err("failed to register %s driver\n", name);
return -1;
}
k = 0; k = 0;
if (pg_drive_count == 0) { if (pg_drive_count == 0) {
if (pi_init(dev->pi, 1, -1, -1, -1, -1, -1, pg_scratch, if (pi_init(dev->pi, 1, -1, -1, -1, -1, -1, pg_scratch,
...@@ -511,6 +518,7 @@ static int pg_detect(void) ...@@ -511,6 +518,7 @@ static int pg_detect(void)
if (k) if (k)
return 0; return 0;
pi_unregister_driver(par_drv);
printk("%s: No ATAPI device detected\n", name); printk("%s: No ATAPI device detected\n", name);
return -1; return -1;
} }
......
...@@ -232,6 +232,7 @@ static int pt_identify(struct pt_unit *tape); ...@@ -232,6 +232,7 @@ static int pt_identify(struct pt_unit *tape);
static struct pt_unit pt[PT_UNITS]; static struct pt_unit pt[PT_UNITS];
static char pt_scratch[512]; /* scratch block buffer */ static char pt_scratch[512]; /* scratch block buffer */
static void *par_drv; /* reference of parport driver */
/* kernel glue structures */ /* kernel glue structures */
...@@ -605,6 +606,12 @@ static int pt_detect(void) ...@@ -605,6 +606,12 @@ static int pt_detect(void)
printk("%s: %s version %s, major %d\n", name, name, PT_VERSION, major); printk("%s: %s version %s, major %d\n", name, name, PT_VERSION, major);
par_drv = pi_register_driver(name);
if (!par_drv) {
pr_err("failed to register %s driver\n", name);
return -1;
}
specified = 0; specified = 0;
for (unit = 0; unit < PT_UNITS; unit++) { for (unit = 0; unit < PT_UNITS; unit++) {
struct pt_unit *tape = &pt[unit]; struct pt_unit *tape = &pt[unit];
...@@ -644,6 +651,7 @@ static int pt_detect(void) ...@@ -644,6 +651,7 @@ static int pt_detect(void)
if (found) if (found)
return 0; return 0;
pi_unregister_driver(par_drv);
printk("%s: No ATAPI tape drive detected\n", name); printk("%s: No ATAPI tape drive detected\n", name);
return -1; return -1;
} }
......
...@@ -590,14 +590,6 @@ config DEVPORT ...@@ -590,14 +590,6 @@ config DEVPORT
source "drivers/s390/char/Kconfig" source "drivers/s390/char/Kconfig"
config MSM_SMD_PKT
bool "Enable device interface for some SMD packet ports"
default n
depends on MSM_SMD
help
Enables userspace clients to read and write to some packet SMD
ports via device interface for MSM chipset.
config TILE_SROM config TILE_SROM
bool "Character-device access via hypervisor to the Tilera SPI ROM" bool "Character-device access via hypervisor to the Tilera SPI ROM"
depends on TILE depends on TILE
......
...@@ -9,7 +9,6 @@ obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o ...@@ -9,7 +9,6 @@ obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
obj-$(CONFIG_MSM_SMD_PKT) += msm_smd_pkt.o
obj-$(CONFIG_MSPEC) += mspec.o obj-$(CONFIG_MSPEC) += mspec.o
obj-$(CONFIG_MMTIMER) += mmtimer.o obj-$(CONFIG_MMTIMER) += mmtimer.o
obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o
...@@ -36,7 +35,6 @@ else ...@@ -36,7 +35,6 @@ else
obj-$(CONFIG_NVRAM) += nvram.o obj-$(CONFIG_NVRAM) += nvram.o
endif endif
obj-$(CONFIG_TOSHIBA) += toshiba.o obj-$(CONFIG_TOSHIBA) += toshiba.o
obj-$(CONFIG_I8K) += i8k.o
obj-$(CONFIG_DS1620) += ds1620.o obj-$(CONFIG_DS1620) += ds1620.o
obj-$(CONFIG_HW_RANDOM) += hw_random/ obj-$(CONFIG_HW_RANDOM) += hw_random/
obj-$(CONFIG_PPDEV) += ppdev.o obj-$(CONFIG_PPDEV) += ppdev.o
......
...@@ -117,14 +117,14 @@ static int misc_open(struct inode * inode, struct file * file) ...@@ -117,14 +117,14 @@ static int misc_open(struct inode * inode, struct file * file)
const struct file_operations *new_fops = NULL; const struct file_operations *new_fops = NULL;
mutex_lock(&misc_mtx); mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) { list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) { if (c->minor == minor) {
new_fops = fops_get(c->fops); new_fops = fops_get(c->fops);
break; break;
} }
} }
if (!new_fops) { if (!new_fops) {
mutex_unlock(&misc_mtx); mutex_unlock(&misc_mtx);
request_module("char-major-%d-%d", MISC_MAJOR, minor); request_module("char-major-%d-%d", MISC_MAJOR, minor);
...@@ -167,7 +167,7 @@ static const struct file_operations misc_fops = { ...@@ -167,7 +167,7 @@ static const struct file_operations misc_fops = {
/** /**
* misc_register - register a miscellaneous device * misc_register - register a miscellaneous device
* @misc: device structure * @misc: device structure
* *
* Register a miscellaneous device with the kernel. If the minor * Register a miscellaneous device with the kernel. If the minor
* number is set to %MISC_DYNAMIC_MINOR a minor number is assigned * number is set to %MISC_DYNAMIC_MINOR a minor number is assigned
* and placed in the minor field of the structure. For other cases * and placed in the minor field of the structure. For other cases
...@@ -181,17 +181,18 @@ static const struct file_operations misc_fops = { ...@@ -181,17 +181,18 @@ static const struct file_operations misc_fops = {
* A zero is returned on success and a negative errno code for * A zero is returned on success and a negative errno code for
* failure. * failure.
*/ */
int misc_register(struct miscdevice * misc) int misc_register(struct miscdevice * misc)
{ {
dev_t dev; dev_t dev;
int err = 0; int err = 0;
bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR);
INIT_LIST_HEAD(&misc->list); INIT_LIST_HEAD(&misc->list);
mutex_lock(&misc_mtx); mutex_lock(&misc_mtx);
if (misc->minor == MISC_DYNAMIC_MINOR) { if (is_dynamic) {
int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
if (i >= DYNAMIC_MINORS) { if (i >= DYNAMIC_MINORS) {
err = -EBUSY; err = -EBUSY;
...@@ -216,9 +217,13 @@ int misc_register(struct miscdevice * misc) ...@@ -216,9 +217,13 @@ int misc_register(struct miscdevice * misc)
device_create_with_groups(misc_class, misc->parent, dev, device_create_with_groups(misc_class, misc->parent, dev,
misc, misc->groups, "%s", misc->name); misc, misc->groups, "%s", misc->name);
if (IS_ERR(misc->this_device)) { if (IS_ERR(misc->this_device)) {
int i = DYNAMIC_MINORS - misc->minor - 1; if (is_dynamic) {
if (i < DYNAMIC_MINORS && i >= 0) int i = DYNAMIC_MINORS - misc->minor - 1;
clear_bit(i, misc_minors);
if (i < DYNAMIC_MINORS && i >= 0)
clear_bit(i, misc_minors);
misc->minor = MISC_DYNAMIC_MINOR;
}
err = PTR_ERR(misc->this_device); err = PTR_ERR(misc->this_device);
goto out; goto out;
} }
......
/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
/*
* SMD Packet Driver -- Provides userspace interface to SMD packet ports.
*/
#include <linux/slab.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/sched.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/poll.h>
#include <mach/msm_smd.h>
#define NUM_SMD_PKT_PORTS 9
#define DEVICE_NAME "smdpkt"
#define MAX_BUF_SIZE 2048
struct smd_pkt_dev {
struct cdev cdev;
struct device *devicep;
struct smd_channel *ch;
int open_count;
struct mutex ch_lock;
struct mutex rx_lock;
struct mutex tx_lock;
wait_queue_head_t ch_read_wait_queue;
wait_queue_head_t ch_opened_wait_queue;
int i;
unsigned char tx_buf[MAX_BUF_SIZE];
unsigned char rx_buf[MAX_BUF_SIZE];
int remote_open;
} *smd_pkt_devp[NUM_SMD_PKT_PORTS];
struct class *smd_pkt_classp;
static dev_t smd_pkt_number;
static int msm_smd_pkt_debug_enable;
module_param_named(debug_enable, msm_smd_pkt_debug_enable,
int, S_IRUGO | S_IWUSR | S_IWGRP);
#ifdef DEBUG
#define D_DUMP_BUFFER(prestr, cnt, buf) do { \
int i; \
if (msm_smd_pkt_debug_enable) { \
pr_debug("%s", prestr); \
for (i = 0; i < cnt; i++) \
pr_debug("%.2x", buf[i]); \
pr_debug("\n"); \
} \
} while (0)
#else
#define D_DUMP_BUFFER(prestr, cnt, buf) do {} while (0)
#endif
#ifdef DEBUG
#define DBG(x...) do { \
if (msm_smd_pkt_debug_enable) \
pr_debug(x); \
} while (0)
#else
#define DBG(x...) do {} while (0)
#endif
static void check_and_wakeup_reader(struct smd_pkt_dev *smd_pkt_devp)
{
int sz;
if (!smd_pkt_devp || !smd_pkt_devp->ch)
return;
sz = smd_cur_packet_size(smd_pkt_devp->ch);
if (sz == 0) {
DBG("no packet\n");
return;
}
if (sz > smd_read_avail(smd_pkt_devp->ch)) {
DBG("incomplete packet\n");
return;
}
DBG("waking up reader\n");
wake_up_interruptible(&smd_pkt_devp->ch_read_wait_queue);
}
static int smd_pkt_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
int r, bytes_read;
struct smd_pkt_dev *smd_pkt_devp;
struct smd_channel *chl;
DBG("read %d bytes\n", count);
if (count > MAX_BUF_SIZE)
return -EINVAL;
smd_pkt_devp = file->private_data;
if (!smd_pkt_devp || !smd_pkt_devp->ch)
return -EINVAL;
chl = smd_pkt_devp->ch;
wait_for_packet:
r = wait_event_interruptible(smd_pkt_devp->ch_read_wait_queue,
(smd_cur_packet_size(chl) > 0 &&
smd_read_avail(chl) >=
smd_cur_packet_size(chl)));
if (r < 0) {
if (r != -ERESTARTSYS)
pr_err("wait returned %d\n", r);
return r;
}
mutex_lock(&smd_pkt_devp->rx_lock);
bytes_read = smd_cur_packet_size(smd_pkt_devp->ch);
if (bytes_read == 0 ||
bytes_read < smd_read_avail(smd_pkt_devp->ch)) {
mutex_unlock(&smd_pkt_devp->rx_lock);
DBG("Nothing to read\n");
goto wait_for_packet;
}
if (bytes_read > count) {
mutex_unlock(&smd_pkt_devp->rx_lock);
pr_info("packet size %d > buffer size %d", bytes_read, count);
return -EINVAL;
}
r = smd_read(smd_pkt_devp->ch, smd_pkt_devp->rx_buf, bytes_read);
if (r != bytes_read) {
mutex_unlock(&smd_pkt_devp->rx_lock);
pr_err("smd_read failed to read %d bytes: %d\n", bytes_read, r);
return -EIO;
}
D_DUMP_BUFFER("read: ", bytes_read, smd_pkt_devp->rx_buf);
r = copy_to_user(buf, smd_pkt_devp->rx_buf, bytes_read);
mutex_unlock(&smd_pkt_devp->rx_lock);
if (r) {
pr_err("copy_to_user failed %d\n", r);
return -EFAULT;
}
DBG("read complete %d bytes\n", bytes_read);
check_and_wakeup_reader(smd_pkt_devp);
return bytes_read;
}
static int smd_pkt_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
int r;
struct smd_pkt_dev *smd_pkt_devp;
if (count > MAX_BUF_SIZE)
return -EINVAL;
DBG("writing %d bytes\n", count);
smd_pkt_devp = file->private_data;
if (!smd_pkt_devp || !smd_pkt_devp->ch)
return -EINVAL;
mutex_lock(&smd_pkt_devp->tx_lock);
if (smd_write_avail(smd_pkt_devp->ch) < count) {
mutex_unlock(&smd_pkt_devp->tx_lock);
DBG("Not enough space to write\n");
return -ENOMEM;
}
D_DUMP_BUFFER("write: ", count, buf);
r = copy_from_user(smd_pkt_devp->tx_buf, buf, count);
if (r) {
mutex_unlock(&smd_pkt_devp->tx_lock);
pr_err("copy_from_user failed %d\n", r);
return -EFAULT;
}
r = smd_write(smd_pkt_devp->ch, smd_pkt_devp->tx_buf, count);
if (r != count) {
mutex_unlock(&smd_pkt_devp->tx_lock);
pr_err("smd_write failed to write %d bytes: %d.\n", count, r);
return -EIO;
}
mutex_unlock(&smd_pkt_devp->tx_lock);
DBG("wrote %d bytes\n", count);
return count;
}
static unsigned int smd_pkt_poll(struct file *file, poll_table *wait)
{
struct smd_pkt_dev *smd_pkt_devp;
unsigned int mask = 0;
smd_pkt_devp = file->private_data;
if (!smd_pkt_devp)
return POLLERR;
DBG("poll waiting\n");
poll_wait(file, &smd_pkt_devp->ch_read_wait_queue, wait);
if (smd_read_avail(smd_pkt_devp->ch))
mask |= POLLIN | POLLRDNORM;
DBG("poll return\n");
return mask;
}
static void smd_pkt_ch_notify(void *priv, unsigned event)
{
struct smd_pkt_dev *smd_pkt_devp = priv;
if (smd_pkt_devp->ch == 0)
return;
switch (event) {
case SMD_EVENT_DATA:
DBG("data\n");
check_and_wakeup_reader(smd_pkt_devp);
break;
case SMD_EVENT_OPEN:
DBG("remote open\n");
smd_pkt_devp->remote_open = 1;
wake_up_interruptible(&smd_pkt_devp->ch_opened_wait_queue);
break;
case SMD_EVENT_CLOSE:
smd_pkt_devp->remote_open = 0;
pr_info("remote closed\n");
break;
default:
pr_err("unknown event %d\n", event);
break;
}
}
static char *smd_pkt_dev_name[] = {
"smdcntl0",
"smdcntl1",
"smdcntl2",
"smdcntl3",
"smdcntl4",
"smdcntl5",
"smdcntl6",
"smdcntl7",
"smd22",
};
static char *smd_ch_name[] = {
"DATA5_CNTL",
"DATA6_CNTL",
"DATA7_CNTL",
"DATA8_CNTL",
"DATA9_CNTL",
"DATA12_CNTL",
"DATA13_CNTL",
"DATA14_CNTL",
"DATA22",
};
static int smd_pkt_open(struct inode *inode, struct file *file)
{
int r = 0;
struct smd_pkt_dev *smd_pkt_devp;
smd_pkt_devp = container_of(inode->i_cdev, struct smd_pkt_dev, cdev);
if (!smd_pkt_devp)
return -EINVAL;
file->private_data = smd_pkt_devp;
mutex_lock(&smd_pkt_devp->ch_lock);
if (smd_pkt_devp->open_count == 0) {
r = smd_open(smd_ch_name[smd_pkt_devp->i],
&smd_pkt_devp->ch, smd_pkt_devp,
smd_pkt_ch_notify);
if (r < 0) {
pr_err("smd_open failed for %s, %d\n",
smd_ch_name[smd_pkt_devp->i], r);
goto out;
}
r = wait_event_interruptible_timeout(
smd_pkt_devp->ch_opened_wait_queue,
smd_pkt_devp->remote_open,
msecs_to_jiffies(2 * HZ));
if (r == 0)
r = -ETIMEDOUT;
if (r < 0) {
pr_err("wait returned %d\n", r);
smd_close(smd_pkt_devp->ch);
smd_pkt_devp->ch = 0;
} else {
smd_pkt_devp->open_count++;
r = 0;
}
}
out:
mutex_unlock(&smd_pkt_devp->ch_lock);
return r;
}
static int smd_pkt_release(struct inode *inode, struct file *file)
{
int r = 0;
struct smd_pkt_dev *smd_pkt_devp = file->private_data;
if (!smd_pkt_devp)
return -EINVAL;
mutex_lock(&smd_pkt_devp->ch_lock);
if (--smd_pkt_devp->open_count == 0) {
r = smd_close(smd_pkt_devp->ch);
smd_pkt_devp->ch = 0;
}
mutex_unlock(&smd_pkt_devp->ch_lock);
return r;
}
static const struct file_operations smd_pkt_fops = {
.owner = THIS_MODULE,
.open = smd_pkt_open,
.release = smd_pkt_release,
.read = smd_pkt_read,
.write = smd_pkt_write,
.poll = smd_pkt_poll,
};
static int __init smd_pkt_init(void)
{
int i;
int r;
r = alloc_chrdev_region(&smd_pkt_number, 0,
NUM_SMD_PKT_PORTS, DEVICE_NAME);
if (r) {
pr_err("alloc_chrdev_region() failed %d\n", r);
return r;
}
smd_pkt_classp = class_create(THIS_MODULE, DEVICE_NAME);
if (IS_ERR(smd_pkt_classp)) {
r = PTR_ERR(smd_pkt_classp);
pr_err("class_create() failed %d\n", r);
goto unreg_chardev;
}
for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
smd_pkt_devp[i] = kzalloc(sizeof(struct smd_pkt_dev),
GFP_KERNEL);
if (!smd_pkt_devp[i]) {
pr_err("kmalloc() failed\n");
goto clean_cdevs;
}
smd_pkt_devp[i]->i = i;
init_waitqueue_head(&smd_pkt_devp[i]->ch_read_wait_queue);
smd_pkt_devp[i]->remote_open = 0;
init_waitqueue_head(&smd_pkt_devp[i]->ch_opened_wait_queue);
mutex_init(&smd_pkt_devp[i]->ch_lock);
mutex_init(&smd_pkt_devp[i]->rx_lock);
mutex_init(&smd_pkt_devp[i]->tx_lock);
cdev_init(&smd_pkt_devp[i]->cdev, &smd_pkt_fops);
smd_pkt_devp[i]->cdev.owner = THIS_MODULE;
r = cdev_add(&smd_pkt_devp[i]->cdev,
(smd_pkt_number + i), 1);
if (r) {
pr_err("cdev_add() failed %d\n", r);
kfree(smd_pkt_devp[i]);
goto clean_cdevs;
}
smd_pkt_devp[i]->devicep =
device_create(smd_pkt_classp, NULL,
(smd_pkt_number + i), NULL,
smd_pkt_dev_name[i]);
if (IS_ERR(smd_pkt_devp[i]->devicep)) {
r = PTR_ERR(smd_pkt_devp[i]->devicep);
pr_err("device_create() failed %d\n", r);
cdev_del(&smd_pkt_devp[i]->cdev);
kfree(smd_pkt_devp[i]);
goto clean_cdevs;
}
}
pr_info("SMD Packet Port Driver Initialized.\n");
return 0;
clean_cdevs:
if (i > 0) {
while (--i >= 0) {
mutex_destroy(&smd_pkt_devp[i]->ch_lock);
mutex_destroy(&smd_pkt_devp[i]->rx_lock);
mutex_destroy(&smd_pkt_devp[i]->tx_lock);
cdev_del(&smd_pkt_devp[i]->cdev);
kfree(smd_pkt_devp[i]);
device_destroy(smd_pkt_classp,
MKDEV(MAJOR(smd_pkt_number), i));
}
}
class_destroy(smd_pkt_classp);
unreg_chardev:
unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS);
return r;
}
module_init(smd_pkt_init);
static void __exit smd_pkt_cleanup(void)
{
int i;
for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
mutex_destroy(&smd_pkt_devp[i]->ch_lock);
mutex_destroy(&smd_pkt_devp[i]->rx_lock);
mutex_destroy(&smd_pkt_devp[i]->tx_lock);
cdev_del(&smd_pkt_devp[i]->cdev);
kfree(smd_pkt_devp[i]);
device_destroy(smd_pkt_classp,
MKDEV(MAJOR(smd_pkt_number), i));
}
class_destroy(smd_pkt_classp);
unregister_chrdev_region(MAJOR(smd_pkt_number), NUM_SMD_PKT_PORTS);
}
module_exit(smd_pkt_cleanup);
MODULE_DESCRIPTION("MSM Shared Memory Packet Port");
MODULE_LICENSE("GPL v2");
...@@ -437,7 +437,7 @@ static int mgslpc_device_count = 0; ...@@ -437,7 +437,7 @@ static int mgslpc_device_count = 0;
* .text section address and breakpoint on module load. * .text section address and breakpoint on module load.
* This is useful for use with gdb and add-symbol-file command. * This is useful for use with gdb and add-symbol-file command.
*/ */
static bool break_on_load=0; static bool break_on_load;
/* /*
* Driver major number, defaults to zero to get auto * Driver major number, defaults to zero to get auto
......
...@@ -198,7 +198,7 @@ scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos) ...@@ -198,7 +198,7 @@ scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
add_wait_queue(&sd->sd_rq, &wait); add_wait_queue(&sd->sd_rq, &wait);
spin_unlock_irqrestore(&sd->sd_rlock, flags); spin_unlock_irqrestore(&sd->sd_rlock, flags);
schedule_timeout(SCDRV_TIMEOUT); schedule_timeout(msecs_to_jiffies(SCDRV_TIMEOUT));
remove_wait_queue(&sd->sd_rq, &wait); remove_wait_queue(&sd->sd_rq, &wait);
if (signal_pending(current)) { if (signal_pending(current)) {
...@@ -294,7 +294,7 @@ scdrv_write(struct file *file, const char __user *buf, ...@@ -294,7 +294,7 @@ scdrv_write(struct file *file, const char __user *buf,
add_wait_queue(&sd->sd_wq, &wait); add_wait_queue(&sd->sd_wq, &wait);
spin_unlock_irqrestore(&sd->sd_wlock, flags); spin_unlock_irqrestore(&sd->sd_wlock, flags);
schedule_timeout(SCDRV_TIMEOUT); schedule_timeout(msecs_to_jiffies(SCDRV_TIMEOUT));
remove_wait_queue(&sd->sd_wq, &wait); remove_wait_queue(&sd->sd_wq, &wait);
if (signal_pending(current)) { if (signal_pending(current)) {
......
...@@ -1492,8 +1492,8 @@ static int add_port(struct ports_device *portdev, u32 id) ...@@ -1492,8 +1492,8 @@ static int add_port(struct ports_device *portdev, u32 id)
* Finally, create the debugfs file that we can use to * Finally, create the debugfs file that we can use to
* inspect a port's state at any time * inspect a port's state at any time
*/ */
sprintf(debugfs_name, "vport%up%u", snprintf(debugfs_name, sizeof(debugfs_name), "vport%up%u",
port->portdev->vdev->index, id); port->portdev->vdev->index, id);
port->debugfs_file = debugfs_create_file(debugfs_name, 0444, port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
pdrvdata.debugfs_dir, pdrvdata.debugfs_dir,
port, port,
......
...@@ -270,7 +270,7 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, ...@@ -270,7 +270,7 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
int status; int status;
s32 buffer_count = 0; s32 buffer_count = 0;
s32 num_writes = 0; s32 num_writes = 0;
bool dirty = 0; bool dirty = false;
u32 i; u32 i;
void __iomem *base_address = drvdata->base_address; void __iomem *base_address = drvdata->base_address;
...@@ -279,7 +279,7 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, ...@@ -279,7 +279,7 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
/* Copy data to bram */ /* Copy data to bram */
buffer_icap_set_bram(base_address, buffer_count, data[i]); buffer_icap_set_bram(base_address, buffer_count, data[i]);
dirty = 1; dirty = true;
if (buffer_count < XHI_MAX_BUFFER_INTS - 1) { if (buffer_count < XHI_MAX_BUFFER_INTS - 1) {
buffer_count++; buffer_count++;
...@@ -299,7 +299,7 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data, ...@@ -299,7 +299,7 @@ int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
buffer_count = 0; buffer_count = 0;
num_writes++; num_writes++;
dirty = 0; dirty = false;
} }
/* Write unwritten data to ICAP */ /* Write unwritten data to ICAP */
......
...@@ -24,7 +24,7 @@ config XILLYBUS_PCIE ...@@ -24,7 +24,7 @@ config XILLYBUS_PCIE
config XILLYBUS_OF config XILLYBUS_OF
tristate "Xillybus over Device Tree" tristate "Xillybus over Device Tree"
depends on OF_ADDRESS && OF_IRQ depends on OF_ADDRESS && OF_IRQ && HAS_DMA
help help
Set to M if you want Xillybus to find its resources from the Set to M if you want Xillybus to find its resources from the
Open Firmware Flattened Device Tree. If the target is an embedded Open Firmware Flattened Device Tree. If the target is an embedded
......
...@@ -28,15 +28,22 @@ config EXTCON_ARIZONA ...@@ -28,15 +28,22 @@ config EXTCON_ARIZONA
with Wolfson Arizona devices. These are audio CODECs with with Wolfson Arizona devices. These are audio CODECs with
advanced audio accessory detection support. advanced audio accessory detection support.
config EXTCON_AXP288
tristate "X-Power AXP288 EXTCON support"
depends on MFD_AXP20X && USB_PHY
help
Say Y here to enable support for USB peripheral detection
and USB MUX switching by X-Power AXP288 PMIC.
config EXTCON_GPIO config EXTCON_GPIO
tristate "GPIO extcon support" tristate "GPIO extcon support"
depends on GPIOLIB depends on GPIOLIB || COMPILE_TEST
help help
Say Y here to enable GPIO based extcon support. Note that GPIO Say Y here to enable GPIO based extcon support. Note that GPIO
extcon supports single state per extcon instance. extcon supports single state per extcon instance.
config EXTCON_MAX14577 config EXTCON_MAX14577
tristate "MAX14577/77836 EXTCON Support" tristate "Maxim MAX14577/77836 EXTCON Support"
depends on MFD_MAX14577 depends on MFD_MAX14577
select IRQ_DOMAIN select IRQ_DOMAIN
select REGMAP_I2C select REGMAP_I2C
...@@ -46,7 +53,7 @@ config EXTCON_MAX14577 ...@@ -46,7 +53,7 @@ config EXTCON_MAX14577
detector and switch. detector and switch.
config EXTCON_MAX77693 config EXTCON_MAX77693
tristate "MAX77693 EXTCON Support" tristate "Maxim MAX77693 EXTCON Support"
depends on MFD_MAX77693 && INPUT depends on MFD_MAX77693 && INPUT
select IRQ_DOMAIN select IRQ_DOMAIN
select REGMAP_I2C select REGMAP_I2C
...@@ -56,7 +63,7 @@ config EXTCON_MAX77693 ...@@ -56,7 +63,7 @@ config EXTCON_MAX77693
detector and switch. detector and switch.
config EXTCON_MAX77843 config EXTCON_MAX77843
tristate "MAX77843 EXTCON Support" tristate "Maxim MAX77843 EXTCON Support"
depends on MFD_MAX77843 depends on MFD_MAX77843
select IRQ_DOMAIN select IRQ_DOMAIN
select REGMAP_I2C select REGMAP_I2C
...@@ -66,7 +73,7 @@ config EXTCON_MAX77843 ...@@ -66,7 +73,7 @@ config EXTCON_MAX77843
detector add switch. detector add switch.
config EXTCON_MAX8997 config EXTCON_MAX8997
tristate "MAX8997 EXTCON Support" tristate "Maxim MAX8997 EXTCON Support"
depends on MFD_MAX8997 && IRQ_DOMAIN depends on MFD_MAX8997 && IRQ_DOMAIN
help help
If you say yes here you get support for the MUIC device of If you say yes here you get support for the MUIC device of
...@@ -81,7 +88,7 @@ config EXTCON_PALMAS ...@@ -81,7 +88,7 @@ config EXTCON_PALMAS
detection by palmas usb. detection by palmas usb.
config EXTCON_RT8973A config EXTCON_RT8973A
tristate "RT8973A EXTCON support" tristate "Richtek RT8973A EXTCON support"
depends on I2C depends on I2C
select IRQ_DOMAIN select IRQ_DOMAIN
select REGMAP_I2C select REGMAP_I2C
...@@ -93,7 +100,7 @@ config EXTCON_RT8973A ...@@ -93,7 +100,7 @@ config EXTCON_RT8973A
from abnormal high input voltage (up to 28V). from abnormal high input voltage (up to 28V).
config EXTCON_SM5502 config EXTCON_SM5502
tristate "SM5502 EXTCON support" tristate "Silicon Mitus SM5502 EXTCON support"
depends on I2C depends on I2C
select IRQ_DOMAIN select IRQ_DOMAIN
select REGMAP_I2C select REGMAP_I2C
...@@ -105,9 +112,9 @@ config EXTCON_SM5502 ...@@ -105,9 +112,9 @@ config EXTCON_SM5502
config EXTCON_USB_GPIO config EXTCON_USB_GPIO
tristate "USB GPIO extcon support" tristate "USB GPIO extcon support"
depends on GPIOLIB depends on GPIOLIB || COMPILE_TEST
help help
Say Y here to enable GPIO based USB cable detection extcon support. Say Y here to enable GPIO based USB cable detection extcon support.
Used typically if GPIO is used for USB ID pin detection. Used typically if GPIO is used for USB ID pin detection.
endif # MULTISTATE_SWITCH endif
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
obj-$(CONFIG_EXTCON) += extcon.o obj-$(CONFIG_EXTCON) += extcon.o
obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o obj-$(CONFIG_EXTCON_ADC_JACK) += extcon-adc-jack.o
obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o
obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o
obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o
obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o
obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
* struct adc_jack_data - internal data for adc_jack device driver * struct adc_jack_data - internal data for adc_jack device driver
* @edev: extcon device. * @edev: extcon device.
* @cable_names: list of supported cables. * @cable_names: list of supported cables.
* @num_cables: size of cable_names.
* @adc_conditions: list of adc value conditions. * @adc_conditions: list of adc value conditions.
* @num_conditions: size of adc_conditions. * @num_conditions: size of adc_conditions.
* @irq: irq number of attach/detach event (0 if not exist). * @irq: irq number of attach/detach event (0 if not exist).
...@@ -41,8 +40,7 @@ ...@@ -41,8 +40,7 @@
struct adc_jack_data { struct adc_jack_data {
struct extcon_dev *edev; struct extcon_dev *edev;
const char **cable_names; const unsigned int **cable_names;
int num_cables;
struct adc_jack_cond *adc_conditions; struct adc_jack_cond *adc_conditions;
int num_conditions; int num_conditions;
...@@ -112,17 +110,6 @@ static int adc_jack_probe(struct platform_device *pdev) ...@@ -112,17 +110,6 @@ static int adc_jack_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to allocate extcon device\n"); dev_err(&pdev->dev, "failed to allocate extcon device\n");
return -ENOMEM; return -ENOMEM;
} }
data->edev->name = pdata->name;
/* Check the length of array and set num_cables */
for (i = 0; data->edev->supported_cable[i]; i++)
;
if (i == 0 || i > SUPPORTED_CABLE_MAX) {
dev_err(&pdev->dev, "error: pdata->cable_names size = %d\n",
i - 1);
return -EINVAL;
}
data->num_cables = i;
if (!pdata->adc_conditions || if (!pdata->adc_conditions ||
!pdata->adc_conditions[0].state) { !pdata->adc_conditions[0].state) {
......
...@@ -32,13 +32,10 @@ ...@@ -32,13 +32,10 @@
#include <linux/mfd/arizona/core.h> #include <linux/mfd/arizona/core.h>
#include <linux/mfd/arizona/pdata.h> #include <linux/mfd/arizona/pdata.h>
#include <linux/mfd/arizona/registers.h> #include <linux/mfd/arizona/registers.h>
#include <dt-bindings/mfd/arizona.h>
#define ARIZONA_MAX_MICD_RANGE 8 #define ARIZONA_MAX_MICD_RANGE 8
#define ARIZONA_ACCDET_MODE_MIC 0
#define ARIZONA_ACCDET_MODE_HPL 1
#define ARIZONA_ACCDET_MODE_HPR 2
#define ARIZONA_MICD_CLAMP_MODE_JDL 0x4 #define ARIZONA_MICD_CLAMP_MODE_JDL 0x4
#define ARIZONA_MICD_CLAMP_MODE_JDH 0x5 #define ARIZONA_MICD_CLAMP_MODE_JDH 0x5
#define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9 #define ARIZONA_MICD_CLAMP_MODE_JDL_GP5H 0x9
...@@ -94,7 +91,7 @@ struct arizona_extcon_info { ...@@ -94,7 +91,7 @@ struct arizona_extcon_info {
bool detecting; bool detecting;
int jack_flips; int jack_flips;
int hpdet_ip; int hpdet_ip_version;
struct extcon_dev *edev; struct extcon_dev *edev;
}; };
...@@ -121,17 +118,12 @@ static const int arizona_micd_levels[] = { ...@@ -121,17 +118,12 @@ static const int arizona_micd_levels[] = {
1257, 1257,
}; };
#define ARIZONA_CABLE_MECHANICAL 0 static const unsigned int arizona_cable[] = {
#define ARIZONA_CABLE_MICROPHONE 1 EXTCON_MECHANICAL,
#define ARIZONA_CABLE_HEADPHONE 2 EXTCON_MICROPHONE,
#define ARIZONA_CABLE_LINEOUT 3 EXTCON_HEADPHONE,
EXTCON_LINE_OUT,
static const char *arizona_cable[] = { EXTCON_NONE,
"Mechanical",
"Microphone",
"Headphone",
"Line-out",
NULL,
}; };
static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info); static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info);
...@@ -145,6 +137,7 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info, ...@@ -145,6 +137,7 @@ static void arizona_extcon_hp_clamp(struct arizona_extcon_info *info,
switch (arizona->type) { switch (arizona->type) {
case WM5110: case WM5110:
case WM8280:
mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR | mask = ARIZONA_HP1L_SHRTO | ARIZONA_HP1L_FLWR |
ARIZONA_HP1L_SHRTI; ARIZONA_HP1L_SHRTI;
if (clamp) if (clamp)
...@@ -380,7 +373,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) ...@@ -380,7 +373,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
return ret; return ret;
} }
switch (info->hpdet_ip) { switch (info->hpdet_ip_version) {
case 0: case 0:
if (!(val & ARIZONA_HP_DONE)) { if (!(val & ARIZONA_HP_DONE)) {
dev_err(arizona->dev, "HPDET did not complete: %x\n", dev_err(arizona->dev, "HPDET did not complete: %x\n",
...@@ -441,7 +434,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) ...@@ -441,7 +434,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info)
default: default:
dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n", dev_warn(arizona->dev, "Unknown HPDET IP revision %d\n",
info->hpdet_ip); info->hpdet_ip_version);
case 2: case 2:
if (!(val & ARIZONA_HP_DONE_B)) { if (!(val & ARIZONA_HP_DONE_B)) {
dev_err(arizona->dev, "HPDET did not complete: %x\n", dev_err(arizona->dev, "HPDET did not complete: %x\n",
...@@ -559,7 +552,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) ...@@ -559,7 +552,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
struct arizona_extcon_info *info = data; struct arizona_extcon_info *info = data;
struct arizona *arizona = info->arizona; struct arizona *arizona = info->arizona;
int id_gpio = arizona->pdata.hpdet_id_gpio; int id_gpio = arizona->pdata.hpdet_id_gpio;
int report = ARIZONA_CABLE_HEADPHONE; unsigned int report = EXTCON_HEADPHONE;
int ret, reading; int ret, reading;
bool mic = false; bool mic = false;
...@@ -573,7 +566,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) ...@@ -573,7 +566,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
} }
/* If the cable was removed while measuring ignore the result */ /* If the cable was removed while measuring ignore the result */
ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL); ret = extcon_get_cable_state_(info->edev, EXTCON_MECHANICAL);
if (ret < 0) { if (ret < 0) {
dev_err(arizona->dev, "Failed to check cable state: %d\n", dev_err(arizona->dev, "Failed to check cable state: %d\n",
ret); ret);
...@@ -604,9 +597,9 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) ...@@ -604,9 +597,9 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
/* Report high impedence cables as line outputs */ /* Report high impedence cables as line outputs */
if (reading >= 5000) if (reading >= 5000)
report = ARIZONA_CABLE_LINEOUT; report = EXTCON_LINE_OUT;
else else
report = ARIZONA_CABLE_HEADPHONE; report = EXTCON_HEADPHONE;
ret = extcon_set_cable_state_(info->edev, report, true); ret = extcon_set_cable_state_(info->edev, report, true);
if (ret != 0) if (ret != 0)
...@@ -670,9 +663,9 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) ...@@ -670,9 +663,9 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
ret = regmap_update_bits(arizona->regmap, ret = regmap_update_bits(arizona->regmap,
ARIZONA_ACCESSORY_DETECT_MODE_1, ARIZONA_ACCESSORY_DETECT_MODE_1,
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MASK,
ARIZONA_ACCDET_MODE_HPL); arizona->pdata.hpdet_channel);
if (ret != 0) { if (ret != 0) {
dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret); dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
goto err; goto err;
} }
...@@ -691,8 +684,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info) ...@@ -691,8 +684,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
/* Just report headphone */ /* Just report headphone */
ret = extcon_set_cable_state_(info->edev, ret = extcon_set_cable_state_(info->edev, EXTCON_HEADPHONE, true);
ARIZONA_CABLE_HEADPHONE, true);
if (ret != 0) if (ret != 0)
dev_err(arizona->dev, "Failed to report headphone: %d\n", ret); dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
...@@ -722,9 +714,9 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) ...@@ -722,9 +714,9 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
ARIZONA_ACCESSORY_DETECT_MODE_1, ARIZONA_ACCESSORY_DETECT_MODE_1,
ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_SRC | ARIZONA_ACCDET_MODE_MASK,
info->micd_modes[0].src | info->micd_modes[0].src |
ARIZONA_ACCDET_MODE_HPL); arizona->pdata.hpdet_channel);
if (ret != 0) { if (ret != 0) {
dev_err(arizona->dev, "Failed to set HPDETL mode: %d\n", ret); dev_err(arizona->dev, "Failed to set HPDET mode: %d\n", ret);
goto err; goto err;
} }
...@@ -749,8 +741,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info) ...@@ -749,8 +741,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC); ARIZONA_ACCDET_MODE_MASK, ARIZONA_ACCDET_MODE_MIC);
/* Just report headphone */ /* Just report headphone */
ret = extcon_set_cable_state_(info->edev, ret = extcon_set_cable_state_(info->edev, EXTCON_HEADPHONE, true);
ARIZONA_CABLE_HEADPHONE, true);
if (ret != 0) if (ret != 0)
dev_err(arizona->dev, "Failed to report headphone: %d\n", ret); dev_err(arizona->dev, "Failed to report headphone: %d\n", ret);
...@@ -789,7 +780,7 @@ static void arizona_micd_detect(struct work_struct *work) ...@@ -789,7 +780,7 @@ static void arizona_micd_detect(struct work_struct *work)
mutex_lock(&info->lock); mutex_lock(&info->lock);
/* If the cable was removed while measuring ignore the result */ /* If the cable was removed while measuring ignore the result */
ret = extcon_get_cable_state_(info->edev, ARIZONA_CABLE_MECHANICAL); ret = extcon_get_cable_state_(info->edev, EXTCON_MECHANICAL);
if (ret < 0) { if (ret < 0) {
dev_err(arizona->dev, "Failed to check cable state: %d\n", dev_err(arizona->dev, "Failed to check cable state: %d\n",
ret); ret);
...@@ -838,8 +829,7 @@ static void arizona_micd_detect(struct work_struct *work) ...@@ -838,8 +829,7 @@ static void arizona_micd_detect(struct work_struct *work)
arizona_identify_headphone(info); arizona_identify_headphone(info);
ret = extcon_set_cable_state_(info->edev, ret = extcon_set_cable_state_(info->edev,
ARIZONA_CABLE_MICROPHONE, true); EXTCON_MICROPHONE, true);
if (ret != 0) if (ret != 0)
dev_err(arizona->dev, "Headset report failed: %d\n", dev_err(arizona->dev, "Headset report failed: %d\n",
ret); ret);
...@@ -1030,7 +1020,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) ...@@ -1030,7 +1020,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data)
if (info->last_jackdet == present) { if (info->last_jackdet == present) {
dev_dbg(arizona->dev, "Detected jack\n"); dev_dbg(arizona->dev, "Detected jack\n");
ret = extcon_set_cable_state_(info->edev, ret = extcon_set_cable_state_(info->edev,
ARIZONA_CABLE_MECHANICAL, true); EXTCON_MECHANICAL, true);
if (ret != 0) if (ret != 0)
dev_err(arizona->dev, "Mechanical report failed: %d\n", dev_err(arizona->dev, "Mechanical report failed: %d\n",
...@@ -1120,6 +1110,26 @@ static void arizona_micd_set_level(struct arizona *arizona, int index, ...@@ -1120,6 +1110,26 @@ static void arizona_micd_set_level(struct arizona *arizona, int index,
regmap_update_bits(arizona->regmap, reg, mask, level); regmap_update_bits(arizona->regmap, reg, mask, level);
} }
static int arizona_extcon_of_get_pdata(struct arizona *arizona)
{
struct arizona_pdata *pdata = &arizona->pdata;
unsigned int val = ARIZONA_ACCDET_MODE_HPL;
of_property_read_u32(arizona->dev->of_node, "wlf,hpdet-channel", &val);
switch (val) {
case ARIZONA_ACCDET_MODE_HPL:
case ARIZONA_ACCDET_MODE_HPR:
pdata->hpdet_channel = val;
break;
default:
dev_err(arizona->dev,
"Wrong wlf,hpdet-channel DT value %d\n", val);
pdata->hpdet_channel = ARIZONA_ACCDET_MODE_HPL;
}
return 0;
}
static int arizona_extcon_probe(struct platform_device *pdev) static int arizona_extcon_probe(struct platform_device *pdev)
{ {
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
...@@ -1137,6 +1147,11 @@ static int arizona_extcon_probe(struct platform_device *pdev) ...@@ -1137,6 +1147,11 @@ static int arizona_extcon_probe(struct platform_device *pdev)
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;
if (IS_ENABLED(CONFIG_OF)) {
if (!dev_get_platdata(arizona->dev))
arizona_extcon_of_get_pdata(arizona);
}
info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD"); info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD");
if (IS_ERR(info->micvdd)) { if (IS_ERR(info->micvdd)) {
ret = PTR_ERR(info->micvdd); ret = PTR_ERR(info->micvdd);
...@@ -1161,7 +1176,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) ...@@ -1161,7 +1176,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
break; break;
default: default:
info->micd_clamp = true; info->micd_clamp = true;
info->hpdet_ip = 1; info->hpdet_ip_version = 1;
break; break;
} }
break; break;
...@@ -1172,7 +1187,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) ...@@ -1172,7 +1187,7 @@ static int arizona_extcon_probe(struct platform_device *pdev)
break; break;
default: default:
info->micd_clamp = true; info->micd_clamp = true;
info->hpdet_ip = 2; info->hpdet_ip_version = 2;
break; break;
} }
break; break;
...@@ -1185,7 +1200,6 @@ static int arizona_extcon_probe(struct platform_device *pdev) ...@@ -1185,7 +1200,6 @@ static int arizona_extcon_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to allocate extcon device\n"); dev_err(&pdev->dev, "failed to allocate extcon device\n");
return -ENOMEM; return -ENOMEM;
} }
info->edev->name = "Headset Jack";
ret = devm_extcon_dev_register(&pdev->dev, info->edev); ret = devm_extcon_dev_register(&pdev->dev, info->edev);
if (ret < 0) { if (ret < 0) {
......
/*
* extcon-axp288.c - X-Power AXP288 PMIC extcon cable detection driver
*
* Copyright (C) 2015 Intel Corporation
* Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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/module.h>
#include <linux/kernel.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/usb/phy.h>
#include <linux/notifier.h>
#include <linux/extcon.h>
#include <linux/regmap.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/mfd/axp20x.h>
/* Power source status register */
#define PS_STAT_VBUS_TRIGGER BIT(0)
#define PS_STAT_BAT_CHRG_DIR BIT(2)
#define PS_STAT_VBUS_ABOVE_VHOLD BIT(3)
#define PS_STAT_VBUS_VALID BIT(4)
#define PS_STAT_VBUS_PRESENT BIT(5)
/* BC module global register */
#define BC_GLOBAL_RUN BIT(0)
#define BC_GLOBAL_DET_STAT BIT(2)
#define BC_GLOBAL_DBP_TOUT BIT(3)
#define BC_GLOBAL_VLGC_COM_SEL BIT(4)
#define BC_GLOBAL_DCD_TOUT_MASK (BIT(6)|BIT(5))
#define BC_GLOBAL_DCD_TOUT_300MS 0
#define BC_GLOBAL_DCD_TOUT_100MS 1
#define BC_GLOBAL_DCD_TOUT_500MS 2
#define BC_GLOBAL_DCD_TOUT_900MS 3
#define BC_GLOBAL_DCD_DET_SEL BIT(7)
/* BC module vbus control and status register */
#define VBUS_CNTL_DPDM_PD_EN BIT(4)
#define VBUS_CNTL_DPDM_FD_EN BIT(5)
#define VBUS_CNTL_FIRST_PO_STAT BIT(6)
/* BC USB status register */
#define USB_STAT_BUS_STAT_MASK (BIT(3)|BIT(2)|BIT(1)|BIT(0))
#define USB_STAT_BUS_STAT_SHIFT 0
#define USB_STAT_BUS_STAT_ATHD 0
#define USB_STAT_BUS_STAT_CONN 1
#define USB_STAT_BUS_STAT_SUSP 2
#define USB_STAT_BUS_STAT_CONF 3
#define USB_STAT_USB_SS_MODE BIT(4)
#define USB_STAT_DEAD_BAT_DET BIT(6)
#define USB_STAT_DBP_UNCFG BIT(7)
/* BC detect status register */
#define DET_STAT_MASK (BIT(7)|BIT(6)|BIT(5))
#define DET_STAT_SHIFT 5
#define DET_STAT_SDP 1
#define DET_STAT_CDP 2
#define DET_STAT_DCP 3
/* IRQ enable-1 register */
#define PWRSRC_IRQ_CFG_MASK (BIT(4)|BIT(3)|BIT(2))
/* IRQ enable-6 register */
#define BC12_IRQ_CFG_MASK BIT(1)
enum axp288_extcon_reg {
AXP288_PS_STAT_REG = 0x00,
AXP288_PS_BOOT_REASON_REG = 0x02,
AXP288_BC_GLOBAL_REG = 0x2c,
AXP288_BC_VBUS_CNTL_REG = 0x2d,
AXP288_BC_USB_STAT_REG = 0x2e,
AXP288_BC_DET_STAT_REG = 0x2f,
AXP288_PWRSRC_IRQ_CFG_REG = 0x40,
AXP288_BC12_IRQ_CFG_REG = 0x45,
};
enum axp288_mux_select {
EXTCON_GPIO_MUX_SEL_PMIC = 0,
EXTCON_GPIO_MUX_SEL_SOC,
};
enum axp288_extcon_irq {
VBUS_FALLING_IRQ = 0,
VBUS_RISING_IRQ,
MV_CHNG_IRQ,
BC_USB_CHNG_IRQ,
EXTCON_IRQ_END,
};
static const unsigned int axp288_extcon_cables[] = {
EXTCON_SLOW_CHARGER,
EXTCON_CHARGE_DOWNSTREAM,
EXTCON_FAST_CHARGER,
EXTCON_NONE,
};
struct axp288_extcon_info {
struct device *dev;
struct regmap *regmap;
struct regmap_irq_chip_data *regmap_irqc;
struct axp288_extcon_pdata *pdata;
int irq[EXTCON_IRQ_END];
struct extcon_dev *edev;
struct notifier_block extcon_nb;
struct usb_phy *otg;
};
/* Power up/down reason string array */
static char *axp288_pwr_up_down_info[] = {
"Last wake caused by user pressing the power button",
"Last wake caused by a charger insertion",
"Last wake caused by a battery insertion",
"Last wake caused by SOC initiated global reset",
"Last wake caused by cold reset",
"Last shutdown caused by PMIC UVLO threshold",
"Last shutdown caused by SOC initiated cold off",
"Last shutdown caused by user pressing the power button",
NULL,
};
/*
* Decode and log the given "reset source indicator" (rsi)
* register and then clear it.
*/
static void axp288_extcon_log_rsi(struct axp288_extcon_info *info)
{
char **rsi;
unsigned int val, i, clear_mask = 0;
int ret;
ret = regmap_read(info->regmap, AXP288_PS_BOOT_REASON_REG, &val);
for (i = 0, rsi = axp288_pwr_up_down_info; *rsi; rsi++, i++) {
if (val & BIT(i)) {
dev_dbg(info->dev, "%s\n", *rsi);
clear_mask |= BIT(i);
}
}
/* Clear the register value for next reboot (write 1 to clear bit) */
regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask);
}
static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
{
static bool notify_otg, notify_charger;
static unsigned int cable;
int ret, stat, cfg, pwr_stat;
u8 chrg_type;
bool vbus_attach = false;
ret = regmap_read(info->regmap, AXP288_PS_STAT_REG, &pwr_stat);
if (ret < 0) {
dev_err(info->dev, "failed to read vbus status\n");
return ret;
}
vbus_attach = (pwr_stat & PS_STAT_VBUS_PRESENT);
if (!vbus_attach)
goto notify_otg;
/* Check charger detection completion status */
ret = regmap_read(info->regmap, AXP288_BC_GLOBAL_REG, &cfg);
if (ret < 0)
goto dev_det_ret;
if (cfg & BC_GLOBAL_DET_STAT) {
dev_dbg(info->dev, "can't complete the charger detection\n");
goto dev_det_ret;
}
ret = regmap_read(info->regmap, AXP288_BC_DET_STAT_REG, &stat);
if (ret < 0)
goto dev_det_ret;
chrg_type = (stat & DET_STAT_MASK) >> DET_STAT_SHIFT;
switch (chrg_type) {
case DET_STAT_SDP:
dev_dbg(info->dev, "sdp cable is connecetd\n");
notify_otg = true;
notify_charger = true;
cable = EXTCON_SLOW_CHARGER;
break;
case DET_STAT_CDP:
dev_dbg(info->dev, "cdp cable is connecetd\n");
notify_otg = true;
notify_charger = true;
cable = EXTCON_CHARGE_DOWNSTREAM;
break;
case DET_STAT_DCP:
dev_dbg(info->dev, "dcp cable is connecetd\n");
notify_charger = true;
cable = EXTCON_FAST_CHARGER;
break;
default:
dev_warn(info->dev,
"disconnect or unknown or ID event\n");
}
notify_otg:
if (notify_otg) {
/*
* If VBUS is absent Connect D+/D- lines to PMIC for BC
* detection. Else connect them to SOC for USB communication.
*/
if (info->pdata->gpio_mux_cntl)
gpiod_set_value(info->pdata->gpio_mux_cntl,
vbus_attach ? EXTCON_GPIO_MUX_SEL_SOC
: EXTCON_GPIO_MUX_SEL_PMIC);
atomic_notifier_call_chain(&info->otg->notifier,
vbus_attach ? USB_EVENT_VBUS : USB_EVENT_NONE, NULL);
}
if (notify_charger)
extcon_set_cable_state_(info->edev, cable, vbus_attach);
/* Clear the flags on disconnect event */
if (!vbus_attach)
notify_otg = notify_charger = false;
return 0;
dev_det_ret:
if (ret < 0)
dev_err(info->dev, "failed to detect BC Mod\n");
return ret;
}
static irqreturn_t axp288_extcon_isr(int irq, void *data)
{
struct axp288_extcon_info *info = data;
int ret;
ret = axp288_handle_chrg_det_event(info);
if (ret < 0)
dev_err(info->dev, "failed to handle the interrupt\n");
return IRQ_HANDLED;
}
static void axp288_extcon_enable_irq(struct axp288_extcon_info *info)
{
/* Unmask VBUS interrupt */
regmap_write(info->regmap, AXP288_PWRSRC_IRQ_CFG_REG,
PWRSRC_IRQ_CFG_MASK);
regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
BC_GLOBAL_RUN, 0);
/* Unmask the BC1.2 complete interrupts */
regmap_write(info->regmap, AXP288_BC12_IRQ_CFG_REG, BC12_IRQ_CFG_MASK);
/* Enable the charger detection logic */
regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
BC_GLOBAL_RUN, BC_GLOBAL_RUN);
}
static int axp288_extcon_probe(struct platform_device *pdev)
{
struct axp288_extcon_info *info;
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
int ret, i, pirq, gpio;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
info->dev = &pdev->dev;
info->regmap = axp20x->regmap;
info->regmap_irqc = axp20x->regmap_irqc;
info->pdata = pdev->dev.platform_data;
if (!info->pdata) {
/* Try ACPI provided pdata via device properties */
if (!device_property_present(&pdev->dev,
"axp288_extcon_data\n"))
dev_err(&pdev->dev, "failed to get platform data\n");
return -ENODEV;
}
platform_set_drvdata(pdev, info);
axp288_extcon_log_rsi(info);
/* Initialize extcon device */
info->edev = devm_extcon_dev_allocate(&pdev->dev,
axp288_extcon_cables);
if (IS_ERR(info->edev)) {
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
return PTR_ERR(info->edev);
}
/* Register extcon device */
ret = devm_extcon_dev_register(&pdev->dev, info->edev);
if (ret) {
dev_err(&pdev->dev, "failed to register extcon device\n");
return ret;
}
/* Get otg transceiver phy */
info->otg = usb_get_phy(USB_PHY_TYPE_USB2);
if (IS_ERR(info->otg)) {
dev_err(&pdev->dev, "failed to get otg transceiver\n");
return PTR_ERR(info->otg);
}
/* Set up gpio control for USB Mux */
if (info->pdata->gpio_mux_cntl) {
gpio = desc_to_gpio(info->pdata->gpio_mux_cntl);
ret = gpio_request(gpio, "USB_MUX");
if (ret < 0) {
dev_err(&pdev->dev,
"failed to request the gpio=%d\n", gpio);
goto gpio_req_failed;
}
gpiod_direction_output(info->pdata->gpio_mux_cntl,
EXTCON_GPIO_MUX_SEL_PMIC);
}
for (i = 0; i < EXTCON_IRQ_END; i++) {
pirq = platform_get_irq(pdev, i);
info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq);
if (info->irq[i] < 0) {
dev_err(&pdev->dev,
"failed to get virtual interrupt=%d\n", pirq);
ret = info->irq[i];
goto gpio_req_failed;
}
ret = devm_request_threaded_irq(&pdev->dev, info->irq[i],
NULL, axp288_extcon_isr,
IRQF_ONESHOT | IRQF_NO_SUSPEND,
pdev->name, info);
if (ret) {
dev_err(&pdev->dev, "failed to request interrupt=%d\n",
info->irq[i]);
goto gpio_req_failed;
}
}
/* Enable interrupts */
axp288_extcon_enable_irq(info);
return 0;
gpio_req_failed:
usb_put_phy(info->otg);
return ret;
}
static int axp288_extcon_remove(struct platform_device *pdev)
{
struct axp288_extcon_info *info = platform_get_drvdata(pdev);
usb_put_phy(info->otg);
return 0;
}
static struct platform_driver axp288_extcon_driver = {
.probe = axp288_extcon_probe,
.remove = axp288_extcon_remove,
.driver = {
.name = "axp288_extcon",
},
};
module_platform_driver(axp288_extcon_driver);
MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>");
MODULE_DESCRIPTION("X-Powers AXP288 extcon driver");
MODULE_LICENSE("GPL v2");
...@@ -104,7 +104,6 @@ static int gpio_extcon_probe(struct platform_device *pdev) ...@@ -104,7 +104,6 @@ static int gpio_extcon_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to allocate extcon device\n"); dev_err(&pdev->dev, "failed to allocate extcon device\n");
return -ENOMEM; return -ENOMEM;
} }
extcon_data->edev->name = pdata->name;
extcon_data->gpio = pdata->gpio; extcon_data->gpio = pdata->gpio;
extcon_data->gpio_active_low = pdata->gpio_active_low; extcon_data->gpio_active_low = pdata->gpio_active_low;
......
...@@ -148,33 +148,14 @@ enum max14577_muic_acc_type { ...@@ -148,33 +148,14 @@ enum max14577_muic_acc_type {
MAX14577_MUIC_ADC_OPEN, MAX14577_MUIC_ADC_OPEN,
}; };
/* max14577 MUIC device support below list of accessories(external connector) */ static const unsigned int max14577_extcon_cable[] = {
enum { EXTCON_USB,
EXTCON_CABLE_USB = 0, EXTCON_TA,
EXTCON_CABLE_TA, EXTCON_FAST_CHARGER,
EXTCON_CABLE_FAST_CHARGER, EXTCON_SLOW_CHARGER,
EXTCON_CABLE_SLOW_CHARGER, EXTCON_CHARGE_DOWNSTREAM,
EXTCON_CABLE_CHARGE_DOWNSTREAM, EXTCON_JIG,
EXTCON_CABLE_JIG_USB_ON, EXTCON_NONE,
EXTCON_CABLE_JIG_USB_OFF,
EXTCON_CABLE_JIG_UART_OFF,
EXTCON_CABLE_JIG_UART_ON,
_EXTCON_CABLE_NUM,
};
static const char *max14577_extcon_cable[] = {
[EXTCON_CABLE_USB] = "USB",
[EXTCON_CABLE_TA] = "TA",
[EXTCON_CABLE_FAST_CHARGER] = "Fast-charger",
[EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger",
[EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream",
[EXTCON_CABLE_JIG_USB_ON] = "JIG-USB-ON",
[EXTCON_CABLE_JIG_USB_OFF] = "JIG-USB-OFF",
[EXTCON_CABLE_JIG_UART_OFF] = "JIG-UART-OFF",
[EXTCON_CABLE_JIG_UART_ON] = "JIG-UART-ON",
NULL,
}; };
/* /*
...@@ -348,7 +329,6 @@ static int max14577_muic_get_cable_type(struct max14577_muic_info *info, ...@@ -348,7 +329,6 @@ static int max14577_muic_get_cable_type(struct max14577_muic_info *info,
static int max14577_muic_jig_handler(struct max14577_muic_info *info, static int max14577_muic_jig_handler(struct max14577_muic_info *info,
int cable_type, bool attached) int cable_type, bool attached)
{ {
char cable_name[32];
int ret = 0; int ret = 0;
u8 path = CTRL1_SW_OPEN; u8 path = CTRL1_SW_OPEN;
...@@ -358,18 +338,12 @@ static int max14577_muic_jig_handler(struct max14577_muic_info *info, ...@@ -358,18 +338,12 @@ static int max14577_muic_jig_handler(struct max14577_muic_info *info,
switch (cable_type) { switch (cable_type) {
case MAX14577_MUIC_ADC_FACTORY_MODE_USB_OFF: /* ADC_JIG_USB_OFF */ case MAX14577_MUIC_ADC_FACTORY_MODE_USB_OFF: /* ADC_JIG_USB_OFF */
/* PATH:AP_USB */
strcpy(cable_name, "JIG-USB-OFF");
path = CTRL1_SW_USB;
break;
case MAX14577_MUIC_ADC_FACTORY_MODE_USB_ON: /* ADC_JIG_USB_ON */ case MAX14577_MUIC_ADC_FACTORY_MODE_USB_ON: /* ADC_JIG_USB_ON */
/* PATH:AP_USB */ /* PATH:AP_USB */
strcpy(cable_name, "JIG-USB-ON");
path = CTRL1_SW_USB; path = CTRL1_SW_USB;
break; break;
case MAX14577_MUIC_ADC_FACTORY_MODE_UART_OFF: /* ADC_JIG_UART_OFF */ case MAX14577_MUIC_ADC_FACTORY_MODE_UART_OFF: /* ADC_JIG_UART_OFF */
/* PATH:AP_UART */ /* PATH:AP_UART */
strcpy(cable_name, "JIG-UART-OFF");
path = CTRL1_SW_UART; path = CTRL1_SW_UART;
break; break;
default: default:
...@@ -382,7 +356,7 @@ static int max14577_muic_jig_handler(struct max14577_muic_info *info, ...@@ -382,7 +356,7 @@ static int max14577_muic_jig_handler(struct max14577_muic_info *info,
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, cable_name, attached); extcon_set_cable_state_(info->edev, EXTCON_JIG, attached);
return 0; return 0;
} }
...@@ -479,20 +453,22 @@ static int max14577_muic_chg_handler(struct max14577_muic_info *info) ...@@ -479,20 +453,22 @@ static int max14577_muic_chg_handler(struct max14577_muic_info *info)
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, "USB", attached); extcon_set_cable_state_(info->edev, EXTCON_USB, attached);
break; break;
case MAX14577_CHARGER_TYPE_DEDICATED_CHG: case MAX14577_CHARGER_TYPE_DEDICATED_CHG:
extcon_set_cable_state(info->edev, "TA", attached); extcon_set_cable_state_(info->edev, EXTCON_TA, attached);
break; break;
case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT: case MAX14577_CHARGER_TYPE_DOWNSTREAM_PORT:
extcon_set_cable_state(info->edev, extcon_set_cable_state_(info->edev, EXTCON_CHARGE_DOWNSTREAM,
"Charge-downstream", attached); attached);
break; break;
case MAX14577_CHARGER_TYPE_SPECIAL_500MA: case MAX14577_CHARGER_TYPE_SPECIAL_500MA:
extcon_set_cable_state(info->edev, "Slow-charger", attached); extcon_set_cable_state_(info->edev, EXTCON_SLOW_CHARGER,
attached);
break; break;
case MAX14577_CHARGER_TYPE_SPECIAL_1A: case MAX14577_CHARGER_TYPE_SPECIAL_1A:
extcon_set_cable_state(info->edev, "Fast-charger", attached); extcon_set_cable_state_(info->edev, EXTCON_FAST_CHARGER,
attached);
break; break;
case MAX14577_CHARGER_TYPE_NONE: case MAX14577_CHARGER_TYPE_NONE:
case MAX14577_CHARGER_TYPE_DEAD_BATTERY: case MAX14577_CHARGER_TYPE_DEAD_BATTERY:
...@@ -742,8 +718,6 @@ static int max14577_muic_probe(struct platform_device *pdev) ...@@ -742,8 +718,6 @@ static int max14577_muic_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
} }
info->edev->name = dev_name(&pdev->dev);
ret = devm_extcon_dev_register(&pdev->dev, info->edev); ret = devm_extcon_dev_register(&pdev->dev, info->edev);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to register extcon device\n"); dev_err(&pdev->dev, "failed to register extcon device\n");
......
...@@ -200,44 +200,17 @@ enum max77693_muic_acc_type { ...@@ -200,44 +200,17 @@ enum max77693_muic_acc_type {
/* /*
* MAX77693 MUIC device support below list of accessories(external connector) * MAX77693 MUIC device support below list of accessories(external connector)
*/ */
enum { static const unsigned int max77693_extcon_cable[] = {
EXTCON_CABLE_USB = 0, EXTCON_USB,
EXTCON_CABLE_USB_HOST, EXTCON_USB_HOST,
EXTCON_CABLE_TA, EXTCON_TA,
EXTCON_CABLE_FAST_CHARGER, EXTCON_FAST_CHARGER,
EXTCON_CABLE_SLOW_CHARGER, EXTCON_SLOW_CHARGER,
EXTCON_CABLE_CHARGE_DOWNSTREAM, EXTCON_CHARGE_DOWNSTREAM,
EXTCON_CABLE_MHL, EXTCON_MHL,
EXTCON_CABLE_MHL_TA, EXTCON_JIG,
EXTCON_CABLE_JIG_USB_ON, EXTCON_DOCK,
EXTCON_CABLE_JIG_USB_OFF, EXTCON_NONE,
EXTCON_CABLE_JIG_UART_OFF,
EXTCON_CABLE_JIG_UART_ON,
EXTCON_CABLE_DOCK_SMART,
EXTCON_CABLE_DOCK_DESK,
EXTCON_CABLE_DOCK_AUDIO,
_EXTCON_CABLE_NUM,
};
static const char *max77693_extcon_cable[] = {
[EXTCON_CABLE_USB] = "USB",
[EXTCON_CABLE_USB_HOST] = "USB-Host",
[EXTCON_CABLE_TA] = "TA",
[EXTCON_CABLE_FAST_CHARGER] = "Fast-charger",
[EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger",
[EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream",
[EXTCON_CABLE_MHL] = "MHL",
[EXTCON_CABLE_MHL_TA] = "MHL-TA",
[EXTCON_CABLE_JIG_USB_ON] = "JIG-USB-ON",
[EXTCON_CABLE_JIG_USB_OFF] = "JIG-USB-OFF",
[EXTCON_CABLE_JIG_UART_OFF] = "JIG-UART-OFF",
[EXTCON_CABLE_JIG_UART_ON] = "JIG-UART-ON",
[EXTCON_CABLE_DOCK_SMART] = "Dock-Smart",
[EXTCON_CABLE_DOCK_DESK] = "Dock-Desk",
[EXTCON_CABLE_DOCK_AUDIO] = "Dock-Audio",
NULL,
}; };
/* /*
...@@ -484,7 +457,7 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info, ...@@ -484,7 +457,7 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info,
int ret = 0; int ret = 0;
int vbvolt; int vbvolt;
bool cable_attached; bool cable_attached;
char dock_name[CABLE_NAME_MAX]; unsigned int dock_id;
dev_info(info->dev, dev_info(info->dev,
"external connector is %s (adc:0x%02x)\n", "external connector is %s (adc:0x%02x)\n",
...@@ -507,15 +480,15 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info, ...@@ -507,15 +480,15 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info,
} }
/* /*
* Notify Dock-Smart/MHL state. * Notify Dock/MHL state.
* - Dock-Smart device include three type of cable which * - Dock device include three type of cable which
* are HDMI, USB for mouse/keyboard and micro-usb port * are HDMI, USB for mouse/keyboard and micro-usb port
* for USB/TA cable. Dock-Smart device need always exteranl * for USB/TA cable. Dock device need always exteranl
* power supply(USB/TA cable through micro-usb cable). Dock- * power supply(USB/TA cable through micro-usb cable). Dock
* Smart device support screen output of target to separate * device support screen output of target to separate
* monitor and mouse/keyboard for desktop mode. * monitor and mouse/keyboard for desktop mode.
* *
* Features of 'USB/TA cable with Dock-Smart device' * Features of 'USB/TA cable with Dock device'
* - Support MHL * - Support MHL
* - Support external output feature of audio * - Support external output feature of audio
* - Support charging through micro-usb port without data * - Support charging through micro-usb port without data
...@@ -529,16 +502,16 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info, ...@@ -529,16 +502,16 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info,
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, "Dock-Smart", attached); extcon_set_cable_state_(info->edev, EXTCON_DOCK, attached);
extcon_set_cable_state(info->edev, "MHL", attached); extcon_set_cable_state_(info->edev, EXTCON_MHL, attached);
goto out; goto out;
case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: /* Dock-Desk */ case MAX77693_MUIC_ADC_AUDIO_MODE_REMOTE: /* Dock-Desk */
strcpy(dock_name, "Dock-Desk"); dock_id = EXTCON_DOCK;
break; break;
case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */ case MAX77693_MUIC_ADC_AV_CABLE_NOLOAD: /* Dock-Audio */
strcpy(dock_name, "Dock-Audio"); dock_id = EXTCON_DOCK;
if (!attached) if (!attached)
extcon_set_cable_state(info->edev, "USB", false); extcon_set_cable_state_(info->edev, EXTCON_USB, false);
break; break;
default: default:
dev_err(info->dev, "failed to detect %s dock device\n", dev_err(info->dev, "failed to detect %s dock device\n",
...@@ -550,7 +523,7 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info, ...@@ -550,7 +523,7 @@ static int max77693_muic_dock_handler(struct max77693_muic_info *info,
ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached); ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached);
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, dock_name, attached); extcon_set_cable_state_(info->edev, dock_id, attached);
out: out:
return 0; return 0;
...@@ -615,20 +588,19 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info) ...@@ -615,20 +588,19 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info)
ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached); ret = max77693_muic_set_path(info, CONTROL1_SW_USB, attached);
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, "USB-Host", attached); extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, attached);
break; break;
case MAX77693_MUIC_GND_AV_CABLE_LOAD: case MAX77693_MUIC_GND_AV_CABLE_LOAD:
/* Audio Video Cable with load, PATH:AUDIO */ /* Audio Video Cable with load, PATH:AUDIO */
ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached); ret = max77693_muic_set_path(info, CONTROL1_SW_AUDIO, attached);
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, extcon_set_cable_state_(info->edev, EXTCON_USB, attached);
"Audio-video-load", attached);
break; break;
case MAX77693_MUIC_GND_MHL: case MAX77693_MUIC_GND_MHL:
case MAX77693_MUIC_GND_MHL_VB: case MAX77693_MUIC_GND_MHL_VB:
/* MHL or MHL with USB/TA cable */ /* MHL or MHL with USB/TA cable */
extcon_set_cable_state(info->edev, "MHL", attached); extcon_set_cable_state_(info->edev, EXTCON_MHL, attached);
break; break;
default: default:
dev_err(info->dev, "failed to detect %s cable of gnd type\n", dev_err(info->dev, "failed to detect %s cable of gnd type\n",
...@@ -642,7 +614,6 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info) ...@@ -642,7 +614,6 @@ static int max77693_muic_adc_ground_handler(struct max77693_muic_info *info)
static int max77693_muic_jig_handler(struct max77693_muic_info *info, static int max77693_muic_jig_handler(struct max77693_muic_info *info,
int cable_type, bool attached) int cable_type, bool attached)
{ {
char cable_name[32];
int ret = 0; int ret = 0;
u8 path = CONTROL1_SW_OPEN; u8 path = CONTROL1_SW_OPEN;
...@@ -652,23 +623,13 @@ static int max77693_muic_jig_handler(struct max77693_muic_info *info, ...@@ -652,23 +623,13 @@ static int max77693_muic_jig_handler(struct max77693_muic_info *info,
switch (cable_type) { switch (cable_type) {
case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF: /* ADC_JIG_USB_OFF */ case MAX77693_MUIC_ADC_FACTORY_MODE_USB_OFF: /* ADC_JIG_USB_OFF */
/* PATH:AP_USB */
strcpy(cable_name, "JIG-USB-OFF");
path = CONTROL1_SW_USB;
break;
case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON: /* ADC_JIG_USB_ON */ case MAX77693_MUIC_ADC_FACTORY_MODE_USB_ON: /* ADC_JIG_USB_ON */
/* PATH:AP_USB */ /* PATH:AP_USB */
strcpy(cable_name, "JIG-USB-ON");
path = CONTROL1_SW_USB; path = CONTROL1_SW_USB;
break; break;
case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF: /* ADC_JIG_UART_OFF */ case MAX77693_MUIC_ADC_FACTORY_MODE_UART_OFF: /* ADC_JIG_UART_OFF */
/* PATH:AP_UART */
strcpy(cable_name, "JIG-UART-OFF");
path = CONTROL1_SW_UART;
break;
case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* ADC_JIG_UART_ON */ case MAX77693_MUIC_ADC_FACTORY_MODE_UART_ON: /* ADC_JIG_UART_ON */
/* PATH:AP_UART */ /* PATH:AP_UART */
strcpy(cable_name, "JIG-UART-ON");
path = CONTROL1_SW_UART; path = CONTROL1_SW_UART;
break; break;
default: default:
...@@ -681,7 +642,7 @@ static int max77693_muic_jig_handler(struct max77693_muic_info *info, ...@@ -681,7 +642,7 @@ static int max77693_muic_jig_handler(struct max77693_muic_info *info,
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, cable_name, attached); extcon_set_cable_state_(info->edev, EXTCON_JIG, attached);
return 0; return 0;
} }
...@@ -823,22 +784,22 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) ...@@ -823,22 +784,22 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
case MAX77693_MUIC_GND_MHL: case MAX77693_MUIC_GND_MHL:
case MAX77693_MUIC_GND_MHL_VB: case MAX77693_MUIC_GND_MHL_VB:
/* /*
* MHL cable with MHL-TA(USB/TA) cable * MHL cable with USB/TA cable
* - MHL cable include two port(HDMI line and separate * - MHL cable include two port(HDMI line and separate
* micro-usb port. When the target connect MHL cable, * micro-usb port. When the target connect MHL cable,
* extcon driver check whether MHL-TA(USB/TA) cable is * extcon driver check whether USB/TA cable is
* connected. If MHL-TA cable is connected, extcon * connected. If USB/TA cable is connected, extcon
* driver notify state to notifiee for charging battery. * driver notify state to notifiee for charging battery.
* *
* Features of 'MHL-TA(USB/TA) with MHL cable' * Features of 'USB/TA with MHL cable'
* - Support MHL * - Support MHL
* - Support charging through micro-usb port without * - Support charging through micro-usb port without
* data connection * data connection
*/ */
extcon_set_cable_state(info->edev, "MHL-TA", attached); extcon_set_cable_state_(info->edev, EXTCON_TA, attached);
if (!cable_attached) if (!cable_attached)
extcon_set_cable_state(info->edev, extcon_set_cable_state_(info->edev, EXTCON_MHL,
"MHL", cable_attached); cable_attached);
break; break;
} }
...@@ -861,11 +822,12 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) ...@@ -861,11 +822,12 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
* - Support charging through micro-usb port without * - Support charging through micro-usb port without
* data connection. * data connection.
*/ */
extcon_set_cable_state(info->edev, "USB", attached); extcon_set_cable_state_(info->edev, EXTCON_USB,
attached);
if (!cable_attached) if (!cable_attached)
extcon_set_cable_state(info->edev, "Dock-Audio", extcon_set_cable_state_(info->edev, EXTCON_DOCK,
cable_attached); cable_attached);
break; break;
case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */ case MAX77693_MUIC_ADC_RESERVED_ACC_3: /* Dock-Smart */
/* /*
...@@ -893,10 +855,10 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) ...@@ -893,10 +855,10 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, "Dock-Smart", extcon_set_cable_state_(info->edev, EXTCON_DOCK,
attached); attached);
extcon_set_cable_state(info->edev, "MHL", attached); extcon_set_cable_state_(info->edev, EXTCON_MHL,
attached);
break; break;
} }
...@@ -929,23 +891,26 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) ...@@ -929,23 +891,26 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info)
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, "USB", attached); extcon_set_cable_state_(info->edev, EXTCON_USB,
attached);
break; break;
case MAX77693_CHARGER_TYPE_DEDICATED_CHG: case MAX77693_CHARGER_TYPE_DEDICATED_CHG:
/* Only TA cable */ /* Only TA cable */
extcon_set_cable_state(info->edev, "TA", attached); extcon_set_cable_state_(info->edev, EXTCON_TA, attached);
break; break;
} }
break; break;
case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT: case MAX77693_CHARGER_TYPE_DOWNSTREAM_PORT:
extcon_set_cable_state(info->edev, extcon_set_cable_state_(info->edev, EXTCON_CHARGE_DOWNSTREAM,
"Charge-downstream", attached); attached);
break; break;
case MAX77693_CHARGER_TYPE_APPLE_500MA: case MAX77693_CHARGER_TYPE_APPLE_500MA:
extcon_set_cable_state(info->edev, "Slow-charger", attached); extcon_set_cable_state_(info->edev, EXTCON_SLOW_CHARGER,
attached);
break; break;
case MAX77693_CHARGER_TYPE_APPLE_1A_2A: case MAX77693_CHARGER_TYPE_APPLE_1A_2A:
extcon_set_cable_state(info->edev, "Fast-charger", attached); extcon_set_cable_state_(info->edev, EXTCON_FAST_CHARGER,
attached);
break; break;
case MAX77693_CHARGER_TYPE_DEAD_BATTERY: case MAX77693_CHARGER_TYPE_DEAD_BATTERY:
break; break;
...@@ -1182,7 +1147,6 @@ static int max77693_muic_probe(struct platform_device *pdev) ...@@ -1182,7 +1147,6 @@ static int max77693_muic_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
return -ENOMEM; return -ENOMEM;
} }
info->edev->name = DEV_NAME;
ret = devm_extcon_dev_register(&pdev->dev, info->edev); ret = devm_extcon_dev_register(&pdev->dev, info->edev);
if (ret) { if (ret) {
......
...@@ -118,36 +118,16 @@ enum max77843_muic_charger_type { ...@@ -118,36 +118,16 @@ enum max77843_muic_charger_type {
MAX77843_MUIC_CHG_GND, MAX77843_MUIC_CHG_GND,
}; };
enum { static const unsigned int max77843_extcon_cable[] = {
MAX77843_CABLE_USB = 0, EXTCON_USB,
MAX77843_CABLE_USB_HOST, EXTCON_USB_HOST,
MAX77843_CABLE_TA, EXTCON_TA,
MAX77843_CABLE_CHARGE_DOWNSTREAM, EXTCON_CHARGE_DOWNSTREAM,
MAX77843_CABLE_FAST_CHARGER, EXTCON_FAST_CHARGER,
MAX77843_CABLE_SLOW_CHARGER, EXTCON_SLOW_CHARGER,
MAX77843_CABLE_MHL, EXTCON_MHL,
MAX77843_CABLE_MHL_TA, EXTCON_JIG,
MAX77843_CABLE_JIG_USB_ON, EXTCON_NONE,
MAX77843_CABLE_JIG_USB_OFF,
MAX77843_CABLE_JIG_UART_ON,
MAX77843_CABLE_JIG_UART_OFF,
MAX77843_CABLE_NUM,
};
static const char *max77843_extcon_cable[] = {
[MAX77843_CABLE_USB] = "USB",
[MAX77843_CABLE_USB_HOST] = "USB-HOST",
[MAX77843_CABLE_TA] = "TA",
[MAX77843_CABLE_CHARGE_DOWNSTREAM] = "CHARGER-DOWNSTREAM",
[MAX77843_CABLE_FAST_CHARGER] = "FAST-CHARGER",
[MAX77843_CABLE_SLOW_CHARGER] = "SLOW-CHARGER",
[MAX77843_CABLE_MHL] = "MHL",
[MAX77843_CABLE_MHL_TA] = "MHL-TA",
[MAX77843_CABLE_JIG_USB_ON] = "JIG-USB-ON",
[MAX77843_CABLE_JIG_USB_OFF] = "JIG-USB-OFF",
[MAX77843_CABLE_JIG_UART_ON] = "JIG-UART-ON",
[MAX77843_CABLE_JIG_UART_OFF] = "JIG-UART-OFF",
}; };
struct max77843_muic_irq { struct max77843_muic_irq {
...@@ -362,7 +342,7 @@ static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info) ...@@ -362,7 +342,7 @@ static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info)
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, "USB-HOST", attached); extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, attached);
break; break;
case MAX77843_MUIC_GND_MHL_VB: case MAX77843_MUIC_GND_MHL_VB:
case MAX77843_MUIC_GND_MHL: case MAX77843_MUIC_GND_MHL:
...@@ -370,7 +350,7 @@ static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info) ...@@ -370,7 +350,7 @@ static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info)
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, "MHL", attached); extcon_set_cable_state_(info->edev, EXTCON_MHL, attached);
break; break;
default: default:
dev_err(info->dev, "failed to detect %s accessory(gnd:0x%x)\n", dev_err(info->dev, "failed to detect %s accessory(gnd:0x%x)\n",
...@@ -385,36 +365,29 @@ static int max77843_muic_jig_handler(struct max77843_muic_info *info, ...@@ -385,36 +365,29 @@ static int max77843_muic_jig_handler(struct max77843_muic_info *info,
int cable_type, bool attached) int cable_type, bool attached)
{ {
int ret; int ret;
u8 path = CONTROL1_SW_OPEN;
dev_dbg(info->dev, "external connector is %s (adc:0x%02x)\n", dev_dbg(info->dev, "external connector is %s (adc:0x%02x)\n",
attached ? "attached" : "detached", cable_type); attached ? "attached" : "detached", cable_type);
switch (cable_type) { switch (cable_type) {
case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF: case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
ret = max77843_muic_set_path(info, CONTROL1_SW_USB, attached);
if (ret < 0)
return ret;
extcon_set_cable_state(info->edev, "JIG-USB-OFF", attached);
break;
case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON: case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
ret = max77843_muic_set_path(info, CONTROL1_SW_USB, attached); path = CONTROL1_SW_USB;
if (ret < 0)
return ret;
extcon_set_cable_state(info->edev, "JIG-USB-ON", attached);
break; break;
case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF: case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
ret = max77843_muic_set_path(info, CONTROL1_SW_UART, attached); path = CONTROL1_SW_UART;
if (ret < 0)
return ret;
extcon_set_cable_state(info->edev, "JIG-UART-OFF", attached);
break; break;
default: default:
ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); return -EINVAL;
if (ret < 0)
return ret;
break;
} }
ret = max77843_muic_set_path(info, path, attached);
if (ret < 0)
return ret;
extcon_set_cable_state_(info->edev, EXTCON_JIG, attached);
return 0; return 0;
} }
...@@ -505,36 +478,38 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) ...@@ -505,36 +478,38 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info)
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, "USB", attached); extcon_set_cable_state_(info->edev, EXTCON_USB, attached);
break; break;
case MAX77843_MUIC_CHG_DOWNSTREAM: case MAX77843_MUIC_CHG_DOWNSTREAM:
ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, extcon_set_cable_state_(info->edev, EXTCON_CHARGE_DOWNSTREAM,
"CHARGER-DOWNSTREAM", attached); attached);
break; break;
case MAX77843_MUIC_CHG_DEDICATED: case MAX77843_MUIC_CHG_DEDICATED:
ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, "TA", attached); extcon_set_cable_state_(info->edev, EXTCON_TA, attached);
break; break;
case MAX77843_MUIC_CHG_SPECIAL_500MA: case MAX77843_MUIC_CHG_SPECIAL_500MA:
ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, "SLOW-CHAREGER", attached); extcon_set_cable_state_(info->edev, EXTCON_SLOW_CHARGER,
attached);
break; break;
case MAX77843_MUIC_CHG_SPECIAL_1A: case MAX77843_MUIC_CHG_SPECIAL_1A:
ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached); ret = max77843_muic_set_path(info, CONTROL1_SW_OPEN, attached);
if (ret < 0) if (ret < 0)
return ret; return ret;
extcon_set_cable_state(info->edev, "FAST-CHARGER", attached); extcon_set_cable_state_(info->edev, EXTCON_FAST_CHARGER,
attached);
break; break;
case MAX77843_MUIC_CHG_GND: case MAX77843_MUIC_CHG_GND:
gnd_type = max77843_muic_get_cable_type(info, gnd_type = max77843_muic_get_cable_type(info,
...@@ -542,9 +517,9 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info) ...@@ -542,9 +517,9 @@ static int max77843_muic_chg_handler(struct max77843_muic_info *info)
/* Charger cable on MHL accessory is attach or detach */ /* Charger cable on MHL accessory is attach or detach */
if (gnd_type == MAX77843_MUIC_GND_MHL_VB) if (gnd_type == MAX77843_MUIC_GND_MHL_VB)
extcon_set_cable_state(info->edev, "MHL-TA", true); extcon_set_cable_state_(info->edev, EXTCON_TA, true);
else if (gnd_type == MAX77843_MUIC_GND_MHL) else if (gnd_type == MAX77843_MUIC_GND_MHL)
extcon_set_cable_state(info->edev, "MHL-TA", false); extcon_set_cable_state_(info->edev, EXTCON_TA, false);
break; break;
case MAX77843_MUIC_CHG_NONE: case MAX77843_MUIC_CHG_NONE:
break; break;
......
...@@ -145,34 +145,17 @@ struct max8997_muic_info { ...@@ -145,34 +145,17 @@ struct max8997_muic_info {
int path_uart; int path_uart;
}; };
enum { static const unsigned int max8997_extcon_cable[] = {
EXTCON_CABLE_USB = 0, EXTCON_USB,
EXTCON_CABLE_USB_HOST, EXTCON_USB_HOST,
EXTCON_CABLE_TA, EXTCON_TA,
EXTCON_CABLE_FAST_CHARGER, EXTCON_FAST_CHARGER,
EXTCON_CABLE_SLOW_CHARGER, EXTCON_SLOW_CHARGER,
EXTCON_CABLE_CHARGE_DOWNSTREAM, EXTCON_CHARGE_DOWNSTREAM,
EXTCON_CABLE_MHL, EXTCON_MHL,
EXTCON_CABLE_DOCK_DESK, EXTCON_DOCK,
EXTCON_CABLE_DOCK_CARD, EXTCON_JIG,
EXTCON_CABLE_JIG, EXTCON_NONE,
_EXTCON_CABLE_NUM,
};
static const char *max8997_extcon_cable[] = {
[EXTCON_CABLE_USB] = "USB",
[EXTCON_CABLE_USB_HOST] = "USB-Host",
[EXTCON_CABLE_TA] = "TA",
[EXTCON_CABLE_FAST_CHARGER] = "Fast-charger",
[EXTCON_CABLE_SLOW_CHARGER] = "Slow-charger",
[EXTCON_CABLE_CHARGE_DOWNSTREAM] = "Charge-downstream",
[EXTCON_CABLE_MHL] = "MHL",
[EXTCON_CABLE_DOCK_DESK] = "Dock-Desk",
[EXTCON_CABLE_DOCK_CARD] = "Dock-Card",
[EXTCON_CABLE_JIG] = "JIG",
NULL,
}; };
/* /*
...@@ -347,10 +330,10 @@ static int max8997_muic_handle_usb(struct max8997_muic_info *info, ...@@ -347,10 +330,10 @@ static int max8997_muic_handle_usb(struct max8997_muic_info *info,
switch (usb_type) { switch (usb_type) {
case MAX8997_USB_HOST: case MAX8997_USB_HOST:
extcon_set_cable_state(info->edev, "USB-Host", attached); extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, attached);
break; break;
case MAX8997_USB_DEVICE: case MAX8997_USB_DEVICE:
extcon_set_cable_state(info->edev, "USB", attached); extcon_set_cable_state_(info->edev, EXTCON_USB, attached);
break; break;
default: default:
dev_err(info->dev, "failed to detect %s usb cable\n", dev_err(info->dev, "failed to detect %s usb cable\n",
...@@ -374,10 +357,8 @@ static int max8997_muic_handle_dock(struct max8997_muic_info *info, ...@@ -374,10 +357,8 @@ static int max8997_muic_handle_dock(struct max8997_muic_info *info,
switch (cable_type) { switch (cable_type) {
case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD: case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD:
extcon_set_cable_state(info->edev, "Dock-desk", attached);
break;
case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON: case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON:
extcon_set_cable_state(info->edev, "Dock-card", attached); extcon_set_cable_state_(info->edev, EXTCON_DOCK, attached);
break; break;
default: default:
dev_err(info->dev, "failed to detect %s dock device\n", dev_err(info->dev, "failed to detect %s dock device\n",
...@@ -400,7 +381,7 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, ...@@ -400,7 +381,7 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
return ret; return ret;
} }
extcon_set_cable_state(info->edev, "JIG", attached); extcon_set_cable_state_(info->edev, EXTCON_JIG, attached);
return 0; return 0;
} }
...@@ -422,7 +403,7 @@ static int max8997_muic_adc_handler(struct max8997_muic_info *info) ...@@ -422,7 +403,7 @@ static int max8997_muic_adc_handler(struct max8997_muic_info *info)
return ret; return ret;
break; break;
case MAX8997_MUIC_ADC_MHL: case MAX8997_MUIC_ADC_MHL:
extcon_set_cable_state(info->edev, "MHL", attached); extcon_set_cable_state_(info->edev, EXTCON_MHL, attached);
break; break;
case MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF: case MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF:
case MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON: case MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON:
...@@ -505,17 +486,19 @@ static int max8997_muic_chg_handler(struct max8997_muic_info *info) ...@@ -505,17 +486,19 @@ static int max8997_muic_chg_handler(struct max8997_muic_info *info)
} }
break; break;
case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
extcon_set_cable_state(info->edev, extcon_set_cable_state_(info->edev, EXTCON_CHARGE_DOWNSTREAM,
"Charge-downstream", attached); attached);
break; break;
case MAX8997_CHARGER_TYPE_DEDICATED_CHG: case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
extcon_set_cable_state(info->edev, "TA", attached); extcon_set_cable_state_(info->edev, EXTCON_TA, attached);
break; break;
case MAX8997_CHARGER_TYPE_500MA: case MAX8997_CHARGER_TYPE_500MA:
extcon_set_cable_state(info->edev, "Slow-charger", attached); extcon_set_cable_state_(info->edev, EXTCON_SLOW_CHARGER,
attached);
break; break;
case MAX8997_CHARGER_TYPE_1A: case MAX8997_CHARGER_TYPE_1A:
extcon_set_cable_state(info->edev, "Fast-charger", attached); extcon_set_cable_state_(info->edev, EXTCON_FAST_CHARGER,
attached);
break; break;
default: default:
dev_err(info->dev, dev_err(info->dev,
...@@ -700,7 +683,6 @@ static int max8997_muic_probe(struct platform_device *pdev) ...@@ -700,7 +683,6 @@ static int max8997_muic_probe(struct platform_device *pdev)
ret = -ENOMEM; ret = -ENOMEM;
goto err_irq; goto err_irq;
} }
info->edev->name = DEV_NAME;
ret = devm_extcon_dev_register(&pdev->dev, info->edev); ret = devm_extcon_dev_register(&pdev->dev, info->edev);
if (ret) { if (ret) {
......
...@@ -29,10 +29,10 @@ ...@@ -29,10 +29,10 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
static const char *palmas_extcon_cable[] = { static const unsigned int palmas_extcon_cable[] = {
[0] = "USB", EXTCON_USB,
[1] = "USB-HOST", EXTCON_USB_HOST,
NULL, EXTCON_NONE,
}; };
static const int mutually_exclusive[] = {0x3, 0x0}; static const int mutually_exclusive[] = {0x3, 0x0};
...@@ -49,6 +49,7 @@ static void palmas_usb_wakeup(struct palmas *palmas, int enable) ...@@ -49,6 +49,7 @@ static void palmas_usb_wakeup(struct palmas *palmas, int enable)
static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb) static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
{ {
struct palmas_usb *palmas_usb = _palmas_usb; struct palmas_usb *palmas_usb = _palmas_usb;
struct extcon_dev *edev = palmas_usb->edev;
unsigned int vbus_line_state; unsigned int vbus_line_state;
palmas_read(palmas_usb->palmas, PALMAS_INTERRUPT_BASE, palmas_read(palmas_usb->palmas, PALMAS_INTERRUPT_BASE,
...@@ -57,7 +58,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb) ...@@ -57,7 +58,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
if (vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS) { if (vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS) {
if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) { if (palmas_usb->linkstat != PALMAS_USB_STATE_VBUS) {
palmas_usb->linkstat = PALMAS_USB_STATE_VBUS; palmas_usb->linkstat = PALMAS_USB_STATE_VBUS;
extcon_set_cable_state(palmas_usb->edev, "USB", true); extcon_set_cable_state_(edev, EXTCON_USB, true);
dev_info(palmas_usb->dev, "USB cable is attached\n"); dev_info(palmas_usb->dev, "USB cable is attached\n");
} else { } else {
dev_dbg(palmas_usb->dev, dev_dbg(palmas_usb->dev,
...@@ -66,7 +67,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb) ...@@ -66,7 +67,7 @@ static irqreturn_t palmas_vbus_irq_handler(int irq, void *_palmas_usb)
} else if (!(vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS)) { } else if (!(vbus_line_state & PALMAS_INT3_LINE_STATE_VBUS)) {
if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) { if (palmas_usb->linkstat == PALMAS_USB_STATE_VBUS) {
palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT; palmas_usb->linkstat = PALMAS_USB_STATE_DISCONNECT;
extcon_set_cable_state(palmas_usb->edev, "USB", false); extcon_set_cable_state_(edev, EXTCON_USB, false);
dev_info(palmas_usb->dev, "USB cable is detached\n"); dev_info(palmas_usb->dev, "USB cable is detached\n");
} else { } else {
dev_dbg(palmas_usb->dev, dev_dbg(palmas_usb->dev,
...@@ -81,6 +82,7 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb) ...@@ -81,6 +82,7 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
{ {
unsigned int set, id_src; unsigned int set, id_src;
struct palmas_usb *palmas_usb = _palmas_usb; struct palmas_usb *palmas_usb = _palmas_usb;
struct extcon_dev *edev = palmas_usb->edev;
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);
...@@ -93,7 +95,7 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb) ...@@ -93,7 +95,7 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
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_(edev, EXTCON_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)) { (id_src & PALMAS_USB_ID_INT_SRC_ID_FLOAT)) {
...@@ -101,17 +103,17 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb) ...@@ -101,17 +103,17 @@ static irqreturn_t palmas_id_irq_handler(int irq, void *_palmas_usb)
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);
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_(edev, EXTCON_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_ID) && } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_ID) &&
(!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) { (!(set & PALMAS_USB_ID_INT_SRC_ID_GND))) {
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_(edev, EXTCON_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) && } else if ((palmas_usb->linkstat == PALMAS_USB_STATE_DISCONNECT) &&
(id_src & PALMAS_USB_ID_INT_SRC_ID_GND)) { (id_src & PALMAS_USB_ID_INT_SRC_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_(edev, EXTCON_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");
} }
...@@ -193,7 +195,6 @@ static int palmas_usb_probe(struct platform_device *pdev) ...@@ -193,7 +195,6 @@ static int palmas_usb_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to allocate extcon device\n"); dev_err(&pdev->dev, "failed to allocate extcon device\n");
return -ENOMEM; return -ENOMEM;
} }
palmas_usb->edev->name = kstrdup(node->name, GFP_KERNEL);
palmas_usb->edev->mutually_exclusive = mutually_exclusive; palmas_usb->edev->mutually_exclusive = mutually_exclusive;
status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev); status = devm_extcon_dev_register(&pdev->dev, palmas_usb->edev);
......
...@@ -90,27 +90,12 @@ static struct reg_data rt8973a_reg_data[] = { ...@@ -90,27 +90,12 @@ static struct reg_data rt8973a_reg_data[] = {
}; };
/* List of detectable cables */ /* List of detectable cables */
enum { static const unsigned int rt8973a_extcon_cable[] = {
EXTCON_CABLE_USB = 0, EXTCON_USB,
EXTCON_CABLE_USB_HOST, EXTCON_USB_HOST,
EXTCON_CABLE_TA, EXTCON_TA,
EXTCON_CABLE_JIG_OFF_USB, EXTCON_JIG,
EXTCON_CABLE_JIG_ON_USB, EXTCON_NONE,
EXTCON_CABLE_JIG_OFF_UART,
EXTCON_CABLE_JIG_ON_UART,
EXTCON_CABLE_END,
};
static const char *rt8973a_extcon_cable[] = {
[EXTCON_CABLE_USB] = "USB",
[EXTCON_CABLE_USB_HOST] = "USB-Host",
[EXTCON_CABLE_TA] = "TA",
[EXTCON_CABLE_JIG_OFF_USB] = "JIG-USB-OFF",
[EXTCON_CABLE_JIG_ON_USB] = "JIG-USB-ON",
[EXTCON_CABLE_JIG_OFF_UART] = "JIG-UART-OFF",
[EXTCON_CABLE_JIG_ON_UART] = "JIG-UART-ON",
NULL,
}; };
/* Define OVP (Over Voltage Protection), OTP (Over Temperature Protection) */ /* Define OVP (Over Voltage Protection), OTP (Over Temperature Protection) */
...@@ -313,14 +298,11 @@ static int rt8973a_muic_cable_handler(struct rt8973a_muic_info *info, ...@@ -313,14 +298,11 @@ static int rt8973a_muic_cable_handler(struct rt8973a_muic_info *info,
enum rt8973a_event_type event) enum rt8973a_event_type event)
{ {
static unsigned int prev_cable_type; static unsigned int prev_cable_type;
const char **cable_names = info->edev->supported_cable;
unsigned int con_sw = DM_DP_SWITCH_UART; unsigned int con_sw = DM_DP_SWITCH_UART;
int ret, idx = 0, cable_type; int ret, cable_type;
unsigned int id;
bool attached = false; bool attached = false;
if (!cable_names)
return 0;
switch (event) { switch (event) {
case RT8973A_EVENT_ATTACH: case RT8973A_EVENT_ATTACH:
cable_type = rt8973a_muic_get_cable_type(info); cable_type = rt8973a_muic_get_cable_type(info);
...@@ -347,31 +329,25 @@ static int rt8973a_muic_cable_handler(struct rt8973a_muic_info *info, ...@@ -347,31 +329,25 @@ static int rt8973a_muic_cable_handler(struct rt8973a_muic_info *info,
switch (cable_type) { switch (cable_type) {
case RT8973A_MUIC_ADC_OTG: case RT8973A_MUIC_ADC_OTG:
idx = EXTCON_CABLE_USB_HOST; id = EXTCON_USB_HOST;
con_sw = DM_DP_SWITCH_USB; con_sw = DM_DP_SWITCH_USB;
break; break;
case RT8973A_MUIC_ADC_TA: case RT8973A_MUIC_ADC_TA:
idx = EXTCON_CABLE_TA; id = EXTCON_TA;
con_sw = DM_DP_SWITCH_OPEN; con_sw = DM_DP_SWITCH_OPEN;
break; break;
case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_USB: case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_USB:
idx = EXTCON_CABLE_JIG_OFF_USB;
con_sw = DM_DP_SWITCH_UART;
break;
case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_USB: case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_USB:
idx = EXTCON_CABLE_JIG_ON_USB; id = EXTCON_JIG;
con_sw = DM_DP_SWITCH_UART; con_sw = DM_DP_SWITCH_USB;
break; break;
case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_UART: case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_OFF_UART:
idx = EXTCON_CABLE_JIG_OFF_UART;
con_sw = DM_DP_SWITCH_UART;
break;
case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_UART: case RT8973A_MUIC_ADC_FACTORY_MODE_BOOT_ON_UART:
idx = EXTCON_CABLE_JIG_ON_UART; id = EXTCON_JIG;
con_sw = DM_DP_SWITCH_UART; con_sw = DM_DP_SWITCH_UART;
break; break;
case RT8973A_MUIC_ADC_USB: case RT8973A_MUIC_ADC_USB:
idx = EXTCON_CABLE_USB; id = EXTCON_USB;
con_sw = DM_DP_SWITCH_USB; con_sw = DM_DP_SWITCH_USB;
break; break;
case RT8973A_MUIC_ADC_OPEN: case RT8973A_MUIC_ADC_OPEN:
...@@ -421,7 +397,7 @@ static int rt8973a_muic_cable_handler(struct rt8973a_muic_info *info, ...@@ -421,7 +397,7 @@ static int rt8973a_muic_cable_handler(struct rt8973a_muic_info *info,
return ret; return ret;
/* Change the state of external accessory */ /* Change the state of external accessory */
extcon_set_cable_state(info->edev, cable_names[idx], attached); extcon_set_cable_state_(info->edev, id, attached);
return 0; return 0;
} }
...@@ -643,7 +619,6 @@ static int rt8973a_muic_i2c_probe(struct i2c_client *i2c, ...@@ -643,7 +619,6 @@ static int rt8973a_muic_i2c_probe(struct i2c_client *i2c,
dev_err(info->dev, "failed to allocate memory for extcon\n"); dev_err(info->dev, "failed to allocate memory for extcon\n");
return -ENOMEM; return -ENOMEM;
} }
info->edev->name = np->name;
/* Register extcon device */ /* Register extcon device */
ret = devm_extcon_dev_register(info->dev, info->edev); ret = devm_extcon_dev_register(info->dev, info->edev);
......
...@@ -92,19 +92,11 @@ static struct reg_data sm5502_reg_data[] = { ...@@ -92,19 +92,11 @@ static struct reg_data sm5502_reg_data[] = {
}; };
/* List of detectable cables */ /* List of detectable cables */
enum { static const unsigned int sm5502_extcon_cable[] = {
EXTCON_CABLE_USB = 0, EXTCON_USB,
EXTCON_CABLE_USB_HOST, EXTCON_USB_HOST,
EXTCON_CABLE_TA, EXTCON_TA,
EXTCON_NONE,
EXTCON_CABLE_END,
};
static const char *sm5502_extcon_cable[] = {
[EXTCON_CABLE_USB] = "USB",
[EXTCON_CABLE_USB_HOST] = "USB-Host",
[EXTCON_CABLE_TA] = "TA",
NULL,
}; };
/* Define supported accessory type */ /* Define supported accessory type */
...@@ -377,16 +369,12 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, ...@@ -377,16 +369,12 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
bool attached) bool attached)
{ {
static unsigned int prev_cable_type = SM5502_MUIC_ADC_GROUND; static unsigned int prev_cable_type = SM5502_MUIC_ADC_GROUND;
const char **cable_names = info->edev->supported_cable;
unsigned int cable_type = SM5502_MUIC_ADC_GROUND; unsigned int cable_type = SM5502_MUIC_ADC_GROUND;
unsigned int con_sw = DM_DP_SWITCH_OPEN; unsigned int con_sw = DM_DP_SWITCH_OPEN;
unsigned int vbus_sw = VBUSIN_SWITCH_OPEN; unsigned int vbus_sw = VBUSIN_SWITCH_OPEN;
unsigned int idx = 0; unsigned int id;
int ret; int ret;
if (!cable_names)
return 0;
/* Get the type of attached or detached cable */ /* Get the type of attached or detached cable */
if (attached) if (attached)
cable_type = sm5502_muic_get_cable_type(info); cable_type = sm5502_muic_get_cable_type(info);
...@@ -396,17 +384,17 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, ...@@ -396,17 +384,17 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
switch (cable_type) { switch (cable_type) {
case SM5502_MUIC_ADC_OPEN_USB: case SM5502_MUIC_ADC_OPEN_USB:
idx = EXTCON_CABLE_USB; id = EXTCON_USB;
con_sw = DM_DP_SWITCH_USB; con_sw = DM_DP_SWITCH_USB;
vbus_sw = VBUSIN_SWITCH_VBUSOUT_WITH_USB; vbus_sw = VBUSIN_SWITCH_VBUSOUT_WITH_USB;
break; break;
case SM5502_MUIC_ADC_OPEN_TA: case SM5502_MUIC_ADC_OPEN_TA:
idx = EXTCON_CABLE_TA; id = EXTCON_TA;
con_sw = DM_DP_SWITCH_OPEN; con_sw = DM_DP_SWITCH_OPEN;
vbus_sw = VBUSIN_SWITCH_VBUSOUT; vbus_sw = VBUSIN_SWITCH_VBUSOUT;
break; break;
case SM5502_MUIC_ADC_OPEN_USB_OTG: case SM5502_MUIC_ADC_OPEN_USB_OTG:
idx = EXTCON_CABLE_USB_HOST; id = EXTCON_USB_HOST;
con_sw = DM_DP_SWITCH_USB; con_sw = DM_DP_SWITCH_USB;
vbus_sw = VBUSIN_SWITCH_OPEN; vbus_sw = VBUSIN_SWITCH_OPEN;
break; break;
...@@ -422,7 +410,7 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info, ...@@ -422,7 +410,7 @@ static int sm5502_muic_cable_handler(struct sm5502_muic_info *info,
return ret; return ret;
/* Change the state of external accessory */ /* Change the state of external accessory */
extcon_set_cable_state(info->edev, cable_names[idx], attached); extcon_set_cable_state_(info->edev, id, attached);
return 0; return 0;
} }
...@@ -623,7 +611,6 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c, ...@@ -623,7 +611,6 @@ static int sm5022_muic_i2c_probe(struct i2c_client *i2c,
dev_err(info->dev, "failed to allocate memory for extcon\n"); dev_err(info->dev, "failed to allocate memory for extcon\n");
return -ENOMEM; return -ENOMEM;
} }
info->edev->name = np->name;
/* Register extcon device */ /* Register extcon device */
ret = devm_extcon_dev_register(info->dev, info->edev); ret = devm_extcon_dev_register(info->dev, info->edev);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
#include <linux/extcon.h> #include <linux/extcon.h>
#include <linux/gpio/consumer.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
...@@ -38,18 +39,10 @@ struct usb_extcon_info { ...@@ -38,18 +39,10 @@ struct usb_extcon_info {
struct delayed_work wq_detcable; struct delayed_work wq_detcable;
}; };
/* List of detectable cables */ static const unsigned int usb_extcon_cable[] = {
enum { EXTCON_USB,
EXTCON_CABLE_USB = 0, EXTCON_USB_HOST,
EXTCON_CABLE_USB_HOST, EXTCON_NONE,
EXTCON_CABLE_END,
};
static const char *usb_extcon_cable[] = {
[EXTCON_CABLE_USB] = "USB",
[EXTCON_CABLE_USB_HOST] = "USB-HOST",
NULL,
}; };
static void usb_extcon_detect_cable(struct work_struct *work) static void usb_extcon_detect_cable(struct work_struct *work)
...@@ -67,24 +60,16 @@ static void usb_extcon_detect_cable(struct work_struct *work) ...@@ -67,24 +60,16 @@ static void usb_extcon_detect_cable(struct work_struct *work)
* As we don't have event for USB peripheral cable attached, * As we don't have event for USB peripheral cable attached,
* we simulate USB peripheral attach here. * we simulate USB peripheral attach here.
*/ */
extcon_set_cable_state(info->edev, extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, false);
usb_extcon_cable[EXTCON_CABLE_USB_HOST], extcon_set_cable_state_(info->edev, EXTCON_USB, true);
false);
extcon_set_cable_state(info->edev,
usb_extcon_cable[EXTCON_CABLE_USB],
true);
} else { } else {
/* /*
* ID = 0 means USB HOST cable attached. * ID = 0 means USB HOST cable attached.
* As we don't have event for USB peripheral cable detached, * As we don't have event for USB peripheral cable detached,
* we simulate USB peripheral detach here. * we simulate USB peripheral detach here.
*/ */
extcon_set_cable_state(info->edev, extcon_set_cable_state_(info->edev, EXTCON_USB, false);
usb_extcon_cable[EXTCON_CABLE_USB], extcon_set_cable_state_(info->edev, EXTCON_USB_HOST, true);
false);
extcon_set_cable_state(info->edev,
usb_extcon_cable[EXTCON_CABLE_USB_HOST],
true);
} }
} }
...@@ -113,7 +98,7 @@ static int usb_extcon_probe(struct platform_device *pdev) ...@@ -113,7 +98,7 @@ static int usb_extcon_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
info->dev = dev; info->dev = dev;
info->id_gpiod = devm_gpiod_get(&pdev->dev, "id"); info->id_gpiod = devm_gpiod_get(&pdev->dev, "id", GPIOD_IN);
if (IS_ERR(info->id_gpiod)) { if (IS_ERR(info->id_gpiod)) {
dev_err(dev, "failed to get ID GPIO\n"); dev_err(dev, "failed to get ID GPIO\n");
return PTR_ERR(info->id_gpiod); return PTR_ERR(info->id_gpiod);
......
/* /*
* drivers/extcon/extcon_class.c * drivers/extcon/extcon.c - External Connector (extcon) framework.
* *
* External connector (extcon) class driver * External connector (extcon) class driver
* *
* Copyright (C) 2015 Samsung Electronics
* Author: Chanwoo Choi <cw00.choi@samsung.com>
*
* Copyright (C) 2012 Samsung Electronics * Copyright (C) 2012 Samsung Electronics
* Author: Donggeun Kim <dg77.kim@samsung.com> * Author: Donggeun Kim <dg77.kim@samsung.com>
* Author: MyungJoo Ham <myungjoo.ham@samsung.com> * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
...@@ -19,8 +22,7 @@ ...@@ -19,8 +22,7 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* */
*/
#include <linux/module.h> #include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -33,36 +35,43 @@ ...@@ -33,36 +35,43 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
/* #define SUPPORTED_CABLE_MAX 32
* extcon_cable_name suggests the standard cable names for commonly used #define CABLE_NAME_MAX 30
* cable types.
* static const char *extcon_name[] = {
* However, please do not use extcon_cable_name directly for extcon_dev [EXTCON_NONE] = "NONE",
* struct's supported_cable pointer unless your device really supports
* every single port-type of the following cable names. Please choose cable /* USB external connector */
* names that are actually used in your extcon device.
*/
const char extcon_cable_name[][CABLE_NAME_MAX + 1] = {
[EXTCON_USB] = "USB", [EXTCON_USB] = "USB",
[EXTCON_USB_HOST] = "USB-Host", [EXTCON_USB_HOST] = "USB-HOST",
/* Charger external connector */
[EXTCON_TA] = "TA", [EXTCON_TA] = "TA",
[EXTCON_FAST_CHARGER] = "Fast-charger", [EXTCON_FAST_CHARGER] = "FAST-CHARGER",
[EXTCON_SLOW_CHARGER] = "Slow-charger", [EXTCON_SLOW_CHARGER] = "SLOW-CHARGER",
[EXTCON_CHARGE_DOWNSTREAM] = "Charge-downstream", [EXTCON_CHARGE_DOWNSTREAM] = "CHARGE-DOWNSTREAM",
/* Audio/Video external connector */
[EXTCON_LINE_IN] = "LINE-IN",
[EXTCON_LINE_OUT] = "LINE-OUT",
[EXTCON_MICROPHONE] = "MICROPHONE",
[EXTCON_HEADPHONE] = "HEADPHONE",
[EXTCON_HDMI] = "HDMI", [EXTCON_HDMI] = "HDMI",
[EXTCON_MHL] = "MHL", [EXTCON_MHL] = "MHL",
[EXTCON_DVI] = "DVI", [EXTCON_DVI] = "DVI",
[EXTCON_VGA] = "VGA", [EXTCON_VGA] = "VGA",
[EXTCON_DOCK] = "Dock", [EXTCON_SPDIF_IN] = "SPDIF-IN",
[EXTCON_LINE_IN] = "Line-in", [EXTCON_SPDIF_OUT] = "SPDIF-OUT",
[EXTCON_LINE_OUT] = "Line-out", [EXTCON_VIDEO_IN] = "VIDEO-IN",
[EXTCON_MIC_IN] = "Microphone", [EXTCON_VIDEO_OUT] = "VIDEO-OUT",
[EXTCON_HEADPHONE_OUT] = "Headphone",
[EXTCON_SPDIF_IN] = "SPDIF-in", /* Etc external connector */
[EXTCON_SPDIF_OUT] = "SPDIF-out", [EXTCON_DOCK] = "DOCK",
[EXTCON_VIDEO_IN] = "Video-in", [EXTCON_JIG] = "JIG",
[EXTCON_VIDEO_OUT] = "Video-out", [EXTCON_MECHANICAL] = "MECHANICAL",
[EXTCON_MECHANICAL] = "Mechanical",
NULL,
}; };
static struct class *extcon_class; static struct class *extcon_class;
...@@ -102,6 +111,51 @@ static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state) ...@@ -102,6 +111,51 @@ static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
return 0; return 0;
} }
static int find_cable_index_by_id(struct extcon_dev *edev, const unsigned int id)
{
int i;
/* Find the the index of extcon cable in edev->supported_cable */
for (i = 0; i < edev->max_supported; i++) {
if (edev->supported_cable[i] == id)
return i;
}
return -EINVAL;
}
static int find_cable_index_by_name(struct extcon_dev *edev, const char *name)
{
unsigned int id = EXTCON_NONE;
int i = 0;
if (edev->max_supported == 0)
return -EINVAL;
/* Find the the number of extcon cable */
while (extcon_name[i]) {
if (!strncmp(extcon_name[i], name, CABLE_NAME_MAX)) {
id = i;
break;
}
}
if (id == EXTCON_NONE)
return -EINVAL;
return find_cable_index_by_id(edev, id);
}
static bool is_extcon_changed(u32 prev, u32 new, int idx, bool *attached)
{
if (((prev >> idx) & 0x1) != ((new >> idx) & 0x1)) {
*attached = new ? true : false;
return true;
}
return false;
}
static ssize_t state_show(struct device *dev, struct device_attribute *attr, static ssize_t state_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
...@@ -119,11 +173,9 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, ...@@ -119,11 +173,9 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr,
if (edev->max_supported == 0) if (edev->max_supported == 0)
return sprintf(buf, "%u\n", edev->state); return sprintf(buf, "%u\n", edev->state);
for (i = 0; i < SUPPORTED_CABLE_MAX; i++) { for (i = 0; i < edev->max_supported; i++) {
if (!edev->supported_cable[i])
break;
count += sprintf(buf + count, "%s=%d\n", count += sprintf(buf + count, "%s=%d\n",
edev->supported_cable[i], extcon_name[edev->supported_cable[i]],
!!(edev->state & (1 << i))); !!(edev->state & (1 << i)));
} }
...@@ -155,15 +207,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr, ...@@ -155,15 +207,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
{ {
struct extcon_dev *edev = dev_get_drvdata(dev); struct extcon_dev *edev = dev_get_drvdata(dev);
/* Optional callback given by the user */ return sprintf(buf, "%s\n", edev->name);
if (edev->print_name) {
int ret = edev->print_name(edev, buf);
if (ret >= 0)
return ret;
}
return sprintf(buf, "%s\n", dev_name(&edev->dev));
} }
static DEVICE_ATTR_RO(name); static DEVICE_ATTR_RO(name);
...@@ -172,9 +216,10 @@ static ssize_t cable_name_show(struct device *dev, ...@@ -172,9 +216,10 @@ static ssize_t cable_name_show(struct device *dev,
{ {
struct extcon_cable *cable = container_of(attr, struct extcon_cable, struct extcon_cable *cable = container_of(attr, struct extcon_cable,
attr_name); attr_name);
int i = cable->cable_index;
return sprintf(buf, "%s\n", return sprintf(buf, "%s\n",
cable->edev->supported_cable[cable->cable_index]); extcon_name[cable->edev->supported_cable[i]]);
} }
static ssize_t cable_state_show(struct device *dev, static ssize_t cable_state_show(struct device *dev,
...@@ -211,23 +256,27 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) ...@@ -211,23 +256,27 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
char *envp[3]; char *envp[3];
int env_offset = 0; int env_offset = 0;
int length; int length;
int index;
unsigned long flags; unsigned long flags;
bool attached;
spin_lock_irqsave(&edev->lock, flags); spin_lock_irqsave(&edev->lock, flags);
if (edev->state != ((edev->state & ~mask) | (state & mask))) { if (edev->state != ((edev->state & ~mask) | (state & mask))) {
u32 old_state = edev->state;
if (check_mutually_exclusive(edev, (edev->state & ~mask) | if (check_mutually_exclusive(edev, (edev->state & ~mask) |
(state & mask))) { (state & mask))) {
spin_unlock_irqrestore(&edev->lock, flags); spin_unlock_irqrestore(&edev->lock, flags);
return -EPERM; return -EPERM;
} }
for (index = 0; index < edev->max_supported; index++) {
if (is_extcon_changed(edev->state, state, index, &attached))
raw_notifier_call_chain(&edev->nh[index], attached, edev);
}
edev->state &= ~mask; edev->state &= ~mask;
edev->state |= state & mask; edev->state |= state & mask;
raw_notifier_call_chain(&edev->nh, old_state, edev);
/* This could be in interrupt handler */ /* This could be in interrupt handler */
prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
if (prop_buf) { if (prop_buf) {
...@@ -284,39 +333,19 @@ int extcon_set_state(struct extcon_dev *edev, u32 state) ...@@ -284,39 +333,19 @@ int extcon_set_state(struct extcon_dev *edev, u32 state)
EXPORT_SYMBOL_GPL(extcon_set_state); EXPORT_SYMBOL_GPL(extcon_set_state);
/** /**
* extcon_find_cable_index() - Get the cable index based on the cable name. * extcon_get_cable_state_() - Get the status of a specific cable.
* @edev: the extcon device that has the cable. * @edev: the extcon device that has the cable.
* @cable_name: cable name to be searched. * @id: the unique id of each external connector in extcon enumeration.
*
* Note that accessing a cable state based on cable_index is faster than
* cable_name because using cable_name induces a loop with strncmp().
* Thus, when get/set_cable_state is repeatedly used, using cable_index
* is recommended.
*/ */
int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name) int extcon_get_cable_state_(struct extcon_dev *edev, const unsigned int id)
{ {
int i; int index;
if (edev->supported_cable) { index = find_cable_index_by_id(edev, id);
for (i = 0; edev->supported_cable[i]; i++) { if (index < 0)
if (!strncmp(edev->supported_cable[i], return index;
cable_name, CABLE_NAME_MAX))
return i;
}
}
return -EINVAL; if (edev->max_supported && edev->max_supported <= index)
}
EXPORT_SYMBOL_GPL(extcon_find_cable_index);
/**
* extcon_get_cable_state_() - Get the status of a specific cable.
* @edev: the extcon device that has the cable.
* @index: cable index that can be retrieved by extcon_find_cable_index().
*/
int extcon_get_cable_state_(struct extcon_dev *edev, int index)
{
if (index < 0 || (edev->max_supported && edev->max_supported <= index))
return -EINVAL; return -EINVAL;
return !!(edev->state & (1 << index)); return !!(edev->state & (1 << index));
...@@ -332,7 +361,7 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state_); ...@@ -332,7 +361,7 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
*/ */
int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name) int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
{ {
return extcon_get_cable_state_(edev, extcon_find_cable_index return extcon_get_cable_state_(edev, find_cable_index_by_name
(edev, cable_name)); (edev, cable_name));
} }
EXPORT_SYMBOL_GPL(extcon_get_cable_state); EXPORT_SYMBOL_GPL(extcon_get_cable_state);
...@@ -340,17 +369,22 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state); ...@@ -340,17 +369,22 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state);
/** /**
* extcon_set_cable_state_() - Set the status of a specific cable. * extcon_set_cable_state_() - Set the status of a specific cable.
* @edev: the extcon device that has the cable. * @edev: the extcon device that has the cable.
* @index: cable index that can be retrieved by * @id: the unique id of each external connector
* extcon_find_cable_index(). * in extcon enumeration.
* @cable_state: the new cable status. The default semantics is * @state: the new cable status. The default semantics is
* true: attached / false: detached. * true: attached / false: detached.
*/ */
int extcon_set_cable_state_(struct extcon_dev *edev, int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id,
int index, bool cable_state) bool cable_state)
{ {
u32 state; u32 state;
int index;
index = find_cable_index_by_id(edev, id);
if (index < 0)
return index;
if (index < 0 || (edev->max_supported && edev->max_supported <= index)) if (edev->max_supported && edev->max_supported <= index)
return -EINVAL; return -EINVAL;
state = cable_state ? (1 << index) : 0; state = cable_state ? (1 << index) : 0;
...@@ -370,7 +404,7 @@ EXPORT_SYMBOL_GPL(extcon_set_cable_state_); ...@@ -370,7 +404,7 @@ EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
int extcon_set_cable_state(struct extcon_dev *edev, int extcon_set_cable_state(struct extcon_dev *edev,
const char *cable_name, bool cable_state) const char *cable_name, bool cable_state)
{ {
return extcon_set_cable_state_(edev, extcon_find_cable_index return extcon_set_cable_state_(edev, find_cable_index_by_name
(edev, cable_name), cable_state); (edev, cable_name), cable_state);
} }
EXPORT_SYMBOL_GPL(extcon_set_cable_state); EXPORT_SYMBOL_GPL(extcon_set_cable_state);
...@@ -395,29 +429,6 @@ struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) ...@@ -395,29 +429,6 @@ struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
} }
EXPORT_SYMBOL_GPL(extcon_get_extcon_dev); EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
static int _call_per_cable(struct notifier_block *nb, unsigned long val,
void *ptr)
{
struct extcon_specific_cable_nb *obj = container_of(nb,
struct extcon_specific_cable_nb, internal_nb);
struct extcon_dev *edev = ptr;
if ((val & (1 << obj->cable_index)) !=
(edev->state & (1 << obj->cable_index))) {
bool cable_state = true;
obj->previous_value = val;
if (val & (1 << obj->cable_index))
cable_state = false;
return obj->user_nb->notifier_call(obj->user_nb,
cable_state, ptr);
}
return NOTIFY_OK;
}
/** /**
* extcon_register_interest() - Register a notifier for a state change of a * extcon_register_interest() - Register a notifier for a state change of a
* specific cable, not an entier set of cables of a * specific cable, not an entier set of cables of a
...@@ -456,20 +467,18 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj, ...@@ -456,20 +467,18 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj,
if (!obj->edev) if (!obj->edev)
return -ENODEV; return -ENODEV;
obj->cable_index = extcon_find_cable_index(obj->edev, obj->cable_index = find_cable_index_by_name(obj->edev,
cable_name); cable_name);
if (obj->cable_index < 0) if (obj->cable_index < 0)
return obj->cable_index; return obj->cable_index;
obj->user_nb = nb; obj->user_nb = nb;
obj->internal_nb.notifier_call = _call_per_cable;
spin_lock_irqsave(&obj->edev->lock, flags); spin_lock_irqsave(&obj->edev->lock, flags);
ret = raw_notifier_chain_register(&obj->edev->nh, ret = raw_notifier_chain_register(
&obj->internal_nb); &obj->edev->nh[obj->cable_index],
obj->user_nb);
spin_unlock_irqrestore(&obj->edev->lock, flags); spin_unlock_irqrestore(&obj->edev->lock, flags);
return ret;
} else { } else {
struct class_dev_iter iter; struct class_dev_iter iter;
struct extcon_dev *extd; struct extcon_dev *extd;
...@@ -481,7 +490,7 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj, ...@@ -481,7 +490,7 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj,
while ((dev = class_dev_iter_next(&iter))) { while ((dev = class_dev_iter_next(&iter))) {
extd = dev_get_drvdata(dev); extd = dev_get_drvdata(dev);
if (extcon_find_cable_index(extd, cable_name) < 0) if (find_cable_index_by_name(extd, cable_name) < 0)
continue; continue;
class_dev_iter_exit(&iter); class_dev_iter_exit(&iter);
...@@ -489,8 +498,10 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj, ...@@ -489,8 +498,10 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj,
cable_name, nb); cable_name, nb);
} }
return -ENODEV; ret = -ENODEV;
} }
return ret;
} }
EXPORT_SYMBOL_GPL(extcon_register_interest); EXPORT_SYMBOL_GPL(extcon_register_interest);
...@@ -509,7 +520,8 @@ int extcon_unregister_interest(struct extcon_specific_cable_nb *obj) ...@@ -509,7 +520,8 @@ int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&obj->edev->lock, flags); spin_lock_irqsave(&obj->edev->lock, flags);
ret = raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb); ret = raw_notifier_chain_unregister(
&obj->edev->nh[obj->cable_index], obj->user_nb);
spin_unlock_irqrestore(&obj->edev->lock, flags); spin_unlock_irqrestore(&obj->edev->lock, flags);
return ret; return ret;
...@@ -519,21 +531,24 @@ EXPORT_SYMBOL_GPL(extcon_unregister_interest); ...@@ -519,21 +531,24 @@ EXPORT_SYMBOL_GPL(extcon_unregister_interest);
/** /**
* extcon_register_notifier() - Register a notifiee to get notified by * extcon_register_notifier() - Register a notifiee to get notified by
* any attach status changes from the extcon. * any attach status changes from the extcon.
* @edev: the extcon device. * @edev: the extcon device that has the external connecotr.
* @id: the unique id of each external connector in extcon enumeration.
* @nb: a notifier block to be registered. * @nb: a notifier block to be registered.
* *
* Note that the second parameter given to the callback of nb (val) is * Note that the second parameter given to the callback of nb (val) is
* "old_state", not the current state. The current state can be retrieved * "old_state", not the current state. The current state can be retrieved
* by looking at the third pameter (edev pointer)'s state value. * by looking at the third pameter (edev pointer)'s state value.
*/ */
int extcon_register_notifier(struct extcon_dev *edev, int extcon_register_notifier(struct extcon_dev *edev, unsigned int id,
struct notifier_block *nb) struct notifier_block *nb)
{ {
unsigned long flags; unsigned long flags;
int ret; int ret, idx;
idx = find_cable_index_by_id(edev, id);
spin_lock_irqsave(&edev->lock, flags); spin_lock_irqsave(&edev->lock, flags);
ret = raw_notifier_chain_register(&edev->nh, nb); ret = raw_notifier_chain_register(&edev->nh[idx], nb);
spin_unlock_irqrestore(&edev->lock, flags); spin_unlock_irqrestore(&edev->lock, flags);
return ret; return ret;
...@@ -542,17 +557,20 @@ EXPORT_SYMBOL_GPL(extcon_register_notifier); ...@@ -542,17 +557,20 @@ EXPORT_SYMBOL_GPL(extcon_register_notifier);
/** /**
* extcon_unregister_notifier() - Unregister a notifiee from the extcon device. * extcon_unregister_notifier() - Unregister a notifiee from the extcon device.
* @edev: the extcon device. * @edev: the extcon device that has the external connecotr.
* @nb: a registered notifier block to be unregistered. * @id: the unique id of each external connector in extcon enumeration.
* @nb: a notifier block to be registered.
*/ */
int extcon_unregister_notifier(struct extcon_dev *edev, int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id,
struct notifier_block *nb) struct notifier_block *nb)
{ {
unsigned long flags; unsigned long flags;
int ret; int ret, idx;
idx = find_cable_index_by_id(edev, id);
spin_lock_irqsave(&edev->lock, flags); spin_lock_irqsave(&edev->lock, flags);
ret = raw_notifier_chain_unregister(&edev->nh, nb); ret = raw_notifier_chain_unregister(&edev->nh[idx], nb);
spin_unlock_irqrestore(&edev->lock, flags); spin_unlock_irqrestore(&edev->lock, flags);
return ret; return ret;
...@@ -595,7 +613,7 @@ static void dummy_sysfs_dev_release(struct device *dev) ...@@ -595,7 +613,7 @@ static void dummy_sysfs_dev_release(struct device *dev)
/* /*
* extcon_dev_allocate() - Allocate the memory of extcon device. * extcon_dev_allocate() - Allocate the memory of extcon device.
* @supported_cable: Array of supported cable names ending with NULL. * @supported_cable: Array of supported extcon ending with EXTCON_NONE.
* If supported_cable is NULL, cable name related APIs * If supported_cable is NULL, cable name related APIs
* are disabled. * are disabled.
* *
...@@ -605,7 +623,7 @@ static void dummy_sysfs_dev_release(struct device *dev) ...@@ -605,7 +623,7 @@ static void dummy_sysfs_dev_release(struct device *dev)
* *
* Return the pointer of extcon device if success or ERR_PTR(err) if fail * Return the pointer of extcon device if success or ERR_PTR(err) if fail
*/ */
struct extcon_dev *extcon_dev_allocate(const char **supported_cable) struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable)
{ {
struct extcon_dev *edev; struct extcon_dev *edev;
...@@ -647,7 +665,7 @@ static void devm_extcon_dev_release(struct device *dev, void *res) ...@@ -647,7 +665,7 @@ static void devm_extcon_dev_release(struct device *dev, void *res)
/** /**
* devm_extcon_dev_allocate - Allocate managed extcon device * devm_extcon_dev_allocate - Allocate managed extcon device
* @dev: device owning the extcon device being created * @dev: device owning the extcon device being created
* @supported_cable: Array of supported cable names ending with NULL. * @supported_cable: Array of supported extcon ending with EXTCON_NONE.
* If supported_cable is NULL, cable name related APIs * If supported_cable is NULL, cable name related APIs
* are disabled. * are disabled.
* *
...@@ -659,7 +677,7 @@ static void devm_extcon_dev_release(struct device *dev, void *res) ...@@ -659,7 +677,7 @@ static void devm_extcon_dev_release(struct device *dev, void *res)
* or ERR_PTR(err) if fail * or ERR_PTR(err) if fail
*/ */
struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, struct extcon_dev *devm_extcon_dev_allocate(struct device *dev,
const char **supported_cable) const unsigned int *supported_cable)
{ {
struct extcon_dev **ptr, *edev; struct extcon_dev **ptr, *edev;
...@@ -701,6 +719,7 @@ EXPORT_SYMBOL_GPL(devm_extcon_dev_free); ...@@ -701,6 +719,7 @@ EXPORT_SYMBOL_GPL(devm_extcon_dev_free);
int extcon_dev_register(struct extcon_dev *edev) int extcon_dev_register(struct extcon_dev *edev)
{ {
int ret, index = 0; int ret, index = 0;
static atomic_t edev_no = ATOMIC_INIT(-1);
if (!extcon_class) { if (!extcon_class) {
ret = create_extcon_class(); ret = create_extcon_class();
...@@ -708,30 +727,29 @@ int extcon_dev_register(struct extcon_dev *edev) ...@@ -708,30 +727,29 @@ int extcon_dev_register(struct extcon_dev *edev)
return ret; return ret;
} }
if (edev->supported_cable) { if (!edev->supported_cable)
/* Get size of array */ return -EINVAL;
for (index = 0; edev->supported_cable[index]; index++)
; for (; edev->supported_cable[index] != EXTCON_NONE; index++);
edev->max_supported = index;
} else {
edev->max_supported = 0;
}
edev->max_supported = index;
if (index > SUPPORTED_CABLE_MAX) { if (index > SUPPORTED_CABLE_MAX) {
dev_err(&edev->dev, "extcon: maximum number of supported cables exceeded.\n"); dev_err(&edev->dev,
"exceed the maximum number of supported cables\n");
return -EINVAL; return -EINVAL;
} }
edev->dev.class = extcon_class; edev->dev.class = extcon_class;
edev->dev.release = extcon_dev_release; edev->dev.release = extcon_dev_release;
edev->name = edev->name ? edev->name : dev_name(edev->dev.parent); edev->name = dev_name(edev->dev.parent);
if (IS_ERR_OR_NULL(edev->name)) { if (IS_ERR_OR_NULL(edev->name)) {
dev_err(&edev->dev, dev_err(&edev->dev,
"extcon device name is null\n"); "extcon device name is null\n");
return -EINVAL; return -EINVAL;
} }
dev_set_name(&edev->dev, "%s", edev->name); dev_set_name(&edev->dev, "extcon%lu",
(unsigned long)atomic_inc_return(&edev_no));
if (edev->max_supported) { if (edev->max_supported) {
char buf[10]; char buf[10];
...@@ -864,7 +882,15 @@ int extcon_dev_register(struct extcon_dev *edev) ...@@ -864,7 +882,15 @@ int extcon_dev_register(struct extcon_dev *edev)
spin_lock_init(&edev->lock); spin_lock_init(&edev->lock);
RAW_INIT_NOTIFIER_HEAD(&edev->nh); edev->nh = devm_kzalloc(&edev->dev,
sizeof(*edev->nh) * edev->max_supported, GFP_KERNEL);
if (!edev->nh) {
ret = -ENOMEM;
goto err_dev;
}
for (index = 0; index < edev->max_supported; index++)
RAW_INIT_NOTIFIER_HEAD(&edev->nh[index]);
dev_set_drvdata(&edev->dev, edev); dev_set_drvdata(&edev->dev, edev);
edev->state = 0; edev->state = 0;
...@@ -1044,6 +1070,15 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) ...@@ -1044,6 +1070,15 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index)
#endif /* CONFIG_OF */ #endif /* CONFIG_OF */
EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle); EXPORT_SYMBOL_GPL(extcon_get_edev_by_phandle);
/**
* extcon_get_edev_name() - Get the name of the extcon device.
* @edev: the extcon device
*/
const char *extcon_get_edev_name(struct extcon_dev *edev)
{
return !edev ? NULL : edev->name;
}
static int __init extcon_class_init(void) static int __init extcon_class_init(void)
{ {
return create_extcon_class(); return create_extcon_class();
...@@ -1059,6 +1094,7 @@ static void __exit extcon_class_exit(void) ...@@ -1059,6 +1094,7 @@ static void __exit extcon_class_exit(void)
} }
module_exit(extcon_class_exit); module_exit(extcon_class_exit);
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
......
...@@ -5,4 +5,4 @@ obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o ...@@ -5,4 +5,4 @@ obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o
hv_vmbus-y := vmbus_drv.o \ hv_vmbus-y := vmbus_drv.o \
hv.o connection.o channel.o \ hv.o connection.o channel.o \
channel_mgmt.o ring_buffer.o channel_mgmt.o ring_buffer.o
hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_fcopy.o hv_utils_transport.o
...@@ -73,6 +73,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, ...@@ -73,6 +73,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
unsigned long flags; unsigned long flags;
int ret, err = 0; int ret, err = 0;
unsigned long t; unsigned long t;
struct page *page;
spin_lock_irqsave(&newchannel->lock, flags); spin_lock_irqsave(&newchannel->lock, flags);
if (newchannel->state == CHANNEL_OPEN_STATE) { if (newchannel->state == CHANNEL_OPEN_STATE) {
...@@ -87,8 +88,17 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, ...@@ -87,8 +88,17 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
newchannel->channel_callback_context = context; newchannel->channel_callback_context = context;
/* Allocate the ring buffer */ /* Allocate the ring buffer */
out = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, page = alloc_pages_node(cpu_to_node(newchannel->target_cpu),
get_order(send_ringbuffer_size + recv_ringbuffer_size)); GFP_KERNEL|__GFP_ZERO,
get_order(send_ringbuffer_size +
recv_ringbuffer_size));
if (!page)
out = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
get_order(send_ringbuffer_size +
recv_ringbuffer_size));
else
out = (void *)page_address(page);
if (!out) { if (!out) {
err = -ENOMEM; err = -ENOMEM;
...@@ -178,19 +188,18 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, ...@@ -178,19 +188,18 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
goto error1; goto error1;
} }
if (open_info->response.open_result.status)
err = open_info->response.open_result.status;
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
list_del(&open_info->msglistentry); list_del(&open_info->msglistentry);
spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
if (err == 0) if (open_info->response.open_result.status) {
newchannel->state = CHANNEL_OPENED_STATE; err = -EAGAIN;
goto error_gpadl;
}
newchannel->state = CHANNEL_OPENED_STATE;
kfree(open_info); kfree(open_info);
return err; return 0;
error1: error1:
spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
......
...@@ -32,6 +32,9 @@ ...@@ -32,6 +32,9 @@
#include "hyperv_vmbus.h" #include "hyperv_vmbus.h"
static void init_vp_index(struct vmbus_channel *channel,
const uuid_le *type_guid);
/** /**
* vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message * vmbus_prep_negotiate_resp() - Create default response for Hyper-V Negotiate message
* @icmsghdrp: Pointer to msg header structure * @icmsghdrp: Pointer to msg header structure
...@@ -205,6 +208,7 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) ...@@ -205,6 +208,7 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
primary_channel = channel->primary_channel; primary_channel = channel->primary_channel;
spin_lock_irqsave(&primary_channel->lock, flags); spin_lock_irqsave(&primary_channel->lock, flags);
list_del(&channel->sc_list); list_del(&channel->sc_list);
primary_channel->num_sc--;
spin_unlock_irqrestore(&primary_channel->lock, flags); spin_unlock_irqrestore(&primary_channel->lock, flags);
} }
free_channel(channel); free_channel(channel);
...@@ -212,11 +216,16 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) ...@@ -212,11 +216,16 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
void vmbus_free_channels(void) void vmbus_free_channels(void)
{ {
struct vmbus_channel *channel; struct vmbus_channel *channel, *tmp;
list_for_each_entry_safe(channel, tmp, &vmbus_connection.chn_list,
listentry) {
/* if we don't set rescind to true, vmbus_close_internal()
* won't invoke hv_process_channel_removal().
*/
channel->rescind = true;
list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) {
vmbus_device_unregister(channel->device_obj); vmbus_device_unregister(channel->device_obj);
free_channel(channel);
} }
} }
...@@ -228,7 +237,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) ...@@ -228,7 +237,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
{ {
struct vmbus_channel *channel; struct vmbus_channel *channel;
bool fnew = true; bool fnew = true;
bool enq = false;
unsigned long flags; unsigned long flags;
/* Make sure this is a new offer */ /* Make sure this is a new offer */
...@@ -244,25 +252,12 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) ...@@ -244,25 +252,12 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
} }
} }
if (fnew) { if (fnew)
list_add_tail(&newchannel->listentry, list_add_tail(&newchannel->listentry,
&vmbus_connection.chn_list); &vmbus_connection.chn_list);
enq = true;
}
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
if (enq) {
if (newchannel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(newchannel->target_cpu,
percpu_channel_enq,
newchannel, true);
} else {
percpu_channel_enq(newchannel);
put_cpu();
}
}
if (!fnew) { if (!fnew) {
/* /*
* Check to see if this is a sub-channel. * Check to see if this is a sub-channel.
...@@ -274,27 +269,22 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) ...@@ -274,27 +269,22 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
newchannel->primary_channel = channel; newchannel->primary_channel = channel;
spin_lock_irqsave(&channel->lock, flags); spin_lock_irqsave(&channel->lock, flags);
list_add_tail(&newchannel->sc_list, &channel->sc_list); list_add_tail(&newchannel->sc_list, &channel->sc_list);
spin_unlock_irqrestore(&channel->lock, flags);
if (newchannel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(newchannel->target_cpu,
percpu_channel_enq,
newchannel, true);
} else {
percpu_channel_enq(newchannel);
put_cpu();
}
newchannel->state = CHANNEL_OPEN_STATE;
channel->num_sc++; channel->num_sc++;
if (channel->sc_creation_callback != NULL) spin_unlock_irqrestore(&channel->lock, flags);
channel->sc_creation_callback(newchannel); } else
goto err_free_chan;
}
return; init_vp_index(newchannel, &newchannel->offermsg.offer.if_type);
}
goto err_free_chan; if (newchannel->target_cpu != get_cpu()) {
put_cpu();
smp_call_function_single(newchannel->target_cpu,
percpu_channel_enq,
newchannel, true);
} else {
percpu_channel_enq(newchannel);
put_cpu();
} }
/* /*
...@@ -304,6 +294,12 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) ...@@ -304,6 +294,12 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
*/ */
newchannel->state = CHANNEL_OPEN_STATE; newchannel->state = CHANNEL_OPEN_STATE;
if (!fnew) {
if (channel->sc_creation_callback != NULL)
channel->sc_creation_callback(newchannel);
return;
}
/* /*
* Start the process of binding this offer to the driver * Start the process of binding this offer to the driver
* We need to set the DeviceObject field before calling * We need to set the DeviceObject field before calling
...@@ -374,23 +370,27 @@ static const struct hv_vmbus_device_id hp_devs[] = { ...@@ -374,23 +370,27 @@ static const struct hv_vmbus_device_id hp_devs[] = {
/* /*
* We use this state to statically distribute the channel interrupt load. * We use this state to statically distribute the channel interrupt load.
*/ */
static u32 next_vp; static int next_numa_node_id;
/* /*
* Starting with Win8, we can statically distribute the incoming * Starting with Win8, we can statically distribute the incoming
* channel interrupt load by binding a channel to VCPU. We * channel interrupt load by binding a channel to VCPU.
* implement here a simple round robin scheme for distributing * We do this in a hierarchical fashion:
* the interrupt load. * First distribute the primary channels across available NUMA nodes
* We will bind channels that are not performance critical to cpu 0 and * and then distribute the subchannels amongst the CPUs in the NUMA
* performance critical channels (IDE, SCSI and Network) will be uniformly * node assigned to the primary channel.
* distributed across all available CPUs. *
* For pre-win8 hosts or non-performance critical channels we assign the
* first CPU in the first NUMA node.
*/ */
static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_guid) static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_guid)
{ {
u32 cur_cpu; u32 cur_cpu;
int i; int i;
bool perf_chn = false; bool perf_chn = false;
u32 max_cpus = num_online_cpus(); struct vmbus_channel *primary = channel->primary_channel;
int next_node;
struct cpumask available_mask;
for (i = IDE; i < MAX_PERF_CHN; i++) { for (i = IDE; i < MAX_PERF_CHN; i++) {
if (!memcmp(type_guid->b, hp_devs[i].guid, if (!memcmp(type_guid->b, hp_devs[i].guid,
...@@ -407,15 +407,76 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui ...@@ -407,15 +407,76 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui
* Also if the channel is not a performance critical * Also if the channel is not a performance critical
* channel, bind it to cpu 0. * channel, bind it to cpu 0.
*/ */
channel->numa_node = 0;
cpumask_set_cpu(0, &channel->alloced_cpus_in_node);
channel->target_cpu = 0; channel->target_cpu = 0;
channel->target_vp = 0; channel->target_vp = hv_context.vp_index[0];
return; return;
} }
cur_cpu = (++next_vp % max_cpus);
/*
* We distribute primary channels evenly across all the available
* NUMA nodes and within the assigned NUMA node we will assign the
* first available CPU to the primary channel.
* The sub-channels will be assigned to the CPUs available in the
* NUMA node evenly.
*/
if (!primary) {
while (true) {
next_node = next_numa_node_id++;
if (next_node == nr_node_ids)
next_node = next_numa_node_id = 0;
if (cpumask_empty(cpumask_of_node(next_node)))
continue;
break;
}
channel->numa_node = next_node;
primary = channel;
}
if (cpumask_weight(&primary->alloced_cpus_in_node) ==
cpumask_weight(cpumask_of_node(primary->numa_node))) {
/*
* We have cycled through all the CPUs in the node;
* reset the alloced map.
*/
cpumask_clear(&primary->alloced_cpus_in_node);
}
cpumask_xor(&available_mask, &primary->alloced_cpus_in_node,
cpumask_of_node(primary->numa_node));
cur_cpu = cpumask_next(-1, &available_mask);
cpumask_set_cpu(cur_cpu, &primary->alloced_cpus_in_node);
channel->target_cpu = cur_cpu; channel->target_cpu = cur_cpu;
channel->target_vp = hv_context.vp_index[cur_cpu]; channel->target_vp = hv_context.vp_index[cur_cpu];
} }
/*
* vmbus_unload_response - Handler for the unload response.
*/
static void vmbus_unload_response(struct vmbus_channel_message_header *hdr)
{
/*
* This is a global event; just wakeup the waiting thread.
* Once we successfully unload, we can cleanup the monitor state.
*/
complete(&vmbus_connection.unload_event);
}
void vmbus_initiate_unload(void)
{
struct vmbus_channel_message_header hdr;
init_completion(&vmbus_connection.unload_event);
memset(&hdr, 0, sizeof(struct vmbus_channel_message_header));
hdr.msgtype = CHANNELMSG_UNLOAD;
vmbus_post_msg(&hdr, sizeof(struct vmbus_channel_message_header));
wait_for_completion(&vmbus_connection.unload_event);
}
/* /*
* vmbus_onoffer - Handler for channel offers from vmbus in parent partition. * vmbus_onoffer - Handler for channel offers from vmbus in parent partition.
* *
...@@ -461,8 +522,6 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) ...@@ -461,8 +522,6 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
offer->connection_id; offer->connection_id;
} }
init_vp_index(newchannel, &offer->offer.if_type);
memcpy(&newchannel->offermsg, offer, memcpy(&newchannel->offermsg, offer,
sizeof(struct vmbus_channel_offer_channel)); sizeof(struct vmbus_channel_offer_channel));
newchannel->monitor_grp = (u8)offer->monitorid / 32; newchannel->monitor_grp = (u8)offer->monitorid / 32;
...@@ -712,6 +771,7 @@ struct vmbus_channel_message_table_entry ...@@ -712,6 +771,7 @@ struct vmbus_channel_message_table_entry
{CHANNELMSG_INITIATE_CONTACT, 0, NULL}, {CHANNELMSG_INITIATE_CONTACT, 0, NULL},
{CHANNELMSG_VERSION_RESPONSE, 1, vmbus_onversion_response}, {CHANNELMSG_VERSION_RESPONSE, 1, vmbus_onversion_response},
{CHANNELMSG_UNLOAD, 0, NULL}, {CHANNELMSG_UNLOAD, 0, NULL},
{CHANNELMSG_UNLOAD_RESPONSE, 1, vmbus_unload_response},
}; };
/* /*
......
...@@ -58,6 +58,9 @@ static __u32 vmbus_get_next_version(__u32 current_version) ...@@ -58,6 +58,9 @@ static __u32 vmbus_get_next_version(__u32 current_version)
case (VERSION_WIN8_1): case (VERSION_WIN8_1):
return VERSION_WIN8; return VERSION_WIN8;
case (VERSION_WIN10):
return VERSION_WIN8_1;
case (VERSION_WS2008): case (VERSION_WS2008):
default: default:
return VERSION_INVAL; return VERSION_INVAL;
...@@ -80,7 +83,7 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, ...@@ -80,7 +83,7 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
if (version == VERSION_WIN8_1) { if (version >= VERSION_WIN8_1) {
msg->target_vcpu = hv_context.vp_index[get_cpu()]; msg->target_vcpu = hv_context.vp_index[get_cpu()];
put_cpu(); put_cpu();
} }
...@@ -227,6 +230,11 @@ int vmbus_connect(void) ...@@ -227,6 +230,11 @@ int vmbus_connect(void)
void vmbus_disconnect(void) void vmbus_disconnect(void)
{ {
/*
* First send the unload request to the host.
*/
vmbus_initiate_unload();
if (vmbus_connection.work_queue) { if (vmbus_connection.work_queue) {
drain_workqueue(vmbus_connection.work_queue); drain_workqueue(vmbus_connection.work_queue);
destroy_workqueue(vmbus_connection.work_queue); destroy_workqueue(vmbus_connection.work_queue);
...@@ -371,8 +379,7 @@ void vmbus_on_event(unsigned long data) ...@@ -371,8 +379,7 @@ void vmbus_on_event(unsigned long data)
int cpu = smp_processor_id(); int cpu = smp_processor_id();
union hv_synic_event_flags *event; union hv_synic_event_flags *event;
if ((vmbus_proto_version == VERSION_WS2008) || if (vmbus_proto_version < VERSION_WIN8) {
(vmbus_proto_version == VERSION_WIN7)) {
maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5; maxdword = MAX_NUM_CHANNELS_SUPPORTED >> 5;
recv_int_page = vmbus_connection.recv_int_page; recv_int_page = vmbus_connection.recv_int_page;
} else { } else {
......
...@@ -567,7 +567,9 @@ static int hv_memory_notifier(struct notifier_block *nb, unsigned long val, ...@@ -567,7 +567,9 @@ static int hv_memory_notifier(struct notifier_block *nb, unsigned long val,
case MEM_ONLINE: case MEM_ONLINE:
dm_device.num_pages_onlined += mem->nr_pages; dm_device.num_pages_onlined += mem->nr_pages;
case MEM_CANCEL_ONLINE: case MEM_CANCEL_ONLINE:
mutex_unlock(&dm_device.ha_region_mutex); if (val == MEM_ONLINE ||
mutex_is_locked(&dm_device.ha_region_mutex))
mutex_unlock(&dm_device.ha_region_mutex);
if (dm_device.ha_waiting) { if (dm_device.ha_waiting) {
dm_device.ha_waiting = false; dm_device.ha_waiting = false;
complete(&dm_device.ol_waitevent); complete(&dm_device.ol_waitevent);
......
...@@ -19,17 +19,13 @@ ...@@ -19,17 +19,13 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/semaphore.h>
#include <linux/fs.h>
#include <linux/nls.h> #include <linux/nls.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/cdev.h>
#include <linux/hyperv.h> #include <linux/hyperv.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include "hyperv_vmbus.h" #include "hyperv_vmbus.h"
#include "hv_utils_transport.h"
#define WIN8_SRV_MAJOR 1 #define WIN8_SRV_MAJOR 1
#define WIN8_SRV_MINOR 1 #define WIN8_SRV_MINOR 1
...@@ -47,39 +43,31 @@ ...@@ -47,39 +43,31 @@
* ensure this by serializing packet processing in this driver - we do not * ensure this by serializing packet processing in this driver - we do not
* read additional packets from the VMBUs until the current packet is fully * read additional packets from the VMBUs until the current packet is fully
* handled. * handled.
*
* The transaction "active" state is set when we receive a request from the
* host and we cleanup this state when the transaction is completed - when we
* respond to the host with our response. When the transaction active state is
* set, we defer handling incoming packets.
*/ */
static struct { static struct {
bool active; /* transaction status - active or not */ int state; /* hvutil_device_state */
int recv_len; /* number of bytes received. */ int recv_len; /* number of bytes received. */
struct hv_fcopy_hdr *fcopy_msg; /* current message */ struct hv_fcopy_hdr *fcopy_msg; /* current message */
struct hv_start_fcopy message; /* sent to daemon */
struct vmbus_channel *recv_channel; /* chn we got the request */ struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */ u64 recv_req_id; /* request ID. */
void *fcopy_context; /* for the channel callback */ void *fcopy_context; /* for the channel callback */
struct semaphore read_sema;
} fcopy_transaction; } fcopy_transaction;
static bool opened; /* currently device opened */
/*
* Before we can accept copy messages from the host, we need
* to handshake with the user level daemon. This state tracks
* if we are in the handshake phase.
*/
static bool in_hand_shake = true;
static void fcopy_send_data(void);
static void fcopy_respond_to_host(int error); static void fcopy_respond_to_host(int error);
static void fcopy_work_func(struct work_struct *dummy); static void fcopy_send_data(struct work_struct *dummy);
static DECLARE_DELAYED_WORK(fcopy_work, fcopy_work_func); static void fcopy_timeout_func(struct work_struct *dummy);
static DECLARE_DELAYED_WORK(fcopy_timeout_work, fcopy_timeout_func);
static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
static const char fcopy_devname[] = "vmbus/hv_fcopy";
static u8 *recv_buffer; static u8 *recv_buffer;
static struct hvutil_transport *hvt;
/*
* This state maintains the version number registered by the daemon.
*/
static int dm_reg_value;
static void fcopy_work_func(struct work_struct *dummy) static void fcopy_timeout_func(struct work_struct *dummy)
{ {
/* /*
* If the timer fires, the user-mode component has not responded; * If the timer fires, the user-mode component has not responded;
...@@ -87,23 +75,28 @@ static void fcopy_work_func(struct work_struct *dummy) ...@@ -87,23 +75,28 @@ static void fcopy_work_func(struct work_struct *dummy)
*/ */
fcopy_respond_to_host(HV_E_FAIL); fcopy_respond_to_host(HV_E_FAIL);
/* In the case the user-space daemon crashes, hangs or is killed, we /* Transaction is finished, reset the state. */
* need to down the semaphore, otherwise, after the daemon starts next if (fcopy_transaction.state > HVUTIL_READY)
* time, the obsolete data in fcopy_transaction.message or fcopy_transaction.state = HVUTIL_READY;
* fcopy_transaction.fcopy_msg will be used immediately.
*
* NOTE: fcopy_read() happens to get the semaphore (very rare)? We're
* still OK, because we've reported the failure to the host.
*/
if (down_trylock(&fcopy_transaction.read_sema))
;
hv_poll_channel(fcopy_transaction.fcopy_context,
hv_fcopy_onchannelcallback);
} }
static int fcopy_handle_handshake(u32 version) static int fcopy_handle_handshake(u32 version)
{ {
u32 our_ver = FCOPY_CURRENT_VERSION;
switch (version) { switch (version) {
case FCOPY_CURRENT_VERSION: case FCOPY_VERSION_0:
/* Daemon doesn't expect us to reply */
dm_reg_value = version;
break;
case FCOPY_VERSION_1:
/* Daemon expects us to reply with our own version */
if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver)))
return -EFAULT;
dm_reg_value = version;
break; break;
default: default:
/* /*
...@@ -114,20 +107,20 @@ static int fcopy_handle_handshake(u32 version) ...@@ -114,20 +107,20 @@ static int fcopy_handle_handshake(u32 version)
*/ */
return -EINVAL; return -EINVAL;
} }
pr_info("FCP: user-mode registering done. Daemon version: %d\n", pr_debug("FCP: userspace daemon ver. %d registered\n", version);
version); fcopy_transaction.state = HVUTIL_READY;
fcopy_transaction.active = false; hv_poll_channel(fcopy_transaction.fcopy_context,
if (fcopy_transaction.fcopy_context) hv_fcopy_onchannelcallback);
hv_fcopy_onchannelcallback(fcopy_transaction.fcopy_context);
in_hand_shake = false;
return 0; return 0;
} }
static void fcopy_send_data(void) static void fcopy_send_data(struct work_struct *dummy)
{ {
struct hv_start_fcopy *smsg_out = &fcopy_transaction.message; struct hv_start_fcopy smsg_out;
int operation = fcopy_transaction.fcopy_msg->operation; int operation = fcopy_transaction.fcopy_msg->operation;
struct hv_start_fcopy *smsg_in; struct hv_start_fcopy *smsg_in;
void *out_src;
int rc, out_len;
/* /*
* The strings sent from the host are encoded in * The strings sent from the host are encoded in
...@@ -142,26 +135,39 @@ static void fcopy_send_data(void) ...@@ -142,26 +135,39 @@ static void fcopy_send_data(void)
switch (operation) { switch (operation) {
case START_FILE_COPY: case START_FILE_COPY:
memset(smsg_out, 0, sizeof(struct hv_start_fcopy)); out_len = sizeof(struct hv_start_fcopy);
smsg_out->hdr.operation = operation; memset(&smsg_out, 0, out_len);
smsg_out.hdr.operation = operation;
smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg; smsg_in = (struct hv_start_fcopy *)fcopy_transaction.fcopy_msg;
utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH, utf16s_to_utf8s((wchar_t *)smsg_in->file_name, W_MAX_PATH,
UTF16_LITTLE_ENDIAN, UTF16_LITTLE_ENDIAN,
(__u8 *)smsg_out->file_name, W_MAX_PATH - 1); (__u8 *)&smsg_out.file_name, W_MAX_PATH - 1);
utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH, utf16s_to_utf8s((wchar_t *)smsg_in->path_name, W_MAX_PATH,
UTF16_LITTLE_ENDIAN, UTF16_LITTLE_ENDIAN,
(__u8 *)smsg_out->path_name, W_MAX_PATH - 1); (__u8 *)&smsg_out.path_name, W_MAX_PATH - 1);
smsg_out->copy_flags = smsg_in->copy_flags; smsg_out.copy_flags = smsg_in->copy_flags;
smsg_out->file_size = smsg_in->file_size; smsg_out.file_size = smsg_in->file_size;
out_src = &smsg_out;
break; break;
default: default:
out_src = fcopy_transaction.fcopy_msg;
out_len = fcopy_transaction.recv_len;
break; break;
} }
up(&fcopy_transaction.read_sema);
fcopy_transaction.state = HVUTIL_USERSPACE_REQ;
rc = hvutil_transport_send(hvt, out_src, out_len);
if (rc) {
pr_debug("FCP: failed to communicate to the daemon: %d\n", rc);
if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
fcopy_respond_to_host(HV_E_FAIL);
fcopy_transaction.state = HVUTIL_READY;
}
}
return; return;
} }
...@@ -189,8 +195,6 @@ fcopy_respond_to_host(int error) ...@@ -189,8 +195,6 @@ fcopy_respond_to_host(int error)
channel = fcopy_transaction.recv_channel; channel = fcopy_transaction.recv_channel;
req_id = fcopy_transaction.recv_req_id; req_id = fcopy_transaction.recv_req_id;
fcopy_transaction.active = false;
icmsghdr = (struct icmsg_hdr *) icmsghdr = (struct icmsg_hdr *)
&recv_buffer[sizeof(struct vmbuspipe_hdr)]; &recv_buffer[sizeof(struct vmbuspipe_hdr)];
...@@ -218,7 +222,7 @@ void hv_fcopy_onchannelcallback(void *context) ...@@ -218,7 +222,7 @@ void hv_fcopy_onchannelcallback(void *context)
int util_fw_version; int util_fw_version;
int fcopy_srv_version; int fcopy_srv_version;
if (fcopy_transaction.active) { if (fcopy_transaction.state > HVUTIL_READY) {
/* /*
* We will defer processing this callback once * We will defer processing this callback once
* the current transaction is complete. * the current transaction is complete.
...@@ -226,6 +230,7 @@ void hv_fcopy_onchannelcallback(void *context) ...@@ -226,6 +230,7 @@ void hv_fcopy_onchannelcallback(void *context)
fcopy_transaction.fcopy_context = context; fcopy_transaction.fcopy_context = context;
return; return;
} }
fcopy_transaction.fcopy_context = NULL;
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen, vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
&requestid); &requestid);
...@@ -249,17 +254,23 @@ void hv_fcopy_onchannelcallback(void *context) ...@@ -249,17 +254,23 @@ void hv_fcopy_onchannelcallback(void *context)
* transaction; note transactions are serialized. * transaction; note transactions are serialized.
*/ */
fcopy_transaction.active = true;
fcopy_transaction.recv_len = recvlen; fcopy_transaction.recv_len = recvlen;
fcopy_transaction.recv_channel = channel; fcopy_transaction.recv_channel = channel;
fcopy_transaction.recv_req_id = requestid; fcopy_transaction.recv_req_id = requestid;
fcopy_transaction.fcopy_msg = fcopy_msg; fcopy_transaction.fcopy_msg = fcopy_msg;
if (fcopy_transaction.state < HVUTIL_READY) {
/* Userspace is not registered yet */
fcopy_respond_to_host(HV_E_FAIL);
return;
}
fcopy_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
/* /*
* Send the information to the user-level daemon. * Send the information to the user-level daemon.
*/ */
schedule_delayed_work(&fcopy_work, 5*HZ); schedule_work(&fcopy_send_work);
fcopy_send_data(); schedule_delayed_work(&fcopy_timeout_work, 5*HZ);
return; return;
} }
icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
...@@ -267,155 +278,44 @@ void hv_fcopy_onchannelcallback(void *context) ...@@ -267,155 +278,44 @@ void hv_fcopy_onchannelcallback(void *context)
VM_PKT_DATA_INBAND, 0); VM_PKT_DATA_INBAND, 0);
} }
/* /* Callback when data is received from userspace */
* Create a char device that can support read/write for passing static int fcopy_on_msg(void *msg, int len)
* the payload.
*/
static ssize_t fcopy_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
void *src;
size_t copy_size;
int operation;
/*
* Wait until there is something to be read.
*/
if (down_interruptible(&fcopy_transaction.read_sema))
return -EINTR;
/*
* The channel may be rescinded and in this case, we will wakeup the
* the thread blocked on the semaphore and we will use the opened
* state to correctly handle this case.
*/
if (!opened)
return -ENODEV;
operation = fcopy_transaction.fcopy_msg->operation;
if (operation == START_FILE_COPY) {
src = &fcopy_transaction.message;
copy_size = sizeof(struct hv_start_fcopy);
if (count < copy_size)
return 0;
} else {
src = fcopy_transaction.fcopy_msg;
copy_size = sizeof(struct hv_do_fcopy);
if (count < copy_size)
return 0;
}
if (copy_to_user(buf, src, copy_size))
return -EFAULT;
return copy_size;
}
static ssize_t fcopy_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ {
int response = 0; int *val = (int *)msg;
if (count != sizeof(int)) if (len != sizeof(int))
return -EINVAL; return -EINVAL;
if (copy_from_user(&response, buf, sizeof(int))) if (fcopy_transaction.state == HVUTIL_DEVICE_INIT)
return -EFAULT; return fcopy_handle_handshake(*val);
if (in_hand_shake) { if (fcopy_transaction.state != HVUTIL_USERSPACE_REQ)
if (fcopy_handle_handshake(response)) return -EINVAL;
return -EINVAL;
return sizeof(int);
}
/* /*
* Complete the transaction by forwarding the result * Complete the transaction by forwarding the result
* to the host. But first, cancel the timeout. * to the host. But first, cancel the timeout.
*/ */
if (cancel_delayed_work_sync(&fcopy_work)) if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
fcopy_respond_to_host(response); fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
fcopy_respond_to_host(*val);
return sizeof(int); fcopy_transaction.state = HVUTIL_READY;
} hv_poll_channel(fcopy_transaction.fcopy_context,
hv_fcopy_onchannelcallback);
static int fcopy_open(struct inode *inode, struct file *f) }
{
/*
* The user level daemon that will open this device is
* really an extension of this driver. We can have only
* active open at a time.
*/
if (opened)
return -EBUSY;
/*
* The daemon is alive; setup the state.
*/
opened = true;
return 0; return 0;
} }
/* XXX: there are still some tricky corner cases, e.g., static void fcopy_on_reset(void)
* 1) In a SMP guest, when fcopy_release() runs between
* schedule_delayed_work() and fcopy_send_data(), there is
* still a chance an obsolete message will be queued.
*
* 2) When the fcopy daemon is running, if we unload the driver,
* we'll notice a kernel oops when we kill the daemon later.
*/
static int fcopy_release(struct inode *inode, struct file *f)
{ {
/* /*
* The daemon has exited; reset the state. * The daemon has exited; reset the state.
*/ */
in_hand_shake = true; fcopy_transaction.state = HVUTIL_DEVICE_INIT;
opened = false;
if (cancel_delayed_work_sync(&fcopy_work)) { if (cancel_delayed_work_sync(&fcopy_timeout_work))
/* We haven't up()-ed the semaphore(very rare)? */
if (down_trylock(&fcopy_transaction.read_sema))
;
fcopy_respond_to_host(HV_E_FAIL); fcopy_respond_to_host(HV_E_FAIL);
}
return 0;
}
static const struct file_operations fcopy_fops = {
.read = fcopy_read,
.write = fcopy_write,
.release = fcopy_release,
.open = fcopy_open,
};
static struct miscdevice fcopy_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "vmbus/hv_fcopy",
.fops = &fcopy_fops,
};
static int fcopy_dev_init(void)
{
return misc_register(&fcopy_misc);
}
static void fcopy_dev_deinit(void)
{
/*
* The device is going away - perhaps because the
* host has rescinded the channel. Setup state so that
* user level daemon can gracefully exit if it is blocked
* on the read semaphore.
*/
opened = false;
/*
* Signal the semaphore as the device is
* going away.
*/
up(&fcopy_transaction.read_sema);
misc_deregister(&fcopy_misc);
} }
int hv_fcopy_init(struct hv_util_service *srv) int hv_fcopy_init(struct hv_util_service *srv)
...@@ -428,14 +328,19 @@ int hv_fcopy_init(struct hv_util_service *srv) ...@@ -428,14 +328,19 @@ int hv_fcopy_init(struct hv_util_service *srv)
* Defer processing channel callbacks until the daemon * Defer processing channel callbacks until the daemon
* has registered. * has registered.
*/ */
fcopy_transaction.active = true; fcopy_transaction.state = HVUTIL_DEVICE_INIT;
sema_init(&fcopy_transaction.read_sema, 0);
hvt = hvutil_transport_init(fcopy_devname, 0, 0,
fcopy_on_msg, fcopy_on_reset);
if (!hvt)
return -EFAULT;
return fcopy_dev_init(); return 0;
} }
void hv_fcopy_deinit(void) void hv_fcopy_deinit(void)
{ {
cancel_delayed_work_sync(&fcopy_work); fcopy_transaction.state = HVUTIL_DEVICE_DYING;
fcopy_dev_deinit(); cancel_delayed_work_sync(&fcopy_timeout_work);
hvutil_transport_destroy(hvt);
} }
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* Kernel/userspace transport abstraction for Hyper-V util driver.
*
* Copyright (C) 2015, Vitaly Kuznetsov <vkuznets@redhat.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* 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, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for more
* details.
*
*/
#ifndef _HV_UTILS_TRANSPORT_H
#define _HV_UTILS_TRANSPORT_H
#include <linux/connector.h>
#include <linux/miscdevice.h>
enum hvutil_transport_mode {
HVUTIL_TRANSPORT_INIT = 0,
HVUTIL_TRANSPORT_NETLINK,
HVUTIL_TRANSPORT_CHARDEV,
};
struct hvutil_transport {
int mode; /* hvutil_transport_mode */
struct file_operations fops; /* file operations */
struct miscdevice mdev; /* misc device */
struct cb_id cn_id; /* CN_*_IDX/CN_*_VAL */
struct list_head list; /* hvt_list */
int (*on_msg)(void *, int); /* callback on new user message */
void (*on_reset)(void); /* callback when userspace drops */
u8 *outmsg; /* message to the userspace */
int outmsg_len; /* its length */
wait_queue_head_t outmsg_q; /* poll/read wait queue */
struct mutex outmsg_lock; /* protects outmsg */
};
struct hvutil_transport *hvutil_transport_init(const char *name,
u32 cn_idx, u32 cn_val,
int (*on_msg)(void *, int),
void (*on_reset)(void));
int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len);
void hvutil_transport_destroy(struct hvutil_transport *hvt);
#endif /* _HV_UTILS_TRANSPORT_H */
...@@ -647,6 +647,7 @@ struct vmbus_connection { ...@@ -647,6 +647,7 @@ struct vmbus_connection {
atomic_t next_gpadl_handle; atomic_t next_gpadl_handle;
struct completion unload_event;
/* /*
* Represents channel interrupts. Each bit position represents a * Represents channel interrupts. Each bit position represents a
* channel. When a channel sends an interrupt via VMBUS, it finds its * channel. When a channel sends an interrupt via VMBUS, it finds its
...@@ -730,9 +731,39 @@ int vmbus_set_event(struct vmbus_channel *channel); ...@@ -730,9 +731,39 @@ int vmbus_set_event(struct vmbus_channel *channel);
void vmbus_on_event(unsigned long data); void vmbus_on_event(unsigned long data);
int hv_kvp_init(struct hv_util_service *);
void hv_kvp_deinit(void);
void hv_kvp_onchannelcallback(void *);
int hv_vss_init(struct hv_util_service *);
void hv_vss_deinit(void);
void hv_vss_onchannelcallback(void *);
int hv_fcopy_init(struct hv_util_service *); int hv_fcopy_init(struct hv_util_service *);
void hv_fcopy_deinit(void); void hv_fcopy_deinit(void);
void hv_fcopy_onchannelcallback(void *); void hv_fcopy_onchannelcallback(void *);
void vmbus_initiate_unload(void);
static inline void hv_poll_channel(struct vmbus_channel *channel,
void (*cb)(void *))
{
if (!channel)
return;
if (channel->target_cpu != smp_processor_id())
smp_call_function_single(channel->target_cpu,
cb, channel, true);
else
cb(channel);
}
enum hvutil_device_state {
HVUTIL_DEVICE_INIT = 0, /* driver is loaded, waiting for userspace */
HVUTIL_READY, /* userspace is registered */
HVUTIL_HOSTMSG_RECEIVED, /* message from the host was received */
HVUTIL_USERSPACE_REQ, /* request to userspace was sent */
HVUTIL_USERSPACE_RECV, /* reply from userspace was received */
HVUTIL_DEVICE_DYING, /* driver unload is in progress */
};
#endif /* _HYPERV_VMBUS_H */ #endif /* _HYPERV_VMBUS_H */
...@@ -1035,6 +1035,15 @@ static int vmbus_acpi_add(struct acpi_device *device) ...@@ -1035,6 +1035,15 @@ static int vmbus_acpi_add(struct acpi_device *device)
return ret_val; return ret_val;
} }
static int vmbus_acpi_remove(struct acpi_device *device)
{
int ret = 0;
if (hyperv_mmio.start && hyperv_mmio.end)
ret = release_resource(&hyperv_mmio);
return ret;
}
static const struct acpi_device_id vmbus_acpi_device_ids[] = { static const struct acpi_device_id vmbus_acpi_device_ids[] = {
{"VMBUS", 0}, {"VMBUS", 0},
{"VMBus", 0}, {"VMBus", 0},
...@@ -1047,6 +1056,7 @@ static struct acpi_driver vmbus_acpi_driver = { ...@@ -1047,6 +1056,7 @@ static struct acpi_driver vmbus_acpi_driver = {
.ids = vmbus_acpi_device_ids, .ids = vmbus_acpi_device_ids,
.ops = { .ops = {
.add = vmbus_acpi_add, .add = vmbus_acpi_add,
.remove = vmbus_acpi_remove,
}, },
}; };
...@@ -1096,15 +1106,22 @@ static void __exit vmbus_exit(void) ...@@ -1096,15 +1106,22 @@ static void __exit vmbus_exit(void)
vmbus_connection.conn_state = DISCONNECTED; vmbus_connection.conn_state = DISCONNECTED;
hv_synic_clockevents_cleanup(); hv_synic_clockevents_cleanup();
vmbus_disconnect();
hv_remove_vmbus_irq(); hv_remove_vmbus_irq();
tasklet_kill(&msg_dpc);
vmbus_free_channels(); vmbus_free_channels();
if (ms_hyperv.features & HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE) {
atomic_notifier_chain_unregister(&panic_notifier_list,
&hyperv_panic_block);
}
bus_unregister(&hv_bus); bus_unregister(&hv_bus);
hv_cleanup(); hv_cleanup();
for_each_online_cpu(cpu) for_each_online_cpu(cpu) {
tasklet_kill(hv_context.event_dpc[cpu]);
smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1); smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);
}
acpi_bus_unregister_driver(&vmbus_acpi_driver); acpi_bus_unregister_driver(&vmbus_acpi_driver);
hv_cpu_hotplug_quirk(false); hv_cpu_hotplug_quirk(false);
vmbus_disconnect();
} }
......
...@@ -371,6 +371,17 @@ config SENSORS_DS1621 ...@@ -371,6 +371,17 @@ config SENSORS_DS1621
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called ds1621. will be called ds1621.
config SENSORS_DELL_SMM
tristate "Dell laptop SMM BIOS hwmon driver"
depends on X86
help
This hwmon driver adds support for reporting temperature of different
sensors and controls the fans on Dell laptops via System Management
Mode provided by Dell BIOS.
When option I8K is also enabled this driver provides legacy /proc/i8k
userspace interface for i8kutils package.
config SENSORS_DA9052_ADC config SENSORS_DA9052_ADC
tristate "Dialog DA9052/DA9053 ADC" tristate "Dialog DA9052/DA9053 ADC"
depends on PMIC_DA9052 depends on PMIC_DA9052
......
...@@ -49,6 +49,7 @@ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o ...@@ -49,6 +49,7 @@ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o
obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
obj-$(CONFIG_SENSORS_DELL_SMM) += dell-smm-hwmon.o
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
obj-$(CONFIG_SENSORS_DS620) += ds620.o obj-$(CONFIG_SENSORS_DS620) += ds620.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
......
...@@ -58,4 +58,23 @@ config CORESIGHT_SOURCE_ETM3X ...@@ -58,4 +58,23 @@ config CORESIGHT_SOURCE_ETM3X
which allows tracing the instructions that a processor is executing which allows tracing the instructions that a processor is executing
This is primarily useful for instruction level tracing. Depending This is primarily useful for instruction level tracing. Depending
the ETM version data tracing may also be available. the ETM version data tracing may also be available.
config CORESIGHT_SOURCE_ETM4X
bool "CoreSight Embedded Trace Macrocell 4.x driver"
depends on ARM64
select CORESIGHT_LINKS_AND_SINKS
help
This driver provides support for the ETM4.x tracer module, tracing the
instructions that a processor is executing. This is primarily useful
for instruction level tracing. Depending on the implemented version
data tracing may also be available.
config CORESIGHT_QCOM_REPLICATOR
bool "Qualcomm CoreSight Replicator driver"
depends on CORESIGHT_LINKS_AND_SINKS
help
This enables support for Qualcomm CoreSight link driver. The
programmable ATB replicator sends the ATB trace stream from the
ETB/ETF to the TPIUi and ETR.
endif endif
...@@ -9,3 +9,5 @@ obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o ...@@ -9,3 +9,5 @@ obj-$(CONFIG_CORESIGHT_SINK_ETBV10) += coresight-etb10.o
obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \ obj-$(CONFIG_CORESIGHT_LINKS_AND_SINKS) += coresight-funnel.o \
coresight-replicator.o coresight-replicator.o
obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o
obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o
obj-$(CONFIG_CORESIGHT_QCOM_REPLICATOR) += coresight-replicator-qcom.o
...@@ -140,8 +140,8 @@ ...@@ -140,8 +140,8 @@
* struct etm_drvdata - specifics associated to an ETM component * struct etm_drvdata - specifics associated to an ETM component
* @base: memory mapped base address for this component. * @base: memory mapped base address for this component.
* @dev: the device entity associated to this component. * @dev: the device entity associated to this component.
* @atclk: optional clock for the core parts of the ETM.
* @csdev: component vitals needed by the framework. * @csdev: component vitals needed by the framework.
* @clk: the clock this component is associated to.
* @spinlock: only one at a time pls. * @spinlock: only one at a time pls.
* @cpu: the cpu this component is affined to. * @cpu: the cpu this component is affined to.
* @port_size: port size as reported by ETMCR bit 4-6 and 21. * @port_size: port size as reported by ETMCR bit 4-6 and 21.
...@@ -192,8 +192,8 @@ ...@@ -192,8 +192,8 @@
struct etm_drvdata { struct etm_drvdata {
void __iomem *base; void __iomem *base;
struct device *dev; struct device *dev;
struct clk *atclk;
struct coresight_device *csdev; struct coresight_device *csdev;
struct clk *clk;
spinlock_t spinlock; spinlock_t spinlock;
int cpu; int cpu;
int port_size; int port_size;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -37,7 +37,7 @@ of_coresight_get_endpoint_device(struct device_node *endpoint) ...@@ -37,7 +37,7 @@ of_coresight_get_endpoint_device(struct device_node *endpoint)
struct device *dev = NULL; struct device *dev = NULL;
/* /*
* If we have a non-configuable replicator, it will be found on the * If we have a non-configurable replicator, it will be found on the
* platform bus. * platform bus.
*/ */
dev = bus_find_device(&platform_bus_type, NULL, dev = bus_find_device(&platform_bus_type, NULL,
......
此差异已折叠。
...@@ -520,7 +520,6 @@ source "drivers/misc/eeprom/Kconfig" ...@@ -520,7 +520,6 @@ source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig" source "drivers/misc/cb710/Kconfig"
source "drivers/misc/ti-st/Kconfig" source "drivers/misc/ti-st/Kconfig"
source "drivers/misc/lis3lv02d/Kconfig" source "drivers/misc/lis3lv02d/Kconfig"
source "drivers/misc/carma/Kconfig"
source "drivers/misc/altera-stapl/Kconfig" 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"
......
...@@ -44,7 +44,6 @@ obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o ...@@ -44,7 +44,6 @@ obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o
obj-$(CONFIG_PCH_PHUB) += pch_phub.o obj-$(CONFIG_PCH_PHUB) += pch_phub.o
obj-y += ti-st/ obj-y += ti-st/
obj-y += lis3lv02d/ obj-y += lis3lv02d/
obj-y += carma/
obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_INTEL_MEI) += mei/
......
config CARMA_FPGA
tristate "CARMA DATA-FPGA Access Driver"
depends on FSL_SOC && PPC_83xx && HAS_DMA && FSL_DMA
default n
help
Say Y here to include support for communicating with the data
processing FPGAs on the OVRO CARMA board.
config CARMA_FPGA_PROGRAM
tristate "CARMA DATA-FPGA Programmer"
depends on FSL_SOC && PPC_83xx && HAS_DMA && FSL_DMA
default n
help
Say Y here to include support for programming the data processing
FPGAs on the OVRO CARMA board.
obj-$(CONFIG_CARMA_FPGA) += carma-fpga.o
obj-$(CONFIG_CARMA_FPGA_PROGRAM) += carma-fpga-program.o
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册