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

Merge tag 'mfd-for-linus-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd

Pull MFD updates from Lee Jones:
 "Changes to existing drivers:
   - Use of managed resources - omap, twl4030, ti_am335x_tscadc
   - Advanced error handling - omap
   - Rework clk management - omap
   - Device Tree (re-)work - tc3589x, pm8921, da9055, sec
   - IRC management overhaul and !BROKEN - pm8921
   - Convert to regmap - ssbi, pm8921
   - Use simple power-management ops - ucb1x00
   - Include file clean-up - adp5520, cs5535, janz, lpc_ich,
      - lpc_sch, max14577, mcp-sa11x0, pcf50633-adc, rc5t583,
      	rdc321x-southbridge, retu, smsc-ece1099, ti-ssp, ti_am335x_tscadc,
	tps65912, vexpress-config, wm8350, ywm8350
   - Various bug fixes across the subsystem
      - NULL/invalid pointer dereference prevention
      - Resource leak mitigation,
      - Variable used initialised
      - Staticise various containers
      - Enforce return value checks

  New drivers/supported devices:
   - Add support for s2mps14 and s2mpa01 to sec
   - Add support for da9063 (v5) to da9063
   - Add support for atom-c2000 to gpio-ich
   - Add support for come-{mbt10,cbt6,chl6} to kempld
   - Add support for da9053 to da9052
   - Add support for itco-wdt (v3) and baytrail to lpc_ich
   - Add new drivers for tps65218, rtsx_usb, bcm590xx

  (Re-)moved drivers:
   - twl4030 ==> drivers/iio
   - ti-ssp  ==> /dev/null"

* tag 'mfd-for-linus-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (103 commits)
  mfd: wm5110: Correct default for HEADPHONE_DETECT_1
  mfd: arizona: Correct small errors in the DT binding documentation
  mfd: arizona: Mark DSP clocking register as volatile
  mfd: devicetree: bindings: Add pm8xxx RTC description
  mfd: kempld-core: Fix potential hang-up during boot
  mfd: sec-core: Fix uninitialized 'regmap_rtc' on S2MPA01
  mfd: tps65910: Fix regmap_irq_chip_data leak on mfd_add_devices fail
  mfd: tps65910: Fix possible invalid pointer dereference on regmap_add_irq_chip fail
  mfd: sec-core: Fix I2C dummy device resource leak on probe failure
  mfd: sec-core: Add of_compatible strings for clock MFD cells
  mfd: Remove obsolete ti-ssp driver
  Documentation: mfd: s2mps11: Describe S5M8767 and S2MPS14 clocks
  mfd: bcm590xx: Fix type argument for module device table
  mfd: lpc_ich: Add support for Intel Bay Trail SoC
  mfd: lpc_ich: Add support for NM10 GPIO
  mfd: lpc_ich: Change Avoton to iTCO v3
  watchdog: iTCO_wdt: Add support for v3 silicon
  mfd: lpc_ich: Add support for iTCO v3
  mfd: lpc_ich: Remove lpc_ich_cfg struct use
  mfd: lpc_ich: Only configure watchdog or GPIO when present
  ...
无相关合并请求
* TWL4030 Monitoring Analog to Digital Converter (MADC)
The MADC subsystem in the TWL4030 consists of a 10-bit ADC
combined with a 16-input analog multiplexer.
Required properties:
- compatible: Should contain "ti,twl4030-madc".
- interrupts: IRQ line for the MADC submodule.
- #io-channel-cells: Should be set to <1>.
Optional properties:
- ti,system-uses-second-madc-irq: boolean, set if the second madc irq register
should be used, which is intended to be used
by Co-Processors (e.g. a modem).
Example:
&twl {
madc {
compatible = "ti,twl4030-madc";
interrupts = <3>;
#io-channel-cells = <1>;
};
};
......@@ -5,9 +5,10 @@ of analogue I/O.
Required properties:
- compatible : one of the following chip-specific strings:
"wlf,wm5102"
"wlf,wm5110"
- compatible : One of the following chip-specific strings:
"wlf,wm5102"
"wlf,wm5110"
"wlf,wm8997"
- reg : I2C slave address when connected using I2C, chip select number when
using SPI.
......@@ -25,8 +26,9 @@ Required properties:
- #gpio-cells : Must be 2. The first cell is the pin number and the
second cell is used to specify optional parameters (currently unused).
- AVDD1-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply, CPVDD-supply,
SPKVDDL-supply, SPKVDDR-supply : power supplies for the device, as covered
- AVDD-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply (wm5102, wm5110),
CPVDD-supply, SPKVDDL-supply (wm5102, wm5110), SPKVDDR-supply (wm5102,
wm5110), SPKVDD-supply (wm8997) : Power supplies for the device, as covered
in Documentation/devicetree/bindings/regulator/regulator.txt
Optional properties:
......@@ -46,6 +48,7 @@ codec: wm5102@1a {
compatible = "wlf,wm5102";
reg = <0x1a>;
interrupts = <347>;
interrupt-controller;
#interrupt-cells = <2>;
interrupt-parent = <&gic>;
......@@ -53,10 +56,10 @@ codec: wm5102@1a {
#gpio-cells = <2>;
wlf,gpio-defaults = <
0x00000000, /* AIF1TXLRCLK */
0xffffffff,
0xffffffff,
0xffffffff,
0xffffffff,
0x00000000 /* AIF1TXLRCLK */
0xffffffff
0xffffffff
0xffffffff
0xffffffff
>;
};
-------------------------------
BCM590xx Power Management Units
-------------------------------
Required properties:
- compatible: "brcm,bcm59056"
- reg: I2C slave address
- interrupts: interrupt for the PMU. Generic interrupt client node bindings
are described in interrupt-controller/interrupts.txt
------------------
Voltage Regulators
------------------
Optional child nodes:
- regulators: container node for regulators following the generic
regulator binding in regulator/regulator.txt
The valid regulator node names for BCM59056 are:
rfldo, camldo1, camldo2, simldo1, simldo2, sdldo, sdxldo,
mmcldo1, mmcldo2, audldo, micldo, usbldo, vibldo,
csr, iosr1, iosr2, msr, sdsr1, sdsr2, vsr
Example:
pmu: bcm59056@8 {
compatible = "brcm,bcm59056";
reg = <0x08>;
interrupts = <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>;
regulators {
rfldo_reg: rfldo {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3300000>;
};
...
};
};
* Dialog DA9055 Power Management Integrated Circuit (PMIC)
DA9055 consists of a large and varied group of sub-devices (I2C Only):
Device Supply Names Description
------ ------------ -----------
da9055-gpio : : GPIOs
da9055-regulator : : Regulators
da9055-onkey : : On key
da9055-rtc : : RTC
da9055-hwmon : : ADC
da9055-watchdog : : Watchdog
The CODEC device in DA9055 has a separate, configurable I2C address and so
is instantiated separately from the PMIC.
For details on accompanying CODEC I2C device, see the following:
Documentation/devicetree/bindings/sound/da9055.txt
======
Required properties:
- compatible : Should be "dlg,da9055-pmic"
- reg: Specifies the I2C slave address (defaults to 0x5a but can be modified)
- interrupt-parent: Specifies the phandle of the interrupt controller to which
the IRQs from da9055 are delivered to.
- interrupts: IRQ line info for da9055 chip.
- interrupt-controller: da9055 has internal IRQs (has own IRQ domain).
- #interrupt-cells: Should be 1, is the local IRQ number for da9055.
Sub-nodes:
- regulators : Contain the regulator nodes. The DA9055 regulators are
bound using their names as listed below:
buck1 : regulator BUCK1
buck2 : regulator BUCK2
ldo1 : regulator LDO1
ldo2 : regulator LDO2
ldo3 : regulator LDO3
ldo4 : regulator LDO4
ldo5 : regulator LDO5
ldo6 : regulator LDO6
The bindings details of individual regulator device can be found in:
Documentation/devicetree/bindings/regulator/regulator.txt
Example:
pmic: da9055-pmic@5a {
compatible = "dlg,da9055-pmic";
reg = <0x5a>;
interrupt-parent = <&intc>;
interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
interrupt-controller;
#interrupt-cells = <1>;
regulators {
buck1: BUCK1 {
regulator-min-microvolt = <725000>;
regulator-max-microvolt = <2075000>;
};
buck2: BUCK2 {
regulator-min-microvolt = <925000>;
regulator-max-microvolt = <2500000>;
};
ldo1: LDO1 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <3300000>;
};
};
};
......@@ -32,6 +32,29 @@ Optional properties:
- single-ulpi-bypass: Must be present if the controller contains a single
ULPI bypass control bit. e.g. OMAP3 silicon <= ES2.1
- clocks: a list of phandles and clock-specifier pairs, one for each entry in
clock-names.
- clock-names: should include:
For OMAP3
* "usbhost_120m_fck" - 120MHz Functional clock.
For OMAP4+
* "refclk_60m_int" - 60MHz internal reference clock for UTMI clock mux
* "refclk_60m_ext_p1" - 60MHz external ref. clock for Port 1's UTMI clock mux.
* "refclk_60m_ext_p2" - 60MHz external ref. clock for Port 2's UTMI clock mux
* "utmi_p1_gfclk" - Port 1 UTMI clock mux.
* "utmi_p2_gfclk" - Port 2 UTMI clock mux.
* "usb_host_hs_utmi_p1_clk" - Port 1 UTMI clock gate.
* "usb_host_hs_utmi_p2_clk" - Port 2 UTMI clock gate.
* "usb_host_hs_utmi_p3_clk" - Port 3 UTMI clock gate.
* "usb_host_hs_hsic480m_p1_clk" - Port 1 480MHz HSIC clock gate.
* "usb_host_hs_hsic480m_p2_clk" - Port 2 480MHz HSIC clock gate.
* "usb_host_hs_hsic480m_p3_clk" - Port 3 480MHz HSIC clock gate.
* "usb_host_hs_hsic60m_p1_clk" - Port 1 60MHz HSIC clock gate.
* "usb_host_hs_hsic60m_p2_clk" - Port 2 60MHz HSIC clock gate.
* "usb_host_hs_hsic60m_p3_clk" - Port 3 60MHz HSIC clock gate.
Required properties if child node exists:
- #address-cells: Must be 1
......
......@@ -7,6 +7,16 @@ Required properties:
- interrupts : should contain the TLL module's interrupt
- ti,hwmod : must contain "usb_tll_hs"
Optional properties:
- clocks: a list of phandles and clock-specifier pairs, one for each entry in
clock-names.
- clock-names: should include:
* "usb_tll_hs_usb_ch0_clk" - USB TLL channel 0 clock
* "usb_tll_hs_usb_ch1_clk" - USB TLL channel 1 clock
* "usb_tll_hs_usb_ch2_clk" - USB TLL channel 2 clock
Example:
usbhstll: usbhstll@4a062000 {
......
Qualcomm PM8xxx PMIC multi-function devices
The PM8xxx family of Power Management ICs are used to provide regulated
voltages and other various functionality to Qualcomm SoCs.
= PROPERTIES
- compatible:
Usage: required
Value type: <string>
Definition: must be one of:
"qcom,pm8058"
"qcom,pm8921"
- #address-cells:
Usage: required
Value type: <u32>
Definition: must be 1
- #size-cells:
Usage: required
Value type: <u32>
Definition: must be 0
- interrupts:
Usage: required
Value type: <prop-encoded-array>
Definition: specifies the interrupt that indicates a subdevice
has generated an interrupt (summary interrupt). The
format of the specifier is defined by the binding document
describing the node's interrupt parent.
- #interrupt-cells:
Usage: required
Value type : <u32>
Definition: must be 2. Specifies the number of cells needed to encode
an interrupt source. The 1st cell contains the interrupt
number. The 2nd cell is the trigger type and level flags
encoded as follows:
1 = low-to-high edge triggered
2 = high-to-low edge triggered
4 = active high level-sensitive
8 = active low level-sensitive
- interrupt-controller:
Usage: required
Value type: <empty>
Definition: identifies this node as an interrupt controller
= SUBCOMPONENTS
The PMIC contains multiple independent functions, each described in a subnode.
The below bindings specify the set of valid subnodes.
== Real-Time Clock
- compatible:
Usage: required
Value type: <string>
Definition: must be one of:
"qcom,pm8058-rtc"
"qcom,pm8921-rtc"
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: single entry specifying the base address of the RTC registers
- interrupts:
Usage: required
Value type: <prop-encoded-array>
Definition: single entry specifying the RTC's alarm interrupt
- allow-set-time:
Usage: optional
Value type: <empty>
Definition: indicates that the setting of RTC time is allowed by
the host CPU
= EXAMPLE
pmicintc: pmic@0 {
compatible = "qcom,pm8921";
interrupts = <104 8>;
#interrupt-cells = <2>;
interrupt-controller;
#address-cells = <1>;
#size-cells = <0>;
rtc@11d {
compatible = "qcom,pm8921-rtc";
reg = <0x11d>;
interrupts = <0x27 0>;
};
};
......@@ -16,20 +16,25 @@ Optional properties:
- interrupts: Interrupt specifiers for interrupt sources.
Optional nodes:
- clocks: s2mps11 provides three(AP/CP/BT) buffered 32.768 KHz outputs, so to
register these as clocks with common clock framework instantiate a sub-node
named "clocks". It uses the common clock binding documented in :
- clocks: s2mps11 and s5m8767 provide three(AP/CP/BT) buffered 32.768 KHz
outputs, so to register these as clocks with common clock framework
instantiate a sub-node named "clocks". It uses the common clock binding
documented in :
[Documentation/devicetree/bindings/clock/clock-bindings.txt]
The s2mps14 provides two (AP/BT) buffered 32.768 KHz outputs.
- #clock-cells: should be 1.
- The following is the list of clocks generated by the controller. Each clock
is assigned an identifier and client nodes use this identifier to specify
the clock which they consume.
Clock ID
----------------------
32KhzAP 0
32KhzCP 1
32KhzBT 2
Clock ID Devices
----------------------------------------------------------
32KhzAP 0 S2MPS11, S2MPS14, S5M8767
32KhzCP 1 S2MPS11, S5M8767
32KhzBT 2 S2MPS11, S2MPS14, S5M8767
- compatible: Should be one of: "samsung,s2mps11-clk", "samsung,s2mps14-clk",
"samsung,s5m8767-clk"
- regulators: The regulators of s2mps11 that have to be instantiated should be
included in a sub-node named 'regulators'. Regulator nodes included in this
......@@ -75,7 +80,8 @@ Example:
compatible = "samsung,s2mps11-pmic";
reg = <0x66>;
s2m_osc: clocks{
s2m_osc: clocks {
compatible = "samsung,s2mps11-clk";
#clock-cells = 1;
clock-output-names = "xx", "yy", "zz";
};
......
......@@ -733,6 +733,12 @@
#address-cells = <1>;
#size-cells = <1>;
ranges;
clocks = <&init_60m_fclk>,
<&xclk60mhsp1_ck>,
<&xclk60mhsp2_ck>;
clock-names = "refclk_60m_int",
"refclk_60m_ext_p1",
"refclk_60m_ext_p2";
usbhsohci: ohci@4a064800 {
compatible = "ti,ohci-omap3";
......
......@@ -814,6 +814,12 @@
#address-cells = <1>;
#size-cells = <1>;
ranges;
clocks = <&l3init_60m_fclk>,
<&xclk60mhsp1_ck>,
<&xclk60mhsp2_ck>;
clock-names = "refclk_60m_int",
"refclk_60m_ext_p1",
"refclk_60m_ext_p2";
usbhsohci: ohci@4a064800 {
compatible = "ti,ohci-omap3";
......
......@@ -3497,10 +3497,6 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "dss_tv_fck", &dss_tv_fck),
CLK(NULL, "dss_96m_fck", &dss_96m_fck),
CLK(NULL, "dss2_alwon_fck", &dss2_alwon_fck),
CLK(NULL, "utmi_p1_gfclk", &dummy_ck),
CLK(NULL, "utmi_p2_gfclk", &dummy_ck),
CLK(NULL, "xclk60mhsp1_ck", &dummy_ck),
CLK(NULL, "xclk60mhsp2_ck", &dummy_ck),
CLK(NULL, "init_60m_fclk", &dummy_ck),
CLK(NULL, "gpt1_fck", &gpt1_fck),
CLK(NULL, "aes2_ick", &aes2_ick),
......
......@@ -1955,10 +1955,6 @@ static struct omap_hwmod_class omap3xxx_usb_host_hs_hwmod_class = {
.sysc = &omap3xxx_usb_host_hs_sysc,
};
static struct omap_hwmod_opt_clk omap3xxx_usb_host_hs_opt_clks[] = {
{ .role = "ehci_logic_fck", .clk = "usbhost_120m_fck", },
};
static struct omap_hwmod_irq_info omap3xxx_usb_host_hs_irqs[] = {
{ .name = "ohci-irq", .irq = 76 + OMAP_INTC_START, },
{ .name = "ehci-irq", .irq = 77 + OMAP_INTC_START, },
......@@ -1981,8 +1977,6 @@ static struct omap_hwmod omap3xxx_usb_host_hs_hwmod = {
.idlest_stdby_bit = OMAP3430ES2_ST_USBHOST_STDBY_SHIFT,
},
},
.opt_clks = omap3xxx_usb_host_hs_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(omap3xxx_usb_host_hs_opt_clks),
/*
* Errata: USBHOST Configured In Smart-Idle Can Lead To a Deadlock
......
......@@ -130,10 +130,6 @@ static struct ti_dt_clk omap3xxx_clks[] = {
DT_CLK(NULL, "dss_tv_fck", "dss_tv_fck"),
DT_CLK(NULL, "dss_96m_fck", "dss_96m_fck"),
DT_CLK(NULL, "dss2_alwon_fck", "dss2_alwon_fck"),
DT_CLK(NULL, "utmi_p1_gfclk", "dummy_ck"),
DT_CLK(NULL, "utmi_p2_gfclk", "dummy_ck"),
DT_CLK(NULL, "xclk60mhsp1_ck", "dummy_ck"),
DT_CLK(NULL, "xclk60mhsp2_ck", "dummy_ck"),
DT_CLK(NULL, "init_60m_fclk", "dummy_ck"),
DT_CLK(NULL, "gpt1_fck", "gpt1_fck"),
DT_CLK(NULL, "aes2_ick", "aes2_ick"),
......
/*
* Intel ICH6-10, Series 5 and 6 GPIO driver
* Intel ICH6-10, Series 5 and 6, Atom C2000 (Avoton/Rangeley) GPIO driver
*
* Copyright (C) 2010 Extreme Engineering Solutions.
*
......@@ -55,6 +55,16 @@ static const u8 ichx_reglen[3] = {
0x30, 0x10, 0x10,
};
static const u8 avoton_regs[4][3] = {
{0x00, 0x80, 0x00},
{0x04, 0x84, 0x00},
{0x08, 0x88, 0x00},
};
static const u8 avoton_reglen[3] = {
0x10, 0x10, 0x00,
};
#define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start)
#define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start)
......@@ -353,6 +363,17 @@ static struct ichx_desc intel5_desc = {
.reglen = ichx_reglen,
};
/* Avoton */
static struct ichx_desc avoton_desc = {
/* Avoton has only 59 GPIOs, but we assume the first set of register
* (Core) has 32 instead of 31 to keep gpio-ich compliance
*/
.ngpio = 60,
.regs = avoton_regs,
.reglen = avoton_reglen,
.use_outlvl_cache = true,
};
static int ichx_gpio_request_regions(struct resource *res_base,
const char *name, u8 use_gpio)
{
......@@ -427,6 +448,9 @@ static int ichx_gpio_probe(struct platform_device *pdev)
case ICH_V10CONS_GPIO:
ichx_priv.desc = &ich10_cons_desc;
break;
case AVOTON_GPIO:
ichx_priv.desc = &avoton_desc;
break;
default:
return -ENODEV;
}
......
......@@ -193,6 +193,16 @@ config TI_AM335X_ADC
Say yes here to build support for Texas Instruments ADC
driver which is also a MFD client.
config TWL4030_MADC
tristate "TWL4030 MADC (Monitoring A/D Converter)"
depends on TWL4030_CORE
help
This driver provides support for Triton TWL4030-MADC. The
driver supports both RT and SW conversion methods.
This driver can also be built as a module. If so, the module will be
called twl4030-madc.
config TWL6030_GPADC
tristate "TWL6030 GPADC (General Purpose A/D Converter) Support"
depends on TWL4030_CORE
......
......@@ -21,6 +21,7 @@ obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
......
......@@ -29,7 +29,6 @@
*
*/
#include <linux/init.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
......@@ -47,20 +46,84 @@
#include <linux/gfp.h>
#include <linux/err.h>
/*
#include <linux/iio/iio.h>
/**
* struct twl4030_madc_data - a container for madc info
* @dev - pointer to device structure for madc
* @lock - mutex protecting this data structure
* @requests - Array of request struct corresponding to SW1, SW2 and RT
* @imr - Interrupt mask register of MADC
* @isr - Interrupt status register of MADC
* @dev: Pointer to device structure for madc
* @lock: Mutex protecting this data structure
* @requests: Array of request struct corresponding to SW1, SW2 and RT
* @use_second_irq: IRQ selection (main or co-processor)
* @imr: Interrupt mask register of MADC
* @isr: Interrupt status register of MADC
*/
struct twl4030_madc_data {
struct device *dev;
struct mutex lock; /* mutex protecting this data structure */
struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
int imr;
int isr;
bool use_second_irq;
u8 imr;
u8 isr;
};
static int twl4030_madc_read(struct iio_dev *iio_dev,
const struct iio_chan_spec *chan,
int *val, int *val2, long mask)
{
struct twl4030_madc_data *madc = iio_priv(iio_dev);
struct twl4030_madc_request req;
int ret;
req.method = madc->use_second_irq ? TWL4030_MADC_SW2 : TWL4030_MADC_SW1;
req.channels = BIT(chan->channel);
req.active = false;
req.func_cb = NULL;
req.type = TWL4030_MADC_WAIT;
req.raw = !(mask == IIO_CHAN_INFO_PROCESSED);
req.do_avg = (mask == IIO_CHAN_INFO_AVERAGE_RAW);
ret = twl4030_madc_conversion(&req);
if (ret < 0)
return ret;
*val = req.rbuf[chan->channel];
return IIO_VAL_INT;
}
static const struct iio_info twl4030_madc_iio_info = {
.read_raw = &twl4030_madc_read,
.driver_module = THIS_MODULE,
};
#define TWL4030_ADC_CHANNEL(_channel, _type, _name) { \
.type = _type, \
.channel = _channel, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \
BIT(IIO_CHAN_INFO_PROCESSED), \
.datasheet_name = _name, \
.indexed = 1, \
}
static const struct iio_chan_spec twl4030_madc_iio_channels[] = {
TWL4030_ADC_CHANNEL(0, IIO_VOLTAGE, "ADCIN0"),
TWL4030_ADC_CHANNEL(1, IIO_TEMP, "ADCIN1"),
TWL4030_ADC_CHANNEL(2, IIO_VOLTAGE, "ADCIN2"),
TWL4030_ADC_CHANNEL(3, IIO_VOLTAGE, "ADCIN3"),
TWL4030_ADC_CHANNEL(4, IIO_VOLTAGE, "ADCIN4"),
TWL4030_ADC_CHANNEL(5, IIO_VOLTAGE, "ADCIN5"),
TWL4030_ADC_CHANNEL(6, IIO_VOLTAGE, "ADCIN6"),
TWL4030_ADC_CHANNEL(7, IIO_VOLTAGE, "ADCIN7"),
TWL4030_ADC_CHANNEL(8, IIO_VOLTAGE, "ADCIN8"),
TWL4030_ADC_CHANNEL(9, IIO_VOLTAGE, "ADCIN9"),
TWL4030_ADC_CHANNEL(10, IIO_CURRENT, "ADCIN10"),
TWL4030_ADC_CHANNEL(11, IIO_VOLTAGE, "ADCIN11"),
TWL4030_ADC_CHANNEL(12, IIO_VOLTAGE, "ADCIN12"),
TWL4030_ADC_CHANNEL(13, IIO_VOLTAGE, "ADCIN13"),
TWL4030_ADC_CHANNEL(14, IIO_VOLTAGE, "ADCIN14"),
TWL4030_ADC_CHANNEL(15, IIO_VOLTAGE, "ADCIN15"),
};
static struct twl4030_madc_data *twl4030_madc;
......@@ -91,17 +154,16 @@ twl4030_divider_ratios[16] = {
};
/*
* Conversion table from -3 to 55 degree Celcius
*/
static int therm_tbl[] = {
30800, 29500, 28300, 27100,
26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
11600, 11200, 10800, 10400, 10000, 9630, 9280, 8950, 8620, 8310,
8020, 7730, 7460, 7200, 6950, 6710, 6470, 6250, 6040, 5830,
5640, 5450, 5260, 5090, 4920, 4760, 4600, 4450, 4310, 4170,
4040, 3910, 3790, 3670, 3550
/* Conversion table from -3 to 55 degrees Celcius */
static int twl4030_therm_tbl[] = {
30800, 29500, 28300, 27100,
26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700,
17900, 17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100,
12600, 12100, 11600, 11200, 10800, 10400, 10000, 9630, 9280,
8950, 8620, 8310, 8020, 7730, 7460, 7200, 6950, 6710,
6470, 6250, 6040, 5830, 5640, 5450, 5260, 5090, 4920,
4760, 4600, 4450, 4310, 4170, 4040, 3910, 3790, 3670,
3550
};
/*
......@@ -133,37 +195,32 @@ const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
},
};
/*
* Function to read a particular channel value.
* @madc - pointer to struct twl4030_madc_data
* @reg - lsb of ADC Channel
* If the i2c read fails it returns an error else returns 0.
/**
* twl4030_madc_channel_raw_read() - Function to read a particular channel value
* @madc: pointer to struct twl4030_madc_data
* @reg: lsb of ADC Channel
*
* Return: 0 on success, an error code otherwise.
*/
static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
{
u8 msb, lsb;
u16 val;
int ret;
/*
* For each ADC channel, we have MSB and LSB register pair. MSB address
* is always LSB address+1. reg parameter is the address of LSB register
*/
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &msb, reg + 1);
ret = twl_i2c_read_u16(TWL4030_MODULE_MADC, &val, reg);
if (ret) {
dev_err(madc->dev, "unable to read MSB register 0x%X\n",
reg + 1);
return ret;
}
ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &lsb, reg);
if (ret) {
dev_err(madc->dev, "unable to read LSB register 0x%X\n", reg);
dev_err(madc->dev, "unable to read register 0x%X\n", reg);
return ret;
}
return (int)(((msb << 8) | lsb) >> 6);
return (int)(val >> 6);
}
/*
* Return battery temperature
* Return battery temperature in degrees Celsius
* Or < 0 on failure.
*/
static int twl4030battery_temperature(int raw_volt)
......@@ -172,18 +229,18 @@ static int twl4030battery_temperature(int raw_volt)
int temp, curr, volt, res, ret;
volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
/* Getting and calculating the supply current in micro ampers */
/* Getting and calculating the supply current in micro amperes */
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
REG_BCICTL2);
if (ret < 0)
return ret;
curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10;
/* Getting and calculating the thermistor resistance in ohms */
res = volt * 1000 / curr;
/* calculating temperature */
for (temp = 58; temp >= 0; temp--) {
int actual = therm_tbl[temp];
int actual = twl4030_therm_tbl[temp];
if ((actual - res) >= 0)
break;
}
......@@ -205,11 +262,12 @@ static int twl4030battery_current(int raw_volt)
else /* slope of 0.88 mV/mA */
return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2;
}
/*
* Function to read channel values
* @madc - pointer to twl4030_madc_data struct
* @reg_base - Base address of the first channel
* @Channels - 16 bit bitmap. If the bit is set, channel value is read
* @Channels - 16 bit bitmap. If the bit is set, channel's value is read
* @buf - The channel values are stored here. if read fails error
* @raw - Return raw values without conversion
* value is stored
......@@ -220,17 +278,17 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
long channels, int *buf,
bool raw)
{
int count = 0, count_req = 0, i;
int count = 0;
int i;
u8 reg;
for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
reg = reg_base + 2 * i;
reg = reg_base + (2 * i);
buf[i] = twl4030_madc_channel_raw_read(madc, reg);
if (buf[i] < 0) {
dev_err(madc->dev,
"Unable to read register 0x%X\n", reg);
count_req++;
continue;
dev_err(madc->dev, "Unable to read register 0x%X\n",
reg);
return buf[i];
}
if (raw) {
count++;
......@@ -241,7 +299,7 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
buf[i] = twl4030battery_current(buf[i]);
if (buf[i] < 0) {
dev_err(madc->dev, "err reading current\n");
count_req++;
return buf[i];
} else {
count++;
buf[i] = buf[i] - 750;
......@@ -251,7 +309,7 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
buf[i] = twl4030battery_temperature(buf[i]);
if (buf[i] < 0) {
dev_err(madc->dev, "err reading temperature\n");
count_req++;
return buf[i];
} else {
buf[i] -= 3;
count++;
......@@ -272,8 +330,6 @@ static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
twl4030_divider_ratios[i].numerator);
}
}
if (count_req)
dev_err(madc->dev, "%d channel conversion failed\n", count_req);
return count;
}
......@@ -297,13 +353,13 @@ static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
madc->imr);
return ret;
}
val &= ~(1 << id);
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
if (ret) {
dev_err(madc->dev,
"unable to write imr register 0x%X\n", madc->imr);
return ret;
}
return 0;
......@@ -366,7 +422,7 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
continue;
ret = twl4030_madc_disable_irq(madc, i);
if (ret < 0)
dev_dbg(madc->dev, "Disable interrupt failed%d\n", i);
dev_dbg(madc->dev, "Disable interrupt failed %d\n", i);
madc->requests[i].result_pending = 1;
}
for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
......@@ -448,21 +504,17 @@ static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
{
const struct twl4030_madc_conversion_method *method;
int ret = 0;
if (conv_method != TWL4030_MADC_SW1 && conv_method != TWL4030_MADC_SW2)
return -ENOTSUPP;
method = &twl4030_conversion_methods[conv_method];
switch (conv_method) {
case TWL4030_MADC_SW1:
case TWL4030_MADC_SW2:
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
TWL4030_MADC_SW_START, method->ctrl);
if (ret) {
dev_err(madc->dev,
"unable to write ctrl register 0x%X\n",
method->ctrl);
return ret;
}
break;
default:
break;
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, TWL4030_MADC_SW_START,
method->ctrl);
if (ret) {
dev_err(madc->dev, "unable to write ctrl register 0x%X\n",
method->ctrl);
return ret;
}
return 0;
......@@ -513,7 +565,6 @@ static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
int twl4030_madc_conversion(struct twl4030_madc_request *req)
{
const struct twl4030_madc_conversion_method *method;
u8 ch_msb, ch_lsb;
int ret;
if (!req || !twl4030_madc)
......@@ -529,38 +580,22 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
ret = -EBUSY;
goto out;
}
ch_msb = (req->channels >> 8) & 0xff;
ch_lsb = req->channels & 0xff;
method = &twl4030_conversion_methods[req->method];
/* Select channels to be converted */
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_msb, method->sel + 1);
if (ret) {
dev_err(twl4030_madc->dev,
"unable to write sel register 0x%X\n", method->sel + 1);
goto out;
}
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel);
ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels, method->sel);
if (ret) {
dev_err(twl4030_madc->dev,
"unable to write sel register 0x%X\n", method->sel + 1);
"unable to write sel register 0x%X\n", method->sel);
goto out;
}
/* Select averaging for all channels if do_avg is set */
if (req->do_avg) {
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
ch_msb, method->avg + 1);
ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels,
method->avg);
if (ret) {
dev_err(twl4030_madc->dev,
"unable to write avg register 0x%X\n",
method->avg + 1);
goto out;
}
ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
ch_lsb, method->avg);
if (ret) {
dev_err(twl4030_madc->dev,
"unable to write sel reg 0x%X\n",
method->sel + 1);
method->avg);
goto out;
}
}
......@@ -601,10 +636,6 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
}
EXPORT_SYMBOL_GPL(twl4030_madc_conversion);
/*
* Return channel value
* Or < 0 on failure.
*/
int twl4030_get_madc_conversion(int channel_no)
{
struct twl4030_madc_request req;
......@@ -625,20 +656,25 @@ int twl4030_get_madc_conversion(int channel_no)
}
EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion);
/*
/**
* twl4030_madc_set_current_generator() - setup bias current
*
* @madc: pointer to twl4030_madc_data struct
* @chan: can be one of the two values:
* TWL4030_BCI_ITHEN
* Enables bias current for main battery type reading
* TWL4030_BCI_TYPEN
* Enables bias current for main battery temperature sensing
* @on: enable or disable chan.
*
* Function to enable or disable bias current for
* main battery type reading or temperature sensing
* @madc - pointer to twl4030_madc_data struct
* @chan - can be one of the two values
* TWL4030_BCI_ITHEN - Enables bias current for main battery type reading
* TWL4030_BCI_TYPEN - Enables bias current for main battery temperature
* sensing
* @on - enable or disable chan.
*/
static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
int chan, int on)
{
int ret;
int regmask;
u8 regval;
ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
......@@ -648,10 +684,13 @@ static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
TWL4030_BCI_BCICTL1);
return ret;
}
regmask = chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
if (on)
regval |= chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
regval |= regmask;
else
regval &= chan ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
regval &= ~regmask;
ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
regval, TWL4030_BCI_BCICTL1);
if (ret) {
......@@ -666,7 +705,7 @@ static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
/*
* Function that sets MADC software power on bit to enable MADC
* @madc - pointer to twl4030_madc_data struct
* @on - Enable or disable MADC software powen on bit.
* @on - Enable or disable MADC software power on bit.
* returns error if i2c read/write fails else 0
*/
static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
......@@ -702,31 +741,52 @@ static int twl4030_madc_probe(struct platform_device *pdev)
{
struct twl4030_madc_data *madc;
struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev);
int ret;
struct device_node *np = pdev->dev.of_node;
int irq, ret;
u8 regval;
struct iio_dev *iio_dev = NULL;
if (!pdata) {
dev_err(&pdev->dev, "platform_data not available\n");
if (!pdata && !np) {
dev_err(&pdev->dev, "neither platform data nor Device Tree node available\n");
return -EINVAL;
}
madc = kzalloc(sizeof(*madc), GFP_KERNEL);
if (!madc)
iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*madc));
if (!iio_dev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
return -ENOMEM;
}
madc = iio_priv(iio_dev);
madc->dev = &pdev->dev;
iio_dev->name = dev_name(&pdev->dev);
iio_dev->dev.parent = &pdev->dev;
iio_dev->dev.of_node = pdev->dev.of_node;
iio_dev->info = &twl4030_madc_iio_info;
iio_dev->modes = INDIO_DIRECT_MODE;
iio_dev->channels = twl4030_madc_iio_channels;
iio_dev->num_channels = ARRAY_SIZE(twl4030_madc_iio_channels);
/*
* Phoenix provides 2 interrupt lines. The first one is connected to
* the OMAP. The other one can be connected to the other processor such
* as modem. Hence two separate ISR and IMR registers.
*/
madc->imr = (pdata->irq_line == 1) ?
TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
madc->isr = (pdata->irq_line == 1) ?
TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
if (pdata)
madc->use_second_irq = (pdata->irq_line != 1);
else
madc->use_second_irq = of_property_read_bool(np,
"ti,system-uses-second-madc-irq");
madc->imr = madc->use_second_irq ? TWL4030_MADC_IMR2 :
TWL4030_MADC_IMR1;
madc->isr = madc->use_second_irq ? TWL4030_MADC_ISR2 :
TWL4030_MADC_ISR1;
ret = twl4030_madc_set_power(madc, 1);
if (ret < 0)
goto err_power;
return ret;
ret = twl4030_madc_set_current_generator(madc, 0, 1);
if (ret < 0)
goto err_current_generator;
......@@ -768,46 +828,63 @@ static int twl4030_madc_probe(struct platform_device *pdev)
}
}
platform_set_drvdata(pdev, madc);
platform_set_drvdata(pdev, iio_dev);
mutex_init(&madc->lock);
ret = request_threaded_irq(platform_get_irq(pdev, 0), NULL,
irq = platform_get_irq(pdev, 0);
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
twl4030_madc_threaded_irq_handler,
IRQF_TRIGGER_RISING, "twl4030_madc", madc);
if (ret) {
dev_dbg(&pdev->dev, "could not request irq\n");
dev_err(&pdev->dev, "could not request irq\n");
goto err_i2c;
}
twl4030_madc = madc;
ret = iio_device_register(iio_dev);
if (ret) {
dev_err(&pdev->dev, "could not register iio device\n");
goto err_i2c;
}
return 0;
err_i2c:
twl4030_madc_set_current_generator(madc, 0, 0);
err_current_generator:
twl4030_madc_set_power(madc, 0);
err_power:
kfree(madc);
return ret;
}
static int twl4030_madc_remove(struct platform_device *pdev)
{
struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
struct iio_dev *iio_dev = platform_get_drvdata(pdev);
struct twl4030_madc_data *madc = iio_priv(iio_dev);
iio_device_unregister(iio_dev);
free_irq(platform_get_irq(pdev, 0), madc);
twl4030_madc_set_current_generator(madc, 0, 0);
twl4030_madc_set_power(madc, 0);
kfree(madc);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id twl_madc_of_match[] = {
{ .compatible = "ti,twl4030-madc", },
{ },
};
MODULE_DEVICE_TABLE(of, twl_madc_of_match);
#endif
static struct platform_driver twl4030_madc_driver = {
.probe = twl4030_madc_probe,
.remove = twl4030_madc_remove,
.driver = {
.name = "twl4030_madc",
.owner = THIS_MODULE,
},
.of_match_table = of_match_ptr(twl_madc_of_match),
},
};
module_platform_driver(twl4030_madc_driver);
......
......@@ -571,7 +571,7 @@ static int pm800_probe(struct i2c_client *client,
ret = pm800_pages_init(chip);
if (ret) {
dev_err(&client->dev, "pm800_pages_init failed!\n");
goto err_page_init;
goto err_device_init;
}
ret = device_800_init(chip, pdata);
......@@ -587,7 +587,6 @@ static int pm800_probe(struct i2c_client *client,
err_device_init:
pm800_pages_exit(chip);
err_page_init:
err_subchip_alloc:
pm80x_deinit();
out_init:
......
......@@ -1179,12 +1179,18 @@ static int pm860x_probe(struct i2c_client *client,
chip->companion_addr = pdata->companion_addr;
chip->companion = i2c_new_dummy(chip->client->adapter,
chip->companion_addr);
if (!chip->companion) {
dev_err(&client->dev,
"Failed to allocate I2C companion device\n");
return -ENODEV;
}
chip->regmap_companion = regmap_init_i2c(chip->companion,
&pm860x_regmap_config);
if (IS_ERR(chip->regmap_companion)) {
ret = PTR_ERR(chip->regmap_companion);
dev_err(&chip->companion->dev,
"Failed to allocate register map: %d\n", ret);
i2c_unregister_device(chip->companion);
return ret;
}
i2c_set_clientdata(chip->companion, chip);
......
......@@ -59,6 +59,14 @@ config MFD_AAT2870_CORE
additional drivers must be enabled in order to use the
functionality of the device.
config MFD_BCM590XX
tristate "Broadcom BCM590xx PMUs"
select MFD_CORE
select REGMAP_I2C
depends on I2C
help
Support for the BCM590xx PMUs from Broadcom
config MFD_CROS_EC
tristate "ChromeOS Embedded Controller"
select MFD_CORE
......@@ -100,7 +108,7 @@ config PMIC_DA903X
bool "Dialog Semiconductor DA9030/DA9034 PMIC Support"
depends on I2C=y
help
Say yes here to support for Dialog Semiconductor DA9030 (a.k.a
Say yes here to add support for Dialog Semiconductor DA9030 (a.k.a
ARAVA) and DA9034 (a.k.a MICCO), these are Power Management IC
usually found on PXA processors-based platforms. This includes
the I2C driver and the core APIs _only_, you have to select
......@@ -270,13 +278,18 @@ config MFD_KEMPLD
device may provide functions like watchdog, GPIO, UART and I2C bus.
The following modules are supported:
* COMe-bHL6
* COMe-bIP#
* COMe-bPC2 (ETXexpress-PC)
* COMe-bSC# (ETXexpress-SC T#)
* COMe-cBT6
* COMe-cCT6
* COMe-cDC2 (microETXexpress-DC)
* COMe-cHL6
* COMe-cPC2 (microETXexpress-PC)
* COMe-mBT10
* COMe-mCT10
* COMe-mTT10 (nanoETXexpress-TT)
* ETX-OH
This driver can also be built as a module. If so, the module
......@@ -322,9 +335,10 @@ config MFD_MAX14577
depends on I2C=y
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
select IRQ_DOMAIN
help
Say yes here to support for Maxim Semiconductor MAX14577.
Say yes here to add support for Maxim Semiconductor MAX14577.
This is a Micro-USB IC with Charger controls on chip.
This driver provides common support for accessing the device;
additional drivers must be enabled in order to use the functionality
......@@ -337,7 +351,7 @@ config MFD_MAX77686
select REGMAP_I2C
select IRQ_DOMAIN
help
Say yes here to support for Maxim Semiconductor MAX77686.
Say yes here to add support for Maxim Semiconductor MAX77686.
This is a Power Management IC with RTC on chip.
This driver provides common support for accessing the device;
additional drivers must be enabled in order to use the functionality
......@@ -349,7 +363,7 @@ config MFD_MAX77693
select MFD_CORE
select REGMAP_I2C
help
Say yes here to support for Maxim Semiconductor MAX77693.
Say yes here to add support for Maxim Semiconductor MAX77693.
This is a companion Power Management IC with Flash, Haptic, Charger,
and MUIC(Micro USB Interface Controller) controls on chip.
This driver provides common support for accessing the device;
......@@ -363,7 +377,7 @@ config MFD_MAX8907
select REGMAP_I2C
select REGMAP_IRQ
help
Say yes here to support for Maxim Semiconductor MAX8907. This is
Say yes here to add support for Maxim Semiconductor MAX8907. This is
a Power Management IC. This driver provides common support for
accessing the device; additional drivers must be enabled in order
to use the functionality of the device.
......@@ -373,7 +387,7 @@ config MFD_MAX8925
depends on I2C=y
select MFD_CORE
help
Say yes here to support for Maxim Semiconductor MAX8925. This is
Say yes here to add support for Maxim Semiconductor MAX8925. This is
a Power Management IC. This driver provides common support for
accessing the device, additional drivers must be enabled in order
to use the functionality of the device.
......@@ -384,7 +398,7 @@ config MFD_MAX8997
select MFD_CORE
select IRQ_DOMAIN
help
Say yes here to support for Maxim Semiconductor MAX8997/8966.
Say yes here to add support for Maxim Semiconductor MAX8997/8966.
This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic,
MUIC controls on chip.
This driver provides common support for accessing the device;
......@@ -397,7 +411,7 @@ config MFD_MAX8998
select MFD_CORE
select IRQ_DOMAIN
help
Say yes here to support for Maxim Semiconductor MAX8998 and
Say yes here to add support for Maxim Semiconductor MAX8998 and
National Semiconductor LP3974. This is a Power Management IC.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the functionality
......@@ -473,10 +487,11 @@ config MFD_PM8XXX
config MFD_PM8921_CORE
tristate "Qualcomm PM8921 PMIC chip"
depends on (ARCH_MSM || HEXAGON)
depends on BROKEN
depends on (ARM || HEXAGON)
select IRQ_DOMAIN
select MFD_CORE
select MFD_PM8XXX
select REGMAP
help
If you say yes to this option, support will be included for the
built-in PM8921 PMIC chip.
......@@ -487,16 +502,6 @@ config MFD_PM8921_CORE
Say M here if you want to include support for PM8921 chip as a module.
This will build a module called "pm8921-core".
config MFD_PM8XXX_IRQ
bool "Qualcomm PM8xxx IRQ features"
depends on MFD_PM8XXX
default y if MFD_PM8XXX
help
This is the IRQ driver for Qualcomm PM 8xxx PMIC chips.
This is required to use certain other PM 8xxx features, such as GPIO
and MPP.
config MFD_RDC321X
tristate "RDC R-321x southbridge"
select MFD_CORE
......@@ -516,6 +521,16 @@ config MFD_RTSX_PCI
types of memory cards, such as Memory Stick, Memory Stick Pro,
Secure Digital and MultiMediaCard.
config MFD_RTSX_USB
tristate "Realtek USB card reader"
depends on USB
select MFD_CORE
help
Select this option to get support for Realtek USB 2.0 card readers
including RTS5129, RTS5139, RTS5179 and RTS5170.
Realtek card reader supports access to many types of memory cards,
such as Memory Stick Pro, Secure Digital and MultiMediaCard.
config MFD_RC5T583
bool "Ricoh RC5T583 Power Management system device"
depends on I2C=y
......@@ -774,17 +789,6 @@ config MFD_PALMAS
If you say yes here you get support for the Palmas
series of PMIC chips from Texas Instruments.
config MFD_TI_SSP
tristate "TI Sequencer Serial Port support"
depends on ARCH_DAVINCI_TNETV107X
select MFD_CORE
---help---
Say Y here if you want support for the Sequencer Serial Port
in a Texas Instruments TNETV107X SoC.
To compile this driver as a module, choose M here: the
module will be called ti-ssp.
config TPS6105X
tristate "TI TPS61050/61052 Boost Converters"
depends on I2C
......@@ -853,6 +857,22 @@ config MFD_TPS65217
This driver can also be built as a module. If so, the module
will be called tps65217.
config MFD_TPS65218
tristate "TI TPS65218 Power Management chips"
depends on I2C
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
help
If you say yes here you get support for the TPS65218 series of
Power Management chips.
These include voltage regulators, gpio and other features
that are often used in portable devices. Only regulator
component is currently supported.
This driver can also be built as a module. If so, the module
will be called tps65218.
config MFD_TPS6586X
bool "TI TPS6586x Power Management chips"
depends on I2C=y
......@@ -935,16 +955,6 @@ config TWL4030_CORE
high speed USB OTG transceiver, an audio codec (on most
versions) and many other features.
config TWL4030_MADC
tristate "TI TWL4030 MADC"
depends on TWL4030_CORE
help
This driver provides support for triton TWL4030-MADC. The
driver supports both RT and SW conversion methods.
This driver can be built as a module. If so it will be
named twl4030-madc
config TWL4030_POWER
bool "TI TWL4030 power resources"
depends on TWL4030_CORE && ARM
......@@ -1193,9 +1203,6 @@ config MFD_STW481X
in various ST Microelectronics and ST-Ericsson embedded
Nomadik series.
endmenu
endif
menu "Multimedia Capabilities Port drivers"
depends on ARCH_SA1100
......@@ -1226,3 +1233,6 @@ config VEXPRESS_CONFIG
help
Platform configuration infrastructure for the ARM Ltd.
Versatile Express.
endmenu
endif
......@@ -8,12 +8,14 @@ obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o
obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o
obj-$(CONFIG_MFD_SM501) += sm501.o
obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o
obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o
obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o
obj-$(CONFIG_MFD_RTSX_USB) += rtsx_usb.o
obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
......@@ -21,7 +23,6 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o
obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o
obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o
......@@ -62,6 +63,7 @@ obj-$(CONFIG_TPS6105X) += tps6105x.o
obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_TPS6507X) += tps6507x.o
obj-$(CONFIG_MFD_TPS65217) += tps65217.o
obj-$(CONFIG_MFD_TPS65218) += tps65218.o
obj-$(CONFIG_MFD_TPS65910) += tps65910.o
tps65912-objs := tps65912-core.o tps65912-irq.o
obj-$(CONFIG_MFD_TPS65912) += tps65912.o
......@@ -71,7 +73,6 @@ obj-$(CONFIG_MFD_TPS80031) += tps80031.o
obj-$(CONFIG_MENELAUS) += menelaus.o
obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o
obj-$(CONFIG_TWL6040_CORE) += twl6040.o
......@@ -150,7 +151,6 @@ obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o
obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o ssbi.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
......
......@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
......
......@@ -277,6 +277,7 @@ static const struct regmap_range as3722_readable_ranges[] = {
regmap_reg_range(AS3722_ADC0_CONTROL_REG, AS3722_ADC_CONFIGURATION_REG),
regmap_reg_range(AS3722_ASIC_ID1_REG, AS3722_ASIC_ID2_REG),
regmap_reg_range(AS3722_LOCK_REG, AS3722_LOCK_REG),
regmap_reg_range(AS3722_FUSE7_REG, AS3722_FUSE7_REG),
};
static const struct regmap_access_table as3722_readable_table = {
......
/*
* Broadcom BCM590xx PMU
*
* Copyright 2014 Linaro Limited
* Author: Matt Porter <mporter@linaro.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/mfd/bcm590xx.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
static const struct mfd_cell bcm590xx_devs[] = {
{
.name = "bcm590xx-vregs",
},
};
static const struct regmap_config bcm590xx_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = BCM590XX_MAX_REGISTER,
.cache_type = REGCACHE_RBTREE,
};
static int bcm590xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct bcm590xx *bcm590xx;
int ret;
bcm590xx = devm_kzalloc(&i2c->dev, sizeof(*bcm590xx), GFP_KERNEL);
if (!bcm590xx)
return -ENOMEM;
i2c_set_clientdata(i2c, bcm590xx);
bcm590xx->dev = &i2c->dev;
bcm590xx->i2c_client = i2c;
bcm590xx->regmap = devm_regmap_init_i2c(i2c, &bcm590xx_regmap_config);
if (IS_ERR(bcm590xx->regmap)) {
ret = PTR_ERR(bcm590xx->regmap);
dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
return ret;
}
ret = mfd_add_devices(&i2c->dev, -1, bcm590xx_devs,
ARRAY_SIZE(bcm590xx_devs), NULL, 0, NULL);
if (ret < 0)
dev_err(&i2c->dev, "failed to add sub-devices: %d\n", ret);
return ret;
}
static const struct of_device_id bcm590xx_of_match[] = {
{ .compatible = "brcm,bcm59056" },
{ }
};
MODULE_DEVICE_TABLE(of, bcm590xx_of_match);
static const struct i2c_device_id bcm590xx_i2c_id[] = {
{ "bcm59056" },
{ }
};
MODULE_DEVICE_TABLE(i2c, bcm590xx_i2c_id);
static struct i2c_driver bcm590xx_i2c_driver = {
.driver = {
.name = "bcm590xx",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(bcm590xx_of_match),
},
.probe = bcm590xx_i2c_probe,
.id_table = bcm590xx_i2c_id,
};
module_i2c_driver(bcm590xx_i2c_driver);
MODULE_AUTHOR("Matt Porter <mporter@linaro.org>");
MODULE_DESCRIPTION("BCM590xx multi-function driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:bcm590xx");
......@@ -23,7 +23,6 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/pci.h>
......
......@@ -279,6 +279,9 @@ static bool da9052_reg_volatile(struct device *dev, unsigned int reg)
case DA9052_EVENT_B_REG:
case DA9052_EVENT_C_REG:
case DA9052_EVENT_D_REG:
case DA9052_CONTROL_B_REG:
case DA9052_CONTROL_D_REG:
case DA9052_SUPPLY_REG:
case DA9052_FAULTLOG_REG:
case DA9052_CHG_TIME_REG:
case DA9052_ADC_RES_L_REG:
......
......@@ -75,6 +75,7 @@ static int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
DA9052_PARK_REGISTER,
&val);
break;
case DA9053_BC:
default:
/*
* For other chips parking of I2C register
......@@ -114,6 +115,7 @@ static const struct i2c_device_id da9052_i2c_id[] = {
{"da9053-aa", DA9053_AA},
{"da9053-ba", DA9053_BA},
{"da9053-bb", DA9053_BB},
{"da9053-bc", DA9053_BC},
{}
};
......@@ -121,8 +123,9 @@ static const struct i2c_device_id da9052_i2c_id[] = {
static const struct of_device_id dialog_dt_ids[] = {
{ .compatible = "dlg,da9052", .data = &da9052_i2c_id[0] },
{ .compatible = "dlg,da9053-aa", .data = &da9052_i2c_id[1] },
{ .compatible = "dlg,da9053-ab", .data = &da9052_i2c_id[2] },
{ .compatible = "dlg,da9053-ba", .data = &da9052_i2c_id[2] },
{ .compatible = "dlg,da9053-bb", .data = &da9052_i2c_id[3] },
{ .compatible = "dlg,da9053-bc", .data = &da9052_i2c_id[4] },
{ /* sentinel */ }
};
#endif
......
......@@ -71,6 +71,7 @@ static struct spi_device_id da9052_spi_id[] = {
{"da9053-aa", DA9053_AA},
{"da9053-ba", DA9053_BA},
{"da9053-bb", DA9053_BB},
{"da9053-bc", DA9053_BC},
{}
};
......
......@@ -15,6 +15,8 @@
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/mfd/da9055/core.h>
......@@ -66,6 +68,11 @@ static struct i2c_device_id da9055_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
static const struct of_device_id da9055_of_match[] = {
{ .compatible = "dlg,da9055-pmic", },
{ }
};
static struct i2c_driver da9055_i2c_driver = {
.probe = da9055_i2c_probe,
.remove = da9055_i2c_remove,
......@@ -73,6 +80,7 @@ static struct i2c_driver da9055_i2c_driver = {
.driver = {
.name = "da9055-pmic",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(da9055_of_match),
},
};
......
......@@ -110,7 +110,7 @@ static const struct mfd_cell da9063_devs[] = {
int da9063_device_init(struct da9063 *da9063, unsigned int irq)
{
struct da9063_pdata *pdata = da9063->dev->platform_data;
int model, revision;
int model, variant_id, variant_code;
int ret;
if (pdata) {
......@@ -141,23 +141,26 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq)
return -ENODEV;
}
ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_VARIANT, &revision);
ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_VARIANT, &variant_id);
if (ret < 0) {
dev_err(da9063->dev, "Cannot read chip revision id.\n");
dev_err(da9063->dev, "Cannot read chip variant id.\n");
return -EIO;
}
revision >>= DA9063_CHIP_VARIANT_SHIFT;
if (revision != 3) {
dev_err(da9063->dev, "Unknown chip revision: %d\n", revision);
variant_code = variant_id >> DA9063_CHIP_VARIANT_SHIFT;
dev_info(da9063->dev,
"Device detected (chip-ID: 0x%02X, var-ID: 0x%02X)\n",
model, variant_id);
if (variant_code != PMIC_DA9063_BB) {
dev_err(da9063->dev, "Unknown chip variant code: 0x%02X\n",
variant_code);
return -ENODEV;
}
da9063->model = model;
da9063->revision = revision;
dev_info(da9063->dev,
"Device detected (model-ID: 0x%02X rev-ID: 0x%02X)\n",
model, revision);
da9063->variant_code = variant_code;
ret = da9063_irq_init(da9063);
if (ret) {
......
......@@ -13,7 +13,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
......
......@@ -322,9 +322,12 @@ static int kempld_detect_device(struct kempld_device_data *pld)
return -ENODEV;
}
/* Release hardware mutex if aquired */
if (!(index_reg & KEMPLD_MUTEX_KEY))
/* Release hardware mutex if acquired */
if (!(index_reg & KEMPLD_MUTEX_KEY)) {
iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
/* PXT and COMe-cPC2 boards may require a second release */
iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
}
mutex_unlock(&pld->lock);
......@@ -437,6 +440,14 @@ static struct dmi_system_id __initdata kempld_dmi_table[] = {
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "CHL6",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "COMe-cHL6"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "CHR2",
.matches = {
......@@ -509,6 +520,14 @@ static struct dmi_system_id __initdata kempld_dmi_table[] = {
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "CVV6",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "COMe-cBT"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "FRI2",
.matches = {
......@@ -532,6 +551,14 @@ static struct dmi_system_id __initdata kempld_dmi_table[] = {
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "MVV1",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
DMI_MATCH(DMI_BOARD_NAME, "COMe-mBT"),
},
.driver_data = (void *)&kempld_platform_data_generic,
.callback = kempld_create_platform_device,
}, {
.ident = "NTC1",
.matches = {
......
......@@ -58,7 +58,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
......@@ -72,9 +71,11 @@
#define ACPIBASE_GPE_END 0x2f
#define ACPIBASE_SMI_OFF 0x30
#define ACPIBASE_SMI_END 0x33
#define ACPIBASE_PMC_OFF 0x08
#define ACPIBASE_PMC_END 0x0c
#define ACPIBASE_TCO_OFF 0x60
#define ACPIBASE_TCO_END 0x7f
#define ACPICTRL 0x44
#define ACPICTRL_PMCBASE 0x44
#define ACPIBASE_GCS_OFF 0x3410
#define ACPIBASE_GCS_END 0x3414
......@@ -90,16 +91,17 @@
#define wdt_mem_res(i) wdt_res(ICH_RES_MEM_OFF, i)
#define wdt_res(b, i) (&wdt_ich_res[(b) + (i)])
struct lpc_ich_cfg {
int base;
int ctrl;
int save;
};
struct lpc_ich_priv {
int chipset;
struct lpc_ich_cfg acpi;
struct lpc_ich_cfg gpio;
int abase; /* ACPI base */
int actrl_pbase; /* ACPI control or PMC base */
int gbase; /* GPIO base */
int gctrl; /* GPIO control */
int abase_save; /* Cached ACPI base value */
int actrl_pbase_save; /* Cached ACPI control or PMC base value */
int gctrl_save; /* Cached GPIO control value */
};
static struct resource wdt_ich_res[] = {
......@@ -111,7 +113,7 @@ static struct resource wdt_ich_res[] = {
{
.flags = IORESOURCE_IO,
},
/* GCS */
/* GCS or PMC */
{
.flags = IORESOURCE_MEM,
},
......@@ -211,6 +213,7 @@ enum lpc_chipsets {
LPC_LPT_LP, /* Lynx Point-LP */
LPC_WBG, /* Wellsburg */
LPC_AVN, /* Avoton SoC */
LPC_BAYTRAIL, /* Bay Trail SoC */
LPC_COLETO, /* Coleto Creek */
LPC_WPT_LP, /* Wildcat Point-LP */
};
......@@ -303,6 +306,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
[LPC_NM10] = {
.name = "NM10",
.iTCO_version = 2,
.gpio_version = ICH_V7_GPIO,
},
[LPC_ICH8] = {
.name = "ICH8 or ICH8R",
......@@ -499,7 +503,12 @@ static struct lpc_ich_info lpc_chipset_info[] = {
},
[LPC_AVN] = {
.name = "Avoton SoC",
.iTCO_version = 1,
.iTCO_version = 3,
.gpio_version = AVOTON_GPIO,
},
[LPC_BAYTRAIL] = {
.name = "Bay Trail SoC",
.iTCO_version = 3,
},
[LPC_COLETO] = {
.name = "Coleto Creek",
......@@ -726,6 +735,7 @@ static const struct pci_device_id lpc_ich_ids[] = {
{ PCI_VDEVICE(INTEL, 0x1f39), LPC_AVN},
{ PCI_VDEVICE(INTEL, 0x1f3a), LPC_AVN},
{ PCI_VDEVICE(INTEL, 0x1f3b), LPC_AVN},
{ PCI_VDEVICE(INTEL, 0x0f1c), LPC_BAYTRAIL},
{ PCI_VDEVICE(INTEL, 0x2390), LPC_COLETO},
{ PCI_VDEVICE(INTEL, 0x9cc1), LPC_WPT_LP},
{ PCI_VDEVICE(INTEL, 0x9cc2), LPC_WPT_LP},
......@@ -742,14 +752,20 @@ static void lpc_ich_restore_config_space(struct pci_dev *dev)
{
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
if (priv->acpi.save >= 0) {
pci_write_config_byte(dev, priv->acpi.ctrl, priv->acpi.save);
priv->acpi.save = -1;
if (priv->abase_save >= 0) {
pci_write_config_byte(dev, priv->abase, priv->abase_save);
priv->abase_save = -1;
}
if (priv->actrl_pbase_save >= 0) {
pci_write_config_byte(dev, priv->actrl_pbase,
priv->actrl_pbase_save);
priv->actrl_pbase_save = -1;
}
if (priv->gpio.save >= 0) {
pci_write_config_byte(dev, priv->gpio.ctrl, priv->gpio.save);
priv->gpio.save = -1;
if (priv->gctrl_save >= 0) {
pci_write_config_byte(dev, priv->gctrl, priv->gctrl_save);
priv->gctrl_save = -1;
}
}
......@@ -758,9 +774,26 @@ static void lpc_ich_enable_acpi_space(struct pci_dev *dev)
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
u8 reg_save;
pci_read_config_byte(dev, priv->acpi.ctrl, &reg_save);
pci_write_config_byte(dev, priv->acpi.ctrl, reg_save | 0x10);
priv->acpi.save = reg_save;
switch (lpc_chipset_info[priv->chipset].iTCO_version) {
case 3:
/*
* Some chipsets (eg Avoton) enable the ACPI space in the
* ACPI BASE register.
*/
pci_read_config_byte(dev, priv->abase, &reg_save);
pci_write_config_byte(dev, priv->abase, reg_save | 0x2);
priv->abase_save = reg_save;
break;
default:
/*
* Most chipsets enable the ACPI space in the ACPI control
* register.
*/
pci_read_config_byte(dev, priv->actrl_pbase, &reg_save);
pci_write_config_byte(dev, priv->actrl_pbase, reg_save | 0x80);
priv->actrl_pbase_save = reg_save;
break;
}
}
static void lpc_ich_enable_gpio_space(struct pci_dev *dev)
......@@ -768,9 +801,20 @@ static void lpc_ich_enable_gpio_space(struct pci_dev *dev)
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
u8 reg_save;
pci_read_config_byte(dev, priv->gpio.ctrl, &reg_save);
pci_write_config_byte(dev, priv->gpio.ctrl, reg_save | 0x10);
priv->gpio.save = reg_save;
pci_read_config_byte(dev, priv->gctrl, &reg_save);
pci_write_config_byte(dev, priv->gctrl, reg_save | 0x10);
priv->gctrl_save = reg_save;
}
static void lpc_ich_enable_pmc_space(struct pci_dev *dev)
{
struct lpc_ich_priv *priv = pci_get_drvdata(dev);
u8 reg_save;
pci_read_config_byte(dev, priv->actrl_pbase, &reg_save);
pci_write_config_byte(dev, priv->actrl_pbase, reg_save | 0x2);
priv->actrl_pbase_save = reg_save;
}
static void lpc_ich_finalize_cell(struct pci_dev *dev, struct mfd_cell *cell)
......@@ -815,7 +859,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev)
struct resource *res;
/* Setup power management base register */
pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg);
pci_read_config_dword(dev, priv->abase, &base_addr_cfg);
base_addr = base_addr_cfg & 0x0000ff80;
if (!base_addr) {
dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n");
......@@ -841,7 +885,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev)
gpe0_done:
/* Setup GPIO base register */
pci_read_config_dword(dev, priv->gpio.base, &base_addr_cfg);
pci_read_config_dword(dev, priv->gbase, &base_addr_cfg);
base_addr = base_addr_cfg & 0x0000ff80;
if (!base_addr) {
dev_notice(&dev->dev, "I/O space for GPIO uninitialized\n");
......@@ -891,7 +935,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev)
struct resource *res;
/* Setup power management base register */
pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg);
pci_read_config_dword(dev, priv->abase, &base_addr_cfg);
base_addr = base_addr_cfg & 0x0000ff80;
if (!base_addr) {
dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n");
......@@ -910,14 +954,20 @@ static int lpc_ich_init_wdt(struct pci_dev *dev)
lpc_ich_enable_acpi_space(dev);
/*
* iTCO v2:
* Get the Memory-Mapped GCS register. To get access to it
* we have to read RCBA from PCI Config space 0xf0 and use
* it as base. GCS = RCBA + ICH6_GCS(0x3410).
*
* iTCO v3:
* Get the Power Management Configuration register. To get access
* to it we have to read the PMC BASE from config space and address
* the register at offset 0x8.
*/
if (lpc_chipset_info[priv->chipset].iTCO_version == 1) {
/* Don't register iomem for TCO ver 1 */
lpc_ich_cells[LPC_WDT].num_resources--;
} else {
} else if (lpc_chipset_info[priv->chipset].iTCO_version == 2) {
pci_read_config_dword(dev, RCBABASE, &base_addr_cfg);
base_addr = base_addr_cfg & 0xffffc000;
if (!(base_addr_cfg & 1)) {
......@@ -926,9 +976,17 @@ static int lpc_ich_init_wdt(struct pci_dev *dev)
ret = -ENODEV;
goto wdt_done;
}
res = wdt_mem_res(ICH_RES_MEM_GCS);
res = wdt_mem_res(ICH_RES_MEM_GCS_PMC);
res->start = base_addr + ACPIBASE_GCS_OFF;
res->end = base_addr + ACPIBASE_GCS_END;
} else if (lpc_chipset_info[priv->chipset].iTCO_version == 3) {
lpc_ich_enable_pmc_space(dev);
pci_read_config_dword(dev, ACPICTRL_PMCBASE, &base_addr_cfg);
base_addr = base_addr_cfg & 0xfffffe00;
res = wdt_mem_res(ICH_RES_MEM_GCS_PMC);
res->start = base_addr + ACPIBASE_PMC_OFF;
res->end = base_addr + ACPIBASE_PMC_END;
}
lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_WDT]);
......@@ -952,28 +1010,35 @@ static int lpc_ich_probe(struct pci_dev *dev,
return -ENOMEM;
priv->chipset = id->driver_data;
priv->acpi.save = -1;
priv->acpi.base = ACPIBASE;
priv->acpi.ctrl = ACPICTRL;
priv->gpio.save = -1;
priv->actrl_pbase_save = -1;
priv->abase_save = -1;
priv->abase = ACPIBASE;
priv->actrl_pbase = ACPICTRL_PMCBASE;
priv->gctrl_save = -1;
if (priv->chipset <= LPC_ICH5) {
priv->gpio.base = GPIOBASE_ICH0;
priv->gpio.ctrl = GPIOCTRL_ICH0;
priv->gbase = GPIOBASE_ICH0;
priv->gctrl = GPIOCTRL_ICH0;
} else {
priv->gpio.base = GPIOBASE_ICH6;
priv->gpio.ctrl = GPIOCTRL_ICH6;
priv->gbase = GPIOBASE_ICH6;
priv->gctrl = GPIOCTRL_ICH6;
}
pci_set_drvdata(dev, priv);
ret = lpc_ich_init_wdt(dev);
if (!ret)
cell_added = true;
if (lpc_chipset_info[priv->chipset].iTCO_version) {
ret = lpc_ich_init_wdt(dev);
if (!ret)
cell_added = true;
}
ret = lpc_ich_init_gpio(dev);
if (!ret)
cell_added = true;
if (lpc_chipset_info[priv->chipset].gpio_version) {
ret = lpc_ich_init_gpio(dev);
if (!ret)
cell_added = true;
}
/*
* We only care if at least one or none of the cells registered
......
......@@ -23,7 +23,6 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
......
......@@ -18,6 +18,7 @@
* This driver is based on max8997.c
*/
#include <linux/err.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
......@@ -25,7 +26,10 @@
#include <linux/mfd/max14577-private.h>
static struct mfd_cell max14577_devs[] = {
{ .name = "max14577-muic", },
{
.name = "max14577-muic",
.of_compatible = "maxim,max14577-muic",
},
{
.name = "max14577-regulator",
.of_compatible = "maxim,max14577-regulator",
......
......@@ -121,6 +121,10 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
dev_info(max77686->dev, "device found\n");
max77686->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
if (!max77686->rtc) {
dev_err(max77686->dev, "Failed to allocate I2C device for RTC\n");
return -ENODEV;
}
i2c_set_clientdata(max77686->rtc, max77686);
max77686_irq_init(max77686);
......
......@@ -148,9 +148,18 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
dev_info(max77693->dev, "device ID: 0x%x\n", reg_data);
max77693->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC);
if (!max77693->muic) {
dev_err(max77693->dev, "Failed to allocate I2C device for MUIC\n");
return -ENODEV;
}
i2c_set_clientdata(max77693->muic, max77693);
max77693->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC);
if (!max77693->haptic) {
dev_err(max77693->dev, "Failed to allocate I2C device for Haptic\n");
ret = -ENODEV;
goto err_i2c_haptic;
}
i2c_set_clientdata(max77693->haptic, max77693);
/*
......@@ -184,8 +193,9 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
max77693_irq_exit(max77693);
err_irq:
err_regmap_muic:
i2c_unregister_device(max77693->muic);
i2c_unregister_device(max77693->haptic);
err_i2c_haptic:
i2c_unregister_device(max77693->muic);
return ret;
}
......
......@@ -181,9 +181,18 @@ static int max8925_probe(struct i2c_client *client,
mutex_init(&chip->io_lock);
chip->rtc = i2c_new_dummy(chip->i2c->adapter, RTC_I2C_ADDR);
if (!chip->rtc) {
dev_err(chip->dev, "Failed to allocate I2C device for RTC\n");
return -ENODEV;
}
i2c_set_clientdata(chip->rtc, chip);
chip->adc = i2c_new_dummy(chip->i2c->adapter, ADC_I2C_ADDR);
if (!chip->adc) {
dev_err(chip->dev, "Failed to allocate I2C device for ADC\n");
i2c_unregister_device(chip->rtc);
return -ENODEV;
}
i2c_set_clientdata(chip->adc, chip);
device_init_wakeup(&client->dev, 1);
......
......@@ -208,10 +208,26 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
mutex_init(&max8997->iolock);
max8997->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
if (!max8997->rtc) {
dev_err(max8997->dev, "Failed to allocate I2C device for RTC\n");
return -ENODEV;
}
i2c_set_clientdata(max8997->rtc, max8997);
max8997->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC);
if (!max8997->haptic) {
dev_err(max8997->dev, "Failed to allocate I2C device for Haptic\n");
ret = -ENODEV;
goto err_i2c_haptic;
}
i2c_set_clientdata(max8997->haptic, max8997);
max8997->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC);
if (!max8997->muic) {
dev_err(max8997->dev, "Failed to allocate I2C device for MUIC\n");
ret = -ENODEV;
goto err_i2c_muic;
}
i2c_set_clientdata(max8997->muic, max8997);
pm_runtime_set_active(max8997->dev);
......@@ -239,7 +255,9 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
err_mfd:
mfd_remove_devices(max8997->dev);
i2c_unregister_device(max8997->muic);
err_i2c_muic:
i2c_unregister_device(max8997->haptic);
err_i2c_haptic:
i2c_unregister_device(max8997->rtc);
return ret;
}
......
......@@ -215,6 +215,10 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
mutex_init(&max8998->iolock);
max8998->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
if (!max8998->rtc) {
dev_err(&i2c->dev, "Failed to allocate I2C device for RTC\n");
return -ENODEV;
}
i2c_set_clientdata(max8998->rtc, max8998);
max8998_irq_init(max8998);
......
......@@ -140,6 +140,11 @@ static int mc13xxx_spi_probe(struct spi_device *spi)
mc13xxx->irq = spi->irq;
spi->max_speed_hz = spi->max_speed_hz ? : 26000000;
ret = spi_setup(spi);
if (ret)
return ret;
mc13xxx->regmap = devm_regmap_init(&spi->dev, &regmap_mc13xxx_bus,
&spi->dev,
&mc13xxx_regmap_spi_config);
......
......@@ -12,7 +12,6 @@
* MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/kernel.h>
......
......@@ -665,55 +665,78 @@ static int usbhs_omap_probe(struct platform_device *pdev)
goto err_mem;
}
need_logic_fck = false;
/* Set all clocks as invalid to begin with */
omap->ehci_logic_fck = ERR_PTR(-ENODEV);
omap->init_60m_fclk = ERR_PTR(-ENODEV);
omap->utmi_p1_gfclk = ERR_PTR(-ENODEV);
omap->utmi_p2_gfclk = ERR_PTR(-ENODEV);
omap->xclk60mhsp1_ck = ERR_PTR(-ENODEV);
omap->xclk60mhsp2_ck = ERR_PTR(-ENODEV);
for (i = 0; i < omap->nports; i++) {
if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
is_ehci_hsic_mode(i))
need_logic_fck |= true;
omap->utmi_clk[i] = ERR_PTR(-ENODEV);
omap->hsic480m_clk[i] = ERR_PTR(-ENODEV);
omap->hsic60m_clk[i] = ERR_PTR(-ENODEV);
}
omap->ehci_logic_fck = ERR_PTR(-EINVAL);
if (need_logic_fck) {
omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
if (IS_ERR(omap->ehci_logic_fck)) {
ret = PTR_ERR(omap->ehci_logic_fck);
dev_dbg(dev, "ehci_logic_fck failed:%d\n", ret);
/* for OMAP3 i.e. USBHS REV1 */
if (omap->usbhs_rev == OMAP_USBHS_REV1) {
need_logic_fck = false;
for (i = 0; i < omap->nports; i++) {
if (is_ehci_phy_mode(pdata->port_mode[i]) ||
is_ehci_tll_mode(pdata->port_mode[i]) ||
is_ehci_hsic_mode(pdata->port_mode[i]))
need_logic_fck |= true;
}
if (need_logic_fck) {
omap->ehci_logic_fck = devm_clk_get(dev,
"usbhost_120m_fck");
if (IS_ERR(omap->ehci_logic_fck)) {
ret = PTR_ERR(omap->ehci_logic_fck);
dev_err(dev, "usbhost_120m_fck failed:%d\n",
ret);
goto err_mem;
}
}
goto initialize;
}
omap->utmi_p1_gfclk = clk_get(dev, "utmi_p1_gfclk");
/* for OMAP4+ i.e. USBHS REV2+ */
omap->utmi_p1_gfclk = devm_clk_get(dev, "utmi_p1_gfclk");
if (IS_ERR(omap->utmi_p1_gfclk)) {
ret = PTR_ERR(omap->utmi_p1_gfclk);
dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
goto err_p1_gfclk;
goto err_mem;
}
omap->utmi_p2_gfclk = clk_get(dev, "utmi_p2_gfclk");
omap->utmi_p2_gfclk = devm_clk_get(dev, "utmi_p2_gfclk");
if (IS_ERR(omap->utmi_p2_gfclk)) {
ret = PTR_ERR(omap->utmi_p2_gfclk);
dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
goto err_p2_gfclk;
goto err_mem;
}
omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
omap->xclk60mhsp1_ck = devm_clk_get(dev, "refclk_60m_ext_p1");
if (IS_ERR(omap->xclk60mhsp1_ck)) {
ret = PTR_ERR(omap->xclk60mhsp1_ck);
dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
goto err_xclk60mhsp1;
dev_err(dev, "refclk_60m_ext_p1 failed error:%d\n", ret);
goto err_mem;
}
omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
omap->xclk60mhsp2_ck = devm_clk_get(dev, "refclk_60m_ext_p2");
if (IS_ERR(omap->xclk60mhsp2_ck)) {
ret = PTR_ERR(omap->xclk60mhsp2_ck);
dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
goto err_xclk60mhsp2;
dev_err(dev, "refclk_60m_ext_p2 failed error:%d\n", ret);
goto err_mem;
}
omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
omap->init_60m_fclk = devm_clk_get(dev, "refclk_60m_int");
if (IS_ERR(omap->init_60m_fclk)) {
ret = PTR_ERR(omap->init_60m_fclk);
dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
goto err_init60m;
dev_err(dev, "refclk_60m_int failed error:%d\n", ret);
goto err_mem;
}
for (i = 0; i < omap->nports; i++) {
......@@ -727,55 +750,72 @@ static int usbhs_omap_probe(struct platform_device *pdev)
* platforms have all clocks and we can function without
* them
*/
omap->utmi_clk[i] = clk_get(dev, clkname);
if (IS_ERR(omap->utmi_clk[i]))
dev_dbg(dev, "Failed to get clock : %s : %ld\n",
clkname, PTR_ERR(omap->utmi_clk[i]));
omap->utmi_clk[i] = devm_clk_get(dev, clkname);
if (IS_ERR(omap->utmi_clk[i])) {
ret = PTR_ERR(omap->utmi_clk[i]);
dev_err(dev, "Failed to get clock : %s : %d\n",
clkname, ret);
goto err_mem;
}
snprintf(clkname, sizeof(clkname),
"usb_host_hs_hsic480m_p%d_clk", i + 1);
omap->hsic480m_clk[i] = clk_get(dev, clkname);
if (IS_ERR(omap->hsic480m_clk[i]))
dev_dbg(dev, "Failed to get clock : %s : %ld\n",
clkname, PTR_ERR(omap->hsic480m_clk[i]));
omap->hsic480m_clk[i] = devm_clk_get(dev, clkname);
if (IS_ERR(omap->hsic480m_clk[i])) {
ret = PTR_ERR(omap->hsic480m_clk[i]);
dev_err(dev, "Failed to get clock : %s : %d\n",
clkname, ret);
goto err_mem;
}
snprintf(clkname, sizeof(clkname),
"usb_host_hs_hsic60m_p%d_clk", i + 1);
omap->hsic60m_clk[i] = clk_get(dev, clkname);
if (IS_ERR(omap->hsic60m_clk[i]))
dev_dbg(dev, "Failed to get clock : %s : %ld\n",
clkname, PTR_ERR(omap->hsic60m_clk[i]));
omap->hsic60m_clk[i] = devm_clk_get(dev, clkname);
if (IS_ERR(omap->hsic60m_clk[i])) {
ret = PTR_ERR(omap->hsic60m_clk[i]);
dev_err(dev, "Failed to get clock : %s : %d\n",
clkname, ret);
goto err_mem;
}
}
if (is_ehci_phy_mode(pdata->port_mode[0])) {
/* for OMAP3, clk_set_parent fails */
ret = clk_set_parent(omap->utmi_p1_gfclk,
omap->xclk60mhsp1_ck);
if (ret != 0)
dev_dbg(dev, "xclk60mhsp1_ck set parent failed: %d\n",
ret);
if (ret != 0) {
dev_err(dev, "xclk60mhsp1_ck set parent failed: %d\n",
ret);
goto err_mem;
}
} else if (is_ehci_tll_mode(pdata->port_mode[0])) {
ret = clk_set_parent(omap->utmi_p1_gfclk,
omap->init_60m_fclk);
if (ret != 0)
dev_dbg(dev, "P0 init_60m_fclk set parent failed: %d\n",
ret);
if (ret != 0) {
dev_err(dev, "P0 init_60m_fclk set parent failed: %d\n",
ret);
goto err_mem;
}
}
if (is_ehci_phy_mode(pdata->port_mode[1])) {
ret = clk_set_parent(omap->utmi_p2_gfclk,
omap->xclk60mhsp2_ck);
if (ret != 0)
dev_dbg(dev, "xclk60mhsp2_ck set parent failed: %d\n",
ret);
if (ret != 0) {
dev_err(dev, "xclk60mhsp2_ck set parent failed: %d\n",
ret);
goto err_mem;
}
} else if (is_ehci_tll_mode(pdata->port_mode[1])) {
ret = clk_set_parent(omap->utmi_p2_gfclk,
omap->init_60m_fclk);
if (ret != 0)
dev_dbg(dev, "P1 init_60m_fclk set parent failed: %d\n",
ret);
if (ret != 0) {
dev_err(dev, "P1 init_60m_fclk set parent failed: %d\n",
ret);
goto err_mem;
}
}
initialize:
omap_usbhs_init(dev);
if (dev->of_node) {
......@@ -784,7 +824,7 @@ static int usbhs_omap_probe(struct platform_device *pdev)
if (ret) {
dev_err(dev, "Failed to create DT children: %d\n", ret);
goto err_alloc;
goto err_mem;
}
} else {
......@@ -792,40 +832,12 @@ static int usbhs_omap_probe(struct platform_device *pdev)
if (ret) {
dev_err(dev, "omap_usbhs_alloc_children failed: %d\n",
ret);
goto err_alloc;
goto err_mem;
}
}
return 0;
err_alloc:
for (i = 0; i < omap->nports; i++) {
if (!IS_ERR(omap->utmi_clk[i]))
clk_put(omap->utmi_clk[i]);
if (!IS_ERR(omap->hsic60m_clk[i]))
clk_put(omap->hsic60m_clk[i]);
if (!IS_ERR(omap->hsic480m_clk[i]))
clk_put(omap->hsic480m_clk[i]);
}
clk_put(omap->init_60m_fclk);
err_init60m:
clk_put(omap->xclk60mhsp2_ck);
err_xclk60mhsp2:
clk_put(omap->xclk60mhsp1_ck);
err_xclk60mhsp1:
clk_put(omap->utmi_p2_gfclk);
err_p2_gfclk:
clk_put(omap->utmi_p1_gfclk);
err_p1_gfclk:
if (!IS_ERR(omap->ehci_logic_fck))
clk_put(omap->ehci_logic_fck);
err_mem:
pm_runtime_disable(dev);
......@@ -847,27 +859,6 @@ static int usbhs_omap_remove_child(struct device *dev, void *data)
*/
static int usbhs_omap_remove(struct platform_device *pdev)
{
struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
int i;
for (i = 0; i < omap->nports; i++) {
if (!IS_ERR(omap->utmi_clk[i]))
clk_put(omap->utmi_clk[i]);
if (!IS_ERR(omap->hsic60m_clk[i]))
clk_put(omap->hsic60m_clk[i]);
if (!IS_ERR(omap->hsic480m_clk[i]))
clk_put(omap->hsic480m_clk[i]);
}
clk_put(omap->init_60m_fclk);
clk_put(omap->utmi_p1_gfclk);
clk_put(omap->utmi_p2_gfclk);
clk_put(omap->xclk60mhsp2_ck);
clk_put(omap->xclk60mhsp1_ck);
if (!IS_ERR(omap->ehci_logic_fck))
clk_put(omap->ehci_logic_fck);
pm_runtime_disable(&pdev->dev);
/* remove children */
......
......@@ -252,7 +252,7 @@ static int usbtll_omap_probe(struct platform_device *pdev)
break;
}
tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk * [tll->nch]),
tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk *) * tll->nch,
GFP_KERNEL);
if (!tll->ch_clk) {
ret = -ENOMEM;
......
......@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/completion.h>
......
......@@ -14,23 +14,316 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/ssbi.h>
#include <linux/regmap.h>
#include <linux/of_platform.h>
#include <linux/mfd/core.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/mfd/pm8xxx/core.h>
#define SSBI_REG_ADDR_IRQ_BASE 0x1BB
#define SSBI_REG_ADDR_IRQ_ROOT (SSBI_REG_ADDR_IRQ_BASE + 0)
#define SSBI_REG_ADDR_IRQ_M_STATUS1 (SSBI_REG_ADDR_IRQ_BASE + 1)
#define SSBI_REG_ADDR_IRQ_M_STATUS2 (SSBI_REG_ADDR_IRQ_BASE + 2)
#define SSBI_REG_ADDR_IRQ_M_STATUS3 (SSBI_REG_ADDR_IRQ_BASE + 3)
#define SSBI_REG_ADDR_IRQ_M_STATUS4 (SSBI_REG_ADDR_IRQ_BASE + 4)
#define SSBI_REG_ADDR_IRQ_BLK_SEL (SSBI_REG_ADDR_IRQ_BASE + 5)
#define SSBI_REG_ADDR_IRQ_IT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 6)
#define SSBI_REG_ADDR_IRQ_CONFIG (SSBI_REG_ADDR_IRQ_BASE + 7)
#define SSBI_REG_ADDR_IRQ_RT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 8)
#define PM_IRQF_LVL_SEL 0x01 /* level select */
#define PM_IRQF_MASK_FE 0x02 /* mask falling edge */
#define PM_IRQF_MASK_RE 0x04 /* mask rising edge */
#define PM_IRQF_CLR 0x08 /* clear interrupt */
#define PM_IRQF_BITS_MASK 0x70
#define PM_IRQF_BITS_SHIFT 4
#define PM_IRQF_WRITE 0x80
#define PM_IRQF_MASK_ALL (PM_IRQF_MASK_FE | \
PM_IRQF_MASK_RE)
#define REG_HWREV 0x002 /* PMIC4 revision */
#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
#define PM8921_NR_IRQS 256
struct pm_irq_chip {
struct device *dev;
struct regmap *regmap;
spinlock_t pm_irq_lock;
struct irq_domain *irqdomain;
unsigned int num_irqs;
unsigned int num_blocks;
unsigned int num_masters;
u8 config[0];
};
struct pm8921 {
struct device *dev;
struct pm_irq_chip *irq_chip;
};
static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp,
unsigned int *ip)
{
int rc;
spin_lock(&chip->pm_irq_lock);
rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
if (rc) {
pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
goto bail;
}
rc = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
if (rc)
pr_err("Failed Reading Status rc=%d\n", rc);
bail:
spin_unlock(&chip->pm_irq_lock);
return rc;
}
static int
pm8xxx_config_irq(struct pm_irq_chip *chip, unsigned int bp, unsigned int cp)
{
int rc;
spin_lock(&chip->pm_irq_lock);
rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
if (rc) {
pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
goto bail;
}
cp |= PM_IRQF_WRITE;
rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_CONFIG, cp);
if (rc)
pr_err("Failed Configuring IRQ rc=%d\n", rc);
bail:
spin_unlock(&chip->pm_irq_lock);
return rc;
}
static int pm8xxx_irq_block_handler(struct pm_irq_chip *chip, int block)
{
int pmirq, irq, i, ret = 0;
unsigned int bits;
ret = pm8xxx_read_block_irq(chip, block, &bits);
if (ret) {
pr_err("Failed reading %d block ret=%d", block, ret);
return ret;
}
if (!bits) {
pr_err("block bit set in master but no irqs: %d", block);
return 0;
}
/* Check IRQ bits */
for (i = 0; i < 8; i++) {
if (bits & (1 << i)) {
pmirq = block * 8 + i;
irq = irq_find_mapping(chip->irqdomain, pmirq);
generic_handle_irq(irq);
}
}
return 0;
}
static int pm8xxx_irq_master_handler(struct pm_irq_chip *chip, int master)
{
unsigned int blockbits;
int block_number, i, ret = 0;
ret = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_M_STATUS1 + master,
&blockbits);
if (ret) {
pr_err("Failed to read master %d ret=%d\n", master, ret);
return ret;
}
if (!blockbits) {
pr_err("master bit set in root but no blocks: %d", master);
return 0;
}
for (i = 0; i < 8; i++)
if (blockbits & (1 << i)) {
block_number = master * 8 + i; /* block # */
ret |= pm8xxx_irq_block_handler(chip, block_number);
}
return ret;
}
static void pm8xxx_irq_handler(unsigned int irq, struct irq_desc *desc)
{
struct pm_irq_chip *chip = irq_desc_get_handler_data(desc);
struct irq_chip *irq_chip = irq_desc_get_chip(desc);
unsigned int root;
int i, ret, masters = 0;
chained_irq_enter(irq_chip, desc);
ret = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_ROOT, &root);
if (ret) {
pr_err("Can't read root status ret=%d\n", ret);
return;
}
/* on pm8xxx series masters start from bit 1 of the root */
masters = root >> 1;
/* Read allowed masters for blocks. */
for (i = 0; i < chip->num_masters; i++)
if (masters & (1 << i))
pm8xxx_irq_master_handler(chip, i);
chained_irq_exit(irq_chip, desc);
}
static void pm8xxx_irq_mask_ack(struct irq_data *d)
{
struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
unsigned int pmirq = irqd_to_hwirq(d);
int irq_bit;
u8 block, config;
block = pmirq / 8;
irq_bit = pmirq % 8;
config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR;
pm8xxx_config_irq(chip, block, config);
}
static void pm8xxx_irq_unmask(struct irq_data *d)
{
struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
unsigned int pmirq = irqd_to_hwirq(d);
int irq_bit;
u8 block, config;
block = pmirq / 8;
irq_bit = pmirq % 8;
config = chip->config[pmirq];
pm8xxx_config_irq(chip, block, config);
}
static int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
unsigned int pmirq = irqd_to_hwirq(d);
int irq_bit;
u8 block, config;
block = pmirq / 8;
irq_bit = pmirq % 8;
chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT)
| PM_IRQF_MASK_ALL;
if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
if (flow_type & IRQF_TRIGGER_RISING)
chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
if (flow_type & IRQF_TRIGGER_FALLING)
chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
} else {
chip->config[pmirq] |= PM_IRQF_LVL_SEL;
if (flow_type & IRQF_TRIGGER_HIGH)
chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
else
chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
}
config = chip->config[pmirq] | PM_IRQF_CLR;
return pm8xxx_config_irq(chip, block, config);
}
static struct irq_chip pm8xxx_irq_chip = {
.name = "pm8xxx",
.irq_mask_ack = pm8xxx_irq_mask_ack,
.irq_unmask = pm8xxx_irq_unmask,
.irq_set_type = pm8xxx_irq_set_type,
.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
};
/**
* pm8xxx_get_irq_stat - get the status of the irq line
* @chip: pointer to identify a pmic irq controller
* @irq: the irq number
*
* The pm8xxx gpio and mpp rely on the interrupt block to read
* the values on their pins. This function is to facilitate reading
* the status of a gpio or an mpp line. The caller has to convert the
* gpio number to irq number.
*
* RETURNS:
* an int indicating the value read on that line
*/
static int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
{
int pmirq, rc;
unsigned int block, bits, bit;
unsigned long flags;
struct irq_data *irq_data = irq_get_irq_data(irq);
pmirq = irq_data->hwirq;
block = pmirq / 8;
bit = pmirq % 8;
spin_lock_irqsave(&chip->pm_irq_lock, flags);
rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_BLK_SEL, block);
if (rc) {
pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
irq, pmirq, block, rc);
goto bail_out;
}
rc = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits);
if (rc) {
pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
irq, pmirq, block, rc);
goto bail_out;
}
rc = (bits & (1 << bit)) ? 1 : 0;
bail_out:
spin_unlock_irqrestore(&chip->pm_irq_lock, flags);
return rc;
}
static int pm8xxx_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq)
{
struct pm_irq_chip *chip = d->host_data;
irq_set_chip_and_handler(irq, &pm8xxx_irq_chip, handle_level_irq);
irq_set_chip_data(irq, chip);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
irq_set_noprobe(irq);
#endif
return 0;
}
static const struct irq_domain_ops pm8xxx_irq_domain_ops = {
.xlate = irq_domain_xlate_twocell,
.map = pm8xxx_irq_domain_map,
};
static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
{
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
......@@ -81,42 +374,35 @@ static struct pm8xxx_drvdata pm8921_drvdata = {
.pmic_read_irq_stat = pm8921_read_irq_stat,
};
static int pm8921_add_subdevices(const struct pm8921_platform_data
*pdata,
struct pm8921 *pmic,
u32 rev)
{
int ret = 0, irq_base = 0;
struct pm_irq_chip *irq_chip;
if (pdata->irq_pdata) {
pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
pdata->irq_pdata->irq_cdata.rev = rev;
irq_base = pdata->irq_pdata->irq_base;
irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
static const struct regmap_config ssbi_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.max_register = 0x3ff,
.fast_io = true,
.reg_read = ssbi_reg_read,
.reg_write = ssbi_reg_write
};
if (IS_ERR(irq_chip)) {
pr_err("Failed to init interrupts ret=%ld\n",
PTR_ERR(irq_chip));
return PTR_ERR(irq_chip);
}
pmic->irq_chip = irq_chip;
}
return ret;
}
static const struct of_device_id pm8921_id_table[] = {
{ .compatible = "qcom,pm8058", },
{ .compatible = "qcom,pm8921", },
{ }
};
MODULE_DEVICE_TABLE(of, pm8921_id_table);
static int pm8921_probe(struct platform_device *pdev)
{
const struct pm8921_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct pm8921 *pmic;
int rc;
u8 val;
struct regmap *regmap;
int irq, rc;
unsigned int val;
u32 rev;
struct pm_irq_chip *chip;
unsigned int nirqs = PM8921_NR_IRQS;
if (!pdata) {
pr_err("missing platform data\n");
return -EINVAL;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8921), GFP_KERNEL);
if (!pmic) {
......@@ -124,8 +410,13 @@ static int pm8921_probe(struct platform_device *pdev)
return -ENOMEM;
}
regmap = devm_regmap_init(&pdev->dev, NULL, pdev->dev.parent,
&ssbi_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
/* Read PMIC chip revision */
rc = ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
rc = regmap_read(regmap, REG_HWREV, &val);
if (rc) {
pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
return rc;
......@@ -134,7 +425,7 @@ static int pm8921_probe(struct platform_device *pdev)
rev = val;
/* Read PMIC chip revision 2 */
rc = ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
rc = regmap_read(regmap, REG_HWREV_2, &val);
if (rc) {
pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
REG_HWREV_2, rc);
......@@ -147,37 +438,56 @@ static int pm8921_probe(struct platform_device *pdev)
pm8921_drvdata.pm_chip_data = pmic;
platform_set_drvdata(pdev, &pm8921_drvdata);
rc = pm8921_add_subdevices(pdata, pmic, rev);
chip = devm_kzalloc(&pdev->dev, sizeof(*chip) +
sizeof(chip->config[0]) * nirqs,
GFP_KERNEL);
if (!chip)
return -ENOMEM;
pmic->irq_chip = chip;
chip->dev = &pdev->dev;
chip->regmap = regmap;
chip->num_irqs = nirqs;
chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
spin_lock_init(&chip->pm_irq_lock);
chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, nirqs,
&pm8xxx_irq_domain_ops,
chip);
if (!chip->irqdomain)
return -ENODEV;
irq_set_handler_data(irq, chip);
irq_set_chained_handler(irq, pm8xxx_irq_handler);
irq_set_irq_wake(irq, 1);
rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
if (rc) {
pr_err("Cannot add subdevices rc=%d\n", rc);
goto err;
irq_set_chained_handler(irq, NULL);
irq_set_handler_data(irq, NULL);
irq_domain_remove(chip->irqdomain);
}
/* gpio might not work if no irq device is found */
WARN_ON(pmic->irq_chip == NULL);
return rc;
}
static int pm8921_remove_child(struct device *dev, void *unused)
{
platform_device_unregister(to_platform_device(dev));
return 0;
err:
mfd_remove_devices(pmic->dev);
return rc;
}
static int pm8921_remove(struct platform_device *pdev)
{
struct pm8xxx_drvdata *drvdata;
struct pm8921 *pmic = NULL;
drvdata = platform_get_drvdata(pdev);
if (drvdata)
pmic = drvdata->pm_chip_data;
if (pmic) {
mfd_remove_devices(pmic->dev);
if (pmic->irq_chip) {
pm8xxx_irq_exit(pmic->irq_chip);
pmic->irq_chip = NULL;
}
}
int irq = platform_get_irq(pdev, 0);
struct pm8921 *pmic = pm8921_drvdata.pm_chip_data;
struct pm_irq_chip *chip = pmic->irq_chip;
device_for_each_child(&pdev->dev, NULL, pm8921_remove_child);
irq_set_chained_handler(irq, NULL);
irq_set_handler_data(irq, NULL);
irq_domain_remove(chip->irqdomain);
return 0;
}
......@@ -188,6 +498,7 @@ static struct platform_driver pm8921_driver = {
.driver = {
.name = "pm8921-core",
.owner = THIS_MODULE,
.of_match_table = pm8921_id_table,
},
};
......
/*
* Copyright (c) 2011, 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.
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/mfd/pm8xxx/core.h>
#include <linux/mfd/pm8xxx/irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
/* PMIC8xxx IRQ */
#define SSBI_REG_ADDR_IRQ_BASE 0x1BB
#define SSBI_REG_ADDR_IRQ_ROOT (SSBI_REG_ADDR_IRQ_BASE + 0)
#define SSBI_REG_ADDR_IRQ_M_STATUS1 (SSBI_REG_ADDR_IRQ_BASE + 1)
#define SSBI_REG_ADDR_IRQ_M_STATUS2 (SSBI_REG_ADDR_IRQ_BASE + 2)
#define SSBI_REG_ADDR_IRQ_M_STATUS3 (SSBI_REG_ADDR_IRQ_BASE + 3)
#define SSBI_REG_ADDR_IRQ_M_STATUS4 (SSBI_REG_ADDR_IRQ_BASE + 4)
#define SSBI_REG_ADDR_IRQ_BLK_SEL (SSBI_REG_ADDR_IRQ_BASE + 5)
#define SSBI_REG_ADDR_IRQ_IT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 6)
#define SSBI_REG_ADDR_IRQ_CONFIG (SSBI_REG_ADDR_IRQ_BASE + 7)
#define SSBI_REG_ADDR_IRQ_RT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 8)
#define PM_IRQF_LVL_SEL 0x01 /* level select */
#define PM_IRQF_MASK_FE 0x02 /* mask falling edge */
#define PM_IRQF_MASK_RE 0x04 /* mask rising edge */
#define PM_IRQF_CLR 0x08 /* clear interrupt */
#define PM_IRQF_BITS_MASK 0x70
#define PM_IRQF_BITS_SHIFT 4
#define PM_IRQF_WRITE 0x80
#define PM_IRQF_MASK_ALL (PM_IRQF_MASK_FE | \
PM_IRQF_MASK_RE)
struct pm_irq_chip {
struct device *dev;
spinlock_t pm_irq_lock;
unsigned int devirq;
unsigned int irq_base;
unsigned int num_irqs;
unsigned int num_blocks;
unsigned int num_masters;
u8 config[0];
};
static int pm8xxx_read_root_irq(const struct pm_irq_chip *chip, u8 *rp)
{
return pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_ROOT, rp);
}
static int pm8xxx_read_master_irq(const struct pm_irq_chip *chip, u8 m, u8 *bp)
{
return pm8xxx_readb(chip->dev,
SSBI_REG_ADDR_IRQ_M_STATUS1 + m, bp);
}
static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, u8 bp, u8 *ip)
{
int rc;
spin_lock(&chip->pm_irq_lock);
rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
if (rc) {
pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
goto bail;
}
rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
if (rc)
pr_err("Failed Reading Status rc=%d\n", rc);
bail:
spin_unlock(&chip->pm_irq_lock);
return rc;
}
static int pm8xxx_config_irq(struct pm_irq_chip *chip, u8 bp, u8 cp)
{
int rc;
spin_lock(&chip->pm_irq_lock);
rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
if (rc) {
pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
goto bail;
}
cp |= PM_IRQF_WRITE;
rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp);
if (rc)
pr_err("Failed Configuring IRQ rc=%d\n", rc);
bail:
spin_unlock(&chip->pm_irq_lock);
return rc;
}
static int pm8xxx_irq_block_handler(struct pm_irq_chip *chip, int block)
{
int pmirq, irq, i, ret = 0;
u8 bits;
ret = pm8xxx_read_block_irq(chip, block, &bits);
if (ret) {
pr_err("Failed reading %d block ret=%d", block, ret);
return ret;
}
if (!bits) {
pr_err("block bit set in master but no irqs: %d", block);
return 0;
}
/* Check IRQ bits */
for (i = 0; i < 8; i++) {
if (bits & (1 << i)) {
pmirq = block * 8 + i;
irq = pmirq + chip->irq_base;
generic_handle_irq(irq);
}
}
return 0;
}
static int pm8xxx_irq_master_handler(struct pm_irq_chip *chip, int master)
{
u8 blockbits;
int block_number, i, ret = 0;
ret = pm8xxx_read_master_irq(chip, master, &blockbits);
if (ret) {
pr_err("Failed to read master %d ret=%d\n", master, ret);
return ret;
}
if (!blockbits) {
pr_err("master bit set in root but no blocks: %d", master);
return 0;
}
for (i = 0; i < 8; i++)
if (blockbits & (1 << i)) {
block_number = master * 8 + i; /* block # */
ret |= pm8xxx_irq_block_handler(chip, block_number);
}
return ret;
}
static void pm8xxx_irq_handler(unsigned int irq, struct irq_desc *desc)
{
struct pm_irq_chip *chip = irq_desc_get_handler_data(desc);
struct irq_chip *irq_chip = irq_desc_get_chip(desc);
u8 root;
int i, ret, masters = 0;
ret = pm8xxx_read_root_irq(chip, &root);
if (ret) {
pr_err("Can't read root status ret=%d\n", ret);
return;
}
/* on pm8xxx series masters start from bit 1 of the root */
masters = root >> 1;
/* Read allowed masters for blocks. */
for (i = 0; i < chip->num_masters; i++)
if (masters & (1 << i))
pm8xxx_irq_master_handler(chip, i);
irq_chip->irq_ack(&desc->irq_data);
}
static void pm8xxx_irq_mask_ack(struct irq_data *d)
{
struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
unsigned int pmirq = d->irq - chip->irq_base;
int master, irq_bit;
u8 block, config;
block = pmirq / 8;
master = block / 8;
irq_bit = pmirq % 8;
config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR;
pm8xxx_config_irq(chip, block, config);
}
static void pm8xxx_irq_unmask(struct irq_data *d)
{
struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
unsigned int pmirq = d->irq - chip->irq_base;
int master, irq_bit;
u8 block, config;
block = pmirq / 8;
master = block / 8;
irq_bit = pmirq % 8;
config = chip->config[pmirq];
pm8xxx_config_irq(chip, block, config);
}
static int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
unsigned int pmirq = d->irq - chip->irq_base;
int master, irq_bit;
u8 block, config;
block = pmirq / 8;
master = block / 8;
irq_bit = pmirq % 8;
chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT)
| PM_IRQF_MASK_ALL;
if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
if (flow_type & IRQF_TRIGGER_RISING)
chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
if (flow_type & IRQF_TRIGGER_FALLING)
chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
} else {
chip->config[pmirq] |= PM_IRQF_LVL_SEL;
if (flow_type & IRQF_TRIGGER_HIGH)
chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
else
chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
}
config = chip->config[pmirq] | PM_IRQF_CLR;
return pm8xxx_config_irq(chip, block, config);
}
static int pm8xxx_irq_set_wake(struct irq_data *d, unsigned int on)
{
return 0;
}
static struct irq_chip pm8xxx_irq_chip = {
.name = "pm8xxx",
.irq_mask_ack = pm8xxx_irq_mask_ack,
.irq_unmask = pm8xxx_irq_unmask,
.irq_set_type = pm8xxx_irq_set_type,
.irq_set_wake = pm8xxx_irq_set_wake,
.flags = IRQCHIP_MASK_ON_SUSPEND,
};
/**
* pm8xxx_get_irq_stat - get the status of the irq line
* @chip: pointer to identify a pmic irq controller
* @irq: the irq number
*
* The pm8xxx gpio and mpp rely on the interrupt block to read
* the values on their pins. This function is to facilitate reading
* the status of a gpio or an mpp line. The caller has to convert the
* gpio number to irq number.
*
* RETURNS:
* an int indicating the value read on that line
*/
int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
{
int pmirq, rc;
u8 block, bits, bit;
unsigned long flags;
if (chip == NULL || irq < chip->irq_base ||
irq >= chip->irq_base + chip->num_irqs)
return -EINVAL;
pmirq = irq - chip->irq_base;
block = pmirq / 8;
bit = pmirq % 8;
spin_lock_irqsave(&chip->pm_irq_lock, flags);
rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, block);
if (rc) {
pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
irq, pmirq, block, rc);
goto bail_out;
}
rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits);
if (rc) {
pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
irq, pmirq, block, rc);
goto bail_out;
}
rc = (bits & (1 << bit)) ? 1 : 0;
bail_out:
spin_unlock_irqrestore(&chip->pm_irq_lock, flags);
return rc;
}
EXPORT_SYMBOL_GPL(pm8xxx_get_irq_stat);
struct pm_irq_chip * pm8xxx_irq_init(struct device *dev,
const struct pm8xxx_irq_platform_data *pdata)
{
struct pm_irq_chip *chip;
int devirq, rc;
unsigned int pmirq;
if (!pdata) {
pr_err("No platform data\n");
return ERR_PTR(-EINVAL);
}
devirq = pdata->devirq;
if (devirq < 0) {
pr_err("missing devirq\n");
rc = devirq;
return ERR_PTR(-EINVAL);
}
chip = kzalloc(sizeof(struct pm_irq_chip)
+ sizeof(u8) * pdata->irq_cdata.nirqs, GFP_KERNEL);
if (!chip) {
pr_err("Cannot alloc pm_irq_chip struct\n");
return ERR_PTR(-EINVAL);
}
chip->dev = dev;
chip->devirq = devirq;
chip->irq_base = pdata->irq_base;
chip->num_irqs = pdata->irq_cdata.nirqs;
chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
spin_lock_init(&chip->pm_irq_lock);
for (pmirq = 0; pmirq < chip->num_irqs; pmirq++) {
irq_set_chip_and_handler(chip->irq_base + pmirq,
&pm8xxx_irq_chip,
handle_level_irq);
irq_set_chip_data(chip->irq_base + pmirq, chip);
#ifdef CONFIG_ARM
set_irq_flags(chip->irq_base + pmirq, IRQF_VALID);
#else
irq_set_noprobe(chip->irq_base + pmirq);
#endif
}
irq_set_irq_type(devirq, pdata->irq_trigger_flag);
irq_set_handler_data(devirq, chip);
irq_set_chained_handler(devirq, pm8xxx_irq_handler);
set_irq_wake(devirq, 1);
return chip;
}
int pm8xxx_irq_exit(struct pm_irq_chip *chip)
{
irq_set_chained_handler(chip->devirq, NULL);
kfree(chip);
return 0;
}
......@@ -22,7 +22,6 @@
*/
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/mfd/rc5t583.h>
......
......@@ -19,7 +19,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
......
......@@ -19,7 +19,6 @@
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/module.h>
......
/* Driver for Realtek USB card reader
*
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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
* 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, see <http://www.gnu.org/licenses/>.
*
* Author:
* Roger Tseng <rogerable@realtek.com>
*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/usb.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/rtsx_usb.h>
static int polling_pipe = 1;
module_param(polling_pipe, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(polling_pipe, "polling pipe (0: ctl, 1: bulk)");
static struct mfd_cell rtsx_usb_cells[] = {
[RTSX_USB_SD_CARD] = {
.name = "rtsx_usb_sdmmc",
.pdata_size = 0,
},
[RTSX_USB_MS_CARD] = {
.name = "rtsx_usb_ms",
.pdata_size = 0,
},
};
static void rtsx_usb_sg_timed_out(unsigned long data)
{
struct rtsx_ucr *ucr = (struct rtsx_ucr *)data;
dev_dbg(&ucr->pusb_intf->dev, "%s: sg transfer timed out", __func__);
usb_sg_cancel(&ucr->current_sg);
/* we know the cancellation is caused by time-out */
ucr->current_sg.status = -ETIMEDOUT;
}
static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
unsigned int pipe, struct scatterlist *sg, int num_sg,
unsigned int length, unsigned int *act_len, int timeout)
{
int ret;
dev_dbg(&ucr->pusb_intf->dev, "%s: xfer %u bytes, %d entries\n",
__func__, length, num_sg);
ret = usb_sg_init(&ucr->current_sg, ucr->pusb_dev, pipe, 0,
sg, num_sg, length, GFP_NOIO);
if (ret)
return ret;
ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout);
add_timer(&ucr->sg_timer);
usb_sg_wait(&ucr->current_sg);
del_timer(&ucr->sg_timer);
if (act_len)
*act_len = ucr->current_sg.bytes;
return ucr->current_sg.status;
}
int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe,
void *buf, unsigned int len, int num_sg,
unsigned int *act_len, int timeout)
{
if (timeout < 600)
timeout = 600;
if (num_sg)
return rtsx_usb_bulk_transfer_sglist(ucr, pipe,
(struct scatterlist *)buf, num_sg, len, act_len,
timeout);
else
return usb_bulk_msg(ucr->pusb_dev, pipe, buf, len, act_len,
timeout);
}
EXPORT_SYMBOL_GPL(rtsx_usb_transfer_data);
static inline void rtsx_usb_seq_cmd_hdr(struct rtsx_ucr *ucr,
u16 addr, u16 len, u8 seq_type)
{
rtsx_usb_cmd_hdr_tag(ucr);
ucr->cmd_buf[PACKET_TYPE] = seq_type;
ucr->cmd_buf[5] = (u8)(len >> 8);
ucr->cmd_buf[6] = (u8)len;
ucr->cmd_buf[8] = (u8)(addr >> 8);
ucr->cmd_buf[9] = (u8)addr;
if (seq_type == SEQ_WRITE)
ucr->cmd_buf[STAGE_FLAG] = 0;
else
ucr->cmd_buf[STAGE_FLAG] = STAGE_R;
}
static int rtsx_usb_seq_write_register(struct rtsx_ucr *ucr,
u16 addr, u16 len, u8 *data)
{
u16 cmd_len = ALIGN(SEQ_WRITE_DATA_OFFSET + len, 4);
if (!data)
return -EINVAL;
if (cmd_len > IOBUF_SIZE)
return -EINVAL;
rtsx_usb_seq_cmd_hdr(ucr, addr, len, SEQ_WRITE);
memcpy(ucr->cmd_buf + SEQ_WRITE_DATA_OFFSET, data, len);
return rtsx_usb_transfer_data(ucr,
usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT),
ucr->cmd_buf, cmd_len, 0, NULL, 100);
}
static int rtsx_usb_seq_read_register(struct rtsx_ucr *ucr,
u16 addr, u16 len, u8 *data)
{
int i, ret;
u16 rsp_len = round_down(len, 4);
u16 res_len = len - rsp_len;
if (!data)
return -EINVAL;
/* 4-byte aligned part */
if (rsp_len) {
rtsx_usb_seq_cmd_hdr(ucr, addr, len, SEQ_READ);
ret = rtsx_usb_transfer_data(ucr,
usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT),
ucr->cmd_buf, 12, 0, NULL, 100);
if (ret)
return ret;
ret = rtsx_usb_transfer_data(ucr,
usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN),
data, rsp_len, 0, NULL, 100);
if (ret)
return ret;
}
/* unaligned part */
for (i = 0; i < res_len; i++) {
ret = rtsx_usb_read_register(ucr, addr + rsp_len + i,
data + rsp_len + i);
if (ret)
return ret;
}
return 0;
}
int rtsx_usb_read_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len)
{
return rtsx_usb_seq_read_register(ucr, PPBUF_BASE2, (u16)buf_len, buf);
}
EXPORT_SYMBOL_GPL(rtsx_usb_read_ppbuf);
int rtsx_usb_write_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len)
{
return rtsx_usb_seq_write_register(ucr, PPBUF_BASE2, (u16)buf_len, buf);
}
EXPORT_SYMBOL_GPL(rtsx_usb_write_ppbuf);
int rtsx_usb_ep0_write_register(struct rtsx_ucr *ucr, u16 addr,
u8 mask, u8 data)
{
u16 value, index;
addr |= EP0_WRITE_REG_CMD << EP0_OP_SHIFT;
value = swab16(addr);
index = mask | data << 8;
return usb_control_msg(ucr->pusb_dev,
usb_sndctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, NULL, 0, 100);
}
EXPORT_SYMBOL_GPL(rtsx_usb_ep0_write_register);
int rtsx_usb_ep0_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data)
{
u16 value;
if (!data)
return -EINVAL;
*data = 0;
addr |= EP0_READ_REG_CMD << EP0_OP_SHIFT;
value = swab16(addr);
return usb_control_msg(ucr->pusb_dev,
usb_rcvctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, 0, data, 1, 100);
}
EXPORT_SYMBOL_GPL(rtsx_usb_ep0_read_register);
void rtsx_usb_add_cmd(struct rtsx_ucr *ucr, u8 cmd_type, u16 reg_addr,
u8 mask, u8 data)
{
int i;
if (ucr->cmd_idx < (IOBUF_SIZE - CMD_OFFSET) / 4) {
i = CMD_OFFSET + ucr->cmd_idx * 4;
ucr->cmd_buf[i++] = ((cmd_type & 0x03) << 6) |
(u8)((reg_addr >> 8) & 0x3F);
ucr->cmd_buf[i++] = (u8)reg_addr;
ucr->cmd_buf[i++] = mask;
ucr->cmd_buf[i++] = data;
ucr->cmd_idx++;
}
}
EXPORT_SYMBOL_GPL(rtsx_usb_add_cmd);
int rtsx_usb_send_cmd(struct rtsx_ucr *ucr, u8 flag, int timeout)
{
int ret;
ucr->cmd_buf[CNT_H] = (u8)(ucr->cmd_idx >> 8);
ucr->cmd_buf[CNT_L] = (u8)(ucr->cmd_idx);
ucr->cmd_buf[STAGE_FLAG] = flag;
ret = rtsx_usb_transfer_data(ucr,
usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT),
ucr->cmd_buf, ucr->cmd_idx * 4 + CMD_OFFSET,
0, NULL, timeout);
if (ret) {
rtsx_usb_clear_fsm_err(ucr);
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(rtsx_usb_send_cmd);
int rtsx_usb_get_rsp(struct rtsx_ucr *ucr, int rsp_len, int timeout)
{
if (rsp_len <= 0)
return -EINVAL;
rsp_len = ALIGN(rsp_len, 4);
return rtsx_usb_transfer_data(ucr,
usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN),
ucr->rsp_buf, rsp_len, 0, NULL, timeout);
}
EXPORT_SYMBOL_GPL(rtsx_usb_get_rsp);
static int rtsx_usb_get_status_with_bulk(struct rtsx_ucr *ucr, u16 *status)
{
int ret;
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_EXIST, 0x00, 0x00);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, OCPSTAT, 0x00, 0x00);
ret = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
if (ret)
return ret;
ret = rtsx_usb_get_rsp(ucr, 2, 100);
if (ret)
return ret;
*status = ((ucr->rsp_buf[0] >> 2) & 0x0f) |
((ucr->rsp_buf[1] & 0x03) << 4);
return 0;
}
int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status)
{
int ret;
if (!status)
return -EINVAL;
if (polling_pipe == 0)
ret = usb_control_msg(ucr->pusb_dev,
usb_rcvctrlpipe(ucr->pusb_dev, 0),
RTSX_USB_REQ_POLL,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, 0, status, 2, 100);
else
ret = rtsx_usb_get_status_with_bulk(ucr, status);
/* usb_control_msg may return positive when success */
if (ret < 0)
return ret;
return 0;
}
EXPORT_SYMBOL_GPL(rtsx_usb_get_card_status);
static int rtsx_usb_write_phy_register(struct rtsx_ucr *ucr, u8 addr, u8 val)
{
dev_dbg(&ucr->pusb_intf->dev, "Write 0x%x to phy register 0x%x\n",
val, addr);
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VSTAIN, 0xFF, val);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VCONTROL, 0xFF, addr & 0x0F);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VCONTROL,
0xFF, (addr >> 4) & 0x0F);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
int rtsx_usb_write_register(struct rtsx_ucr *ucr, u16 addr, u8 mask, u8 data)
{
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, addr, mask, data);
return rtsx_usb_send_cmd(ucr, MODE_C, 100);
}
EXPORT_SYMBOL_GPL(rtsx_usb_write_register);
int rtsx_usb_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data)
{
int ret;
if (data != NULL)
*data = 0;
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, READ_REG_CMD, addr, 0, 0);
ret = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
if (ret)
return ret;
ret = rtsx_usb_get_rsp(ucr, 1, 100);
if (ret)
return ret;
if (data != NULL)
*data = ucr->rsp_buf[0];
return 0;
}
EXPORT_SYMBOL_GPL(rtsx_usb_read_register);
static inline u8 double_ssc_depth(u8 depth)
{
return (depth > 1) ? (depth - 1) : depth;
}
static u8 revise_ssc_depth(u8 ssc_depth, u8 div)
{
if (div > CLK_DIV_1) {
if (ssc_depth > div - 1)
ssc_depth -= (div - 1);
else
ssc_depth = SSC_DEPTH_2M;
}
return ssc_depth;
}
int rtsx_usb_switch_clock(struct rtsx_ucr *ucr, unsigned int card_clock,
u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
{
int ret;
u8 n, clk_divider, mcu_cnt, div;
if (!card_clock) {
ucr->cur_clk = 0;
return 0;
}
if (initial_mode) {
/* We use 250k(around) here, in initial stage */
clk_divider = SD_CLK_DIVIDE_128;
card_clock = 30000000;
} else {
clk_divider = SD_CLK_DIVIDE_0;
}
ret = rtsx_usb_write_register(ucr, SD_CFG1,
SD_CLK_DIVIDE_MASK, clk_divider);
if (ret < 0)
return ret;
card_clock /= 1000000;
dev_dbg(&ucr->pusb_intf->dev,
"Switch card clock to %dMHz\n", card_clock);
if (!initial_mode && double_clk)
card_clock *= 2;
dev_dbg(&ucr->pusb_intf->dev,
"Internal SSC clock: %dMHz (cur_clk = %d)\n",
card_clock, ucr->cur_clk);
if (card_clock == ucr->cur_clk)
return 0;
/* Converting clock value into internal settings: n and div */
n = card_clock - 2;
if ((card_clock <= 2) || (n > MAX_DIV_N))
return -EINVAL;
mcu_cnt = 60/card_clock + 3;
if (mcu_cnt > 15)
mcu_cnt = 15;
/* Make sure that the SSC clock div_n is not less than MIN_DIV_N */
div = CLK_DIV_1;
while (n < MIN_DIV_N && div < CLK_DIV_4) {
n = (n + 2) * 2 - 2;
div++;
}
dev_dbg(&ucr->pusb_intf->dev, "n = %d, div = %d\n", n, div);
if (double_clk)
ssc_depth = double_ssc_depth(ssc_depth);
ssc_depth = revise_ssc_depth(ssc_depth, div);
dev_dbg(&ucr->pusb_intf->dev, "ssc_depth = %d\n", ssc_depth);
rtsx_usb_init_cmd(ucr);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV,
0x3F, (div << 4) | mcu_cnt);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL2,
SSC_DEPTH_MASK, ssc_depth);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
if (vpclk) {
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
PHASE_NOT_RESET, 0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
PHASE_NOT_RESET, PHASE_NOT_RESET);
}
ret = rtsx_usb_send_cmd(ucr, MODE_C, 2000);
if (ret < 0)
return ret;
ret = rtsx_usb_write_register(ucr, SSC_CTL1, 0xff,
SSC_RSTB | SSC_8X_EN | SSC_SEL_4M);
if (ret < 0)
return ret;
/* Wait SSC clock stable */
usleep_range(100, 1000);
ret = rtsx_usb_write_register(ucr, CLK_DIV, CLK_CHANGE, 0);
if (ret < 0)
return ret;
ucr->cur_clk = card_clock;
return 0;
}
EXPORT_SYMBOL_GPL(rtsx_usb_switch_clock);
int rtsx_usb_card_exclusive_check(struct rtsx_ucr *ucr, int card)
{
int ret;
u16 val;
u16 cd_mask[] = {
[RTSX_USB_SD_CARD] = (CD_MASK & ~SD_CD),
[RTSX_USB_MS_CARD] = (CD_MASK & ~MS_CD)
};
ret = rtsx_usb_get_card_status(ucr, &val);
/*
* If get status fails, return 0 (ok) for the exclusive check
* and let the flow fail at somewhere else.
*/
if (ret)
return 0;
if (val & cd_mask[card])
return -EIO;
return 0;
}
EXPORT_SYMBOL_GPL(rtsx_usb_card_exclusive_check);
static int rtsx_usb_reset_chip(struct rtsx_ucr *ucr)
{
int ret;
u8 val;
rtsx_usb_init_cmd(ucr);
if (CHECK_PKG(ucr, LQFP48)) {
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
LDO3318_PWR_MASK, LDO_SUSPEND);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
FORCE_LDO_POWERB, FORCE_LDO_POWERB);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1,
0x30, 0x10);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5,
0x03, 0x01);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6,
0x0C, 0x04);
}
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SYS_DUMMY0, NYET_MSAK, NYET_EN);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CD_DEGLITCH_WIDTH, 0xFF, 0x08);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
CD_DEGLITCH_EN, XD_CD_DEGLITCH_EN, 0x0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD30_DRIVE_SEL,
SD30_DRIVE_MASK, DRIVER_TYPE_D);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
CARD_DRIVE_SEL, SD20_DRIVE_MASK, 0x0);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG, 0xE0, 0x0);
if (ucr->is_rts5179)
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
CARD_PULL_CTL5, 0x03, 0x01);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DMA1_CTL,
EXTEND_DMA1_ASYNC_SIGNAL, EXTEND_DMA1_ASYNC_SIGNAL);
rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_INT_PEND,
XD_INT | MS_INT | SD_INT,
XD_INT | MS_INT | SD_INT);
ret = rtsx_usb_send_cmd(ucr, MODE_C, 100);
if (ret)
return ret;
/* config non-crystal mode */
rtsx_usb_read_register(ucr, CFG_MODE, &val);
if ((val & XTAL_FREE) || ((val & CLK_MODE_MASK) == CLK_MODE_NON_XTAL)) {
ret = rtsx_usb_write_phy_register(ucr, 0xC2, 0x7C);
if (ret)
return ret;
}
return 0;
}
static int rtsx_usb_init_chip(struct rtsx_ucr *ucr)
{
int ret;
u8 val;
rtsx_usb_clear_fsm_err(ucr);
/* power on SSC */
ret = rtsx_usb_write_register(ucr,
FPDCTL, SSC_POWER_MASK, SSC_POWER_ON);
if (ret)
return ret;
usleep_range(100, 1000);
ret = rtsx_usb_write_register(ucr, CLK_DIV, CLK_CHANGE, 0x00);
if (ret)
return ret;
/* determine IC version */
ret = rtsx_usb_read_register(ucr, HW_VERSION, &val);
if (ret)
return ret;
ucr->ic_version = val & HW_VER_MASK;
/* determine package */
ret = rtsx_usb_read_register(ucr, CARD_SHARE_MODE, &val);
if (ret)
return ret;
if (val & CARD_SHARE_LQFP_SEL) {
ucr->package = LQFP48;
dev_dbg(&ucr->pusb_intf->dev, "Package: LQFP48\n");
} else {
ucr->package = QFN24;
dev_dbg(&ucr->pusb_intf->dev, "Package: QFN24\n");
}
/* determine IC variations */
rtsx_usb_read_register(ucr, CFG_MODE_1, &val);
if (val & RTS5179) {
ucr->is_rts5179 = true;
dev_dbg(&ucr->pusb_intf->dev, "Device is rts5179\n");
} else {
ucr->is_rts5179 = false;
}
return rtsx_usb_reset_chip(ucr);
}
static int rtsx_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct rtsx_ucr *ucr;
int ret;
dev_dbg(&intf->dev,
": Realtek USB Card Reader found at bus %03d address %03d\n",
usb_dev->bus->busnum, usb_dev->devnum);
ucr = devm_kzalloc(&intf->dev, sizeof(*ucr), GFP_KERNEL);
if (!ucr)
return -ENOMEM;
ucr->pusb_dev = usb_dev;
ucr->iobuf = usb_alloc_coherent(ucr->pusb_dev, IOBUF_SIZE,
GFP_KERNEL, &ucr->iobuf_dma);
if (!ucr->iobuf)
return -ENOMEM;
usb_set_intfdata(intf, ucr);
ucr->vendor_id = id->idVendor;
ucr->product_id = id->idProduct;
ucr->cmd_buf = ucr->rsp_buf = ucr->iobuf;
mutex_init(&ucr->dev_mutex);
ucr->pusb_intf = intf;
/* initialize */
ret = rtsx_usb_init_chip(ucr);
if (ret)
goto out_init_fail;
ret = mfd_add_devices(&intf->dev, usb_dev->devnum, rtsx_usb_cells,
ARRAY_SIZE(rtsx_usb_cells), NULL, 0, NULL);
if (ret)
goto out_init_fail;
/* initialize USB SG transfer timer */
init_timer(&ucr->sg_timer);
setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr);
#ifdef CONFIG_PM
intf->needs_remote_wakeup = 1;
usb_enable_autosuspend(usb_dev);
#endif
return 0;
out_init_fail:
usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
ucr->iobuf_dma);
return ret;
}
static void rtsx_usb_disconnect(struct usb_interface *intf)
{
struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf);
dev_dbg(&intf->dev, "%s called\n", __func__);
mfd_remove_devices(&intf->dev);
usb_set_intfdata(ucr->pusb_intf, NULL);
usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
ucr->iobuf_dma);
}
#ifdef CONFIG_PM
static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
{
struct rtsx_ucr *ucr =
(struct rtsx_ucr *)usb_get_intfdata(intf);
dev_dbg(&intf->dev, "%s called with pm message 0x%04u\n",
__func__, message.event);
mutex_lock(&ucr->dev_mutex);
rtsx_usb_turn_off_led(ucr);
mutex_unlock(&ucr->dev_mutex);
return 0;
}
static int rtsx_usb_resume(struct usb_interface *intf)
{
return 0;
}
static int rtsx_usb_reset_resume(struct usb_interface *intf)
{
struct rtsx_ucr *ucr =
(struct rtsx_ucr *)usb_get_intfdata(intf);
rtsx_usb_reset_chip(ucr);
return 0;
}
#else /* CONFIG_PM */
#define rtsx_usb_suspend NULL
#define rtsx_usb_resume NULL
#define rtsx_usb_reset_resume NULL
#endif /* CONFIG_PM */
static int rtsx_usb_pre_reset(struct usb_interface *intf)
{
struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf);
mutex_lock(&ucr->dev_mutex);
return 0;
}
static int rtsx_usb_post_reset(struct usb_interface *intf)
{
struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf);
mutex_unlock(&ucr->dev_mutex);
return 0;
}
static struct usb_device_id rtsx_usb_usb_ids[] = {
{ USB_DEVICE(0x0BDA, 0x0129) },
{ USB_DEVICE(0x0BDA, 0x0139) },
{ USB_DEVICE(0x0BDA, 0x0140) },
{ }
};
static struct usb_driver rtsx_usb_driver = {
.name = "rtsx_usb",
.probe = rtsx_usb_probe,
.disconnect = rtsx_usb_disconnect,
.suspend = rtsx_usb_suspend,
.resume = rtsx_usb_resume,
.reset_resume = rtsx_usb_reset_resume,
.pre_reset = rtsx_usb_pre_reset,
.post_reset = rtsx_usb_post_reset,
.id_table = rtsx_usb_usb_ids,
.supports_autosuspend = 1,
.soft_unbind = 1,
};
module_usb_driver(rtsx_usb_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Roger Tseng <rogerable@realtek.com>");
MODULE_DESCRIPTION("Realtek USB Card Reader Driver");
......@@ -60,6 +60,7 @@ static const struct mfd_cell s5m8767_devs[] = {
.name = "s5m-rtc",
}, {
.name = "s5m8767-clk",
.of_compatible = "samsung,s5m8767-clk",
}
};
......@@ -68,6 +69,7 @@ static const struct mfd_cell s2mps11_devs[] = {
.name = "s2mps11-pmic",
}, {
.name = "s2mps11-clk",
.of_compatible = "samsung,s2mps11-clk",
}
};
......@@ -78,6 +80,7 @@ static const struct mfd_cell s2mps14_devs[] = {
.name = "s2mps14-rtc",
}, {
.name = "s2mps14-clk",
.of_compatible = "samsung,s2mps14-clk",
}
};
......@@ -295,6 +298,13 @@ static int sec_pmic_probe(struct i2c_client *i2c,
switch (sec_pmic->device_type) {
case S2MPA01:
regmap = &s2mpa01_regmap_config;
/*
* The rtc-s5m driver does not support S2MPA01 and there
* is no mfd_cell for S2MPA01 RTC device.
* However we must pass something to devm_regmap_init_i2c()
* so use S5M-like regmap config even though it wouldn't work.
*/
regmap_rtc = &s5m_rtc_regmap_config;
break;
case S2MPS11X:
regmap = &s2mps11_regmap_config;
......@@ -344,7 +354,7 @@ static int sec_pmic_probe(struct i2c_client *i2c,
ret = PTR_ERR(sec_pmic->regmap_rtc);
dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n",
ret);
return ret;
goto err_regmap_rtc;
}
if (pdata && pdata->cfg_pmic_irq)
......@@ -385,14 +395,15 @@ static int sec_pmic_probe(struct i2c_client *i2c,
}
if (ret)
goto err;
goto err_mfd;
device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup);
return ret;
err:
err_mfd:
sec_irq_exit(sec_pmic);
err_regmap_rtc:
i2c_unregister_device(sec_pmic->rtc);
return ret;
}
......
......@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
......
......@@ -706,7 +706,7 @@ static int stmpe1801_reset(struct stmpe *stmpe)
if (!(ret & STMPE1801_MSK_SYS_CTRL_RESET))
return 0;
usleep_range(100, 200);
};
}
return -EIO;
}
......
......@@ -167,7 +167,7 @@ static struct mfd_cell stw481x_cells[] = {
},
};
const struct regmap_config stw481x_regmap_config = {
static const struct regmap_config stw481x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
......@@ -186,6 +186,12 @@ static int stw481x_probe(struct i2c_client *client,
i2c_set_clientdata(client, stw481x);
stw481x->client = client;
stw481x->map = devm_regmap_init_i2c(client, &stw481x_regmap_config);
if (IS_ERR(stw481x->map)) {
ret = PTR_ERR(stw481x->map);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
ret);
return ret;
}
ret = stw481x_startup(stw481x);
if (ret) {
......
......@@ -69,13 +69,6 @@ EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible);
static int syscon_match_pdevname(struct device *dev, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
const struct platform_device_id *id = platform_get_device_id(pdev);
if (id)
if (!strcmp(id->name, (const char *)data))
return 1;
return !strcmp(dev_name(dev), (const char *)data);
}
......@@ -152,7 +145,7 @@ static int syscon_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, syscon);
dev_info(dev, "regmap %pR registered\n", res);
dev_dbg(dev, "regmap %pR registered\n", res);
return 0;
}
......
......@@ -13,8 +13,10 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tc3589x.h>
#include <linux/err.h>
/**
* enum tc3589x_version - indicates the TC3589x version
......@@ -160,7 +162,7 @@ static const struct mfd_cell tc3589x_dev_gpio[] = {
.name = "tc3589x-gpio",
.num_resources = ARRAY_SIZE(gpio_resources),
.resources = &gpio_resources[0],
.of_compatible = "tc3589x-gpio",
.of_compatible = "toshiba,tc3589x-gpio",
},
};
......@@ -169,7 +171,7 @@ static const struct mfd_cell tc3589x_dev_keypad[] = {
.name = "tc3589x-keypad",
.num_resources = ARRAY_SIZE(keypad_resources),
.resources = &keypad_resources[0],
.of_compatible = "tc3589x-keypad",
.of_compatible = "toshiba,tc3589x-keypad",
},
};
......@@ -318,45 +320,74 @@ static int tc3589x_device_init(struct tc3589x *tc3589x)
return ret;
}
static int tc3589x_of_probe(struct device_node *np,
struct tc3589x_platform_data *pdata)
#ifdef CONFIG_OF
static const struct of_device_id tc3589x_match[] = {
/* Legacy compatible string */
{ .compatible = "tc3589x", .data = (void *) TC3589X_UNKNOWN },
{ .compatible = "toshiba,tc35890", .data = (void *) TC3589X_TC35890 },
{ .compatible = "toshiba,tc35892", .data = (void *) TC3589X_TC35892 },
{ .compatible = "toshiba,tc35893", .data = (void *) TC3589X_TC35893 },
{ .compatible = "toshiba,tc35894", .data = (void *) TC3589X_TC35894 },
{ .compatible = "toshiba,tc35895", .data = (void *) TC3589X_TC35895 },
{ .compatible = "toshiba,tc35896", .data = (void *) TC3589X_TC35896 },
{ }
};
MODULE_DEVICE_TABLE(of, tc3589x_match);
static struct tc3589x_platform_data *
tc3589x_of_probe(struct device *dev, enum tc3589x_version *version)
{
struct device_node *np = dev->of_node;
struct tc3589x_platform_data *pdata;
struct device_node *child;
const struct of_device_id *of_id;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
of_id = of_match_device(tc3589x_match, dev);
if (!of_id)
return ERR_PTR(-ENODEV);
*version = (enum tc3589x_version) of_id->data;
for_each_child_of_node(np, child) {
if (!strcmp(child->name, "tc3589x_gpio")) {
if (of_device_is_compatible(child, "toshiba,tc3589x-gpio"))
pdata->block |= TC3589x_BLOCK_GPIO;
}
if (!strcmp(child->name, "tc3589x_keypad")) {
if (of_device_is_compatible(child, "toshiba,tc3589x-keypad"))
pdata->block |= TC3589x_BLOCK_KEYPAD;
}
}
return 0;
return pdata;
}
#else
static inline struct tc3589x_platform_data *
tc3589x_of_probe(struct device *dev, enum tc3589x_version *version)
{
dev_err(dev, "no device tree support\n");
return ERR_PTR(-ENODEV);
}
#endif
static int tc3589x_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct tc3589x_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct device_node *np = i2c->dev.of_node;
struct tc3589x_platform_data *pdata = dev_get_platdata(&i2c->dev);
struct tc3589x *tc3589x;
enum tc3589x_version version;
int ret;
if (!pdata) {
if (np) {
pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
ret = tc3589x_of_probe(np, pdata);
if (ret)
return ret;
}
else {
pdata = tc3589x_of_probe(&i2c->dev, &version);
if (IS_ERR(pdata)) {
dev_err(&i2c->dev, "No platform data or DT found\n");
return -EINVAL;
return PTR_ERR(pdata);
}
} else {
/* When not probing from device tree we have this ID */
version = id->driver_data;
}
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA
......@@ -375,7 +406,7 @@ static int tc3589x_probe(struct i2c_client *i2c,
tc3589x->pdata = pdata;
tc3589x->irq_base = pdata->irq_base;
switch (id->driver_data) {
switch (version) {
case TC3589X_TC35893:
case TC3589X_TC35895:
case TC3589X_TC35896:
......@@ -471,9 +502,12 @@ static const struct i2c_device_id tc3589x_id[] = {
MODULE_DEVICE_TABLE(i2c, tc3589x_id);
static struct i2c_driver tc3589x_driver = {
.driver.name = "tc3589x",
.driver.owner = THIS_MODULE,
.driver.pm = &tc3589x_dev_pm_ops,
.driver = {
.name = "tc3589x",
.owner = THIS_MODULE,
.pm = &tc3589x_dev_pm_ops,
.of_match_table = of_match_ptr(tc3589x_match),
},
.probe = tc3589x_probe,
.remove = tc3589x_remove,
.id_table = tc3589x_id,
......
/*
* Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
*
* Copyright (C) 2010 Texas Instruments Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/sched.h>
#include <linux/mfd/core.h>
#include <linux/mfd/ti_ssp.h>
/* Register Offsets */
#define REG_REV 0x00
#define REG_IOSEL_1 0x04
#define REG_IOSEL_2 0x08
#define REG_PREDIV 0x0c
#define REG_INTR_ST 0x10
#define REG_INTR_EN 0x14
#define REG_TEST_CTRL 0x18
/* Per port registers */
#define PORT_CFG_2 0x00
#define PORT_ADDR 0x04
#define PORT_DATA 0x08
#define PORT_CFG_1 0x0c
#define PORT_STATE 0x10
#define SSP_PORT_CONFIG_MASK (SSP_EARLY_DIN | SSP_DELAY_DOUT)
#define SSP_PORT_CLKRATE_MASK 0x0f
#define SSP_SEQRAM_WR_EN BIT(4)
#define SSP_SEQRAM_RD_EN BIT(5)
#define SSP_START BIT(15)
#define SSP_BUSY BIT(10)
#define SSP_PORT_ASL BIT(7)
#define SSP_PORT_CFO1 BIT(6)
#define SSP_PORT_SEQRAM_SIZE 32
static const int ssp_port_base[] = {0x040, 0x080};
static const int ssp_port_seqram[] = {0x100, 0x180};
struct ti_ssp {
struct resource *res;
struct device *dev;
void __iomem *regs;
spinlock_t lock;
struct clk *clk;
int irq;
wait_queue_head_t wqh;
/*
* Some of the iosel2 register bits always read-back as 0, we need to
* remember these values so that we don't clobber previously set
* values.
*/
u32 iosel2;
};
static inline struct ti_ssp *dev_to_ssp(struct device *dev)
{
return dev_get_drvdata(dev->parent);
}
static inline int dev_to_port(struct device *dev)
{
return to_platform_device(dev)->id;
}
/* Register Access Helpers, rmw() functions need to run locked */
static inline u32 ssp_read(struct ti_ssp *ssp, int reg)
{
return __raw_readl(ssp->regs + reg);
}
static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val)
{
__raw_writel(val, ssp->regs + reg);
}
static inline void ssp_rmw(struct ti_ssp *ssp, int reg, u32 mask, u32 bits)
{
ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~mask) | bits);
}
static inline u32 ssp_port_read(struct ti_ssp *ssp, int port, int reg)
{
return ssp_read(ssp, ssp_port_base[port] + reg);
}
static inline void ssp_port_write(struct ti_ssp *ssp, int port, int reg,
u32 val)
{
ssp_write(ssp, ssp_port_base[port] + reg, val);
}
static inline void ssp_port_rmw(struct ti_ssp *ssp, int port, int reg,
u32 mask, u32 bits)
{
ssp_rmw(ssp, ssp_port_base[port] + reg, mask, bits);
}
static inline void ssp_port_clr_bits(struct ti_ssp *ssp, int port, int reg,
u32 bits)
{
ssp_port_rmw(ssp, port, reg, bits, 0);
}
static inline void ssp_port_set_bits(struct ti_ssp *ssp, int port, int reg,
u32 bits)
{
ssp_port_rmw(ssp, port, reg, 0, bits);
}
/* Called to setup port clock mode, caller must hold ssp->lock */
static int __set_mode(struct ti_ssp *ssp, int port, int mode)
{
mode &= SSP_PORT_CONFIG_MASK;
ssp_port_rmw(ssp, port, PORT_CFG_1, SSP_PORT_CONFIG_MASK, mode);
return 0;
}
int ti_ssp_set_mode(struct device *dev, int mode)
{
struct ti_ssp *ssp = dev_to_ssp(dev);
int port = dev_to_port(dev);
int ret;
spin_lock(&ssp->lock);
ret = __set_mode(ssp, port, mode);
spin_unlock(&ssp->lock);
return ret;
}
EXPORT_SYMBOL(ti_ssp_set_mode);
/* Called to setup iosel2, caller must hold ssp->lock */
static void __set_iosel2(struct ti_ssp *ssp, u32 mask, u32 val)
{
ssp->iosel2 = (ssp->iosel2 & ~mask) | val;
ssp_write(ssp, REG_IOSEL_2, ssp->iosel2);
}
/* Called to setup port iosel, caller must hold ssp->lock */
static void __set_iosel(struct ti_ssp *ssp, int port, u32 iosel)
{
unsigned val, shift = port ? 16 : 0;
/* IOSEL1 gets the least significant 16 bits */
val = ssp_read(ssp, REG_IOSEL_1);
val &= 0xffff << (port ? 0 : 16);
val |= (iosel & 0xffff) << (port ? 16 : 0);
ssp_write(ssp, REG_IOSEL_1, val);
/* IOSEL2 gets the most significant 16 bits */
val = (iosel >> 16) & 0x7;
__set_iosel2(ssp, 0x7 << shift, val << shift);
}
int ti_ssp_set_iosel(struct device *dev, u32 iosel)
{
struct ti_ssp *ssp = dev_to_ssp(dev);
int port = dev_to_port(dev);
spin_lock(&ssp->lock);
__set_iosel(ssp, port, iosel);
spin_unlock(&ssp->lock);
return 0;
}
EXPORT_SYMBOL(ti_ssp_set_iosel);
int ti_ssp_load(struct device *dev, int offs, u32* prog, int len)
{
struct ti_ssp *ssp = dev_to_ssp(dev);
int port = dev_to_port(dev);
int i;
if (len > SSP_PORT_SEQRAM_SIZE)
return -ENOSPC;
spin_lock(&ssp->lock);
/* Enable SeqRAM access */
ssp_port_set_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
/* Copy code */
for (i = 0; i < len; i++) {
__raw_writel(prog[i], ssp->regs + offs + 4*i +
ssp_port_seqram[port]);
}
/* Disable SeqRAM access */
ssp_port_clr_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
spin_unlock(&ssp->lock);
return 0;
}
EXPORT_SYMBOL(ti_ssp_load);
int ti_ssp_raw_read(struct device *dev)
{
struct ti_ssp *ssp = dev_to_ssp(dev);
int port = dev_to_port(dev);
int shift = port ? 27 : 11;
return (ssp_read(ssp, REG_IOSEL_2) >> shift) & 0xf;
}
EXPORT_SYMBOL(ti_ssp_raw_read);
int ti_ssp_raw_write(struct device *dev, u32 val)
{
struct ti_ssp *ssp = dev_to_ssp(dev);
int port = dev_to_port(dev), shift;
spin_lock(&ssp->lock);
shift = port ? 22 : 6;
val &= 0xf;
__set_iosel2(ssp, 0xf << shift, val << shift);
spin_unlock(&ssp->lock);
return 0;
}
EXPORT_SYMBOL(ti_ssp_raw_write);
static inline int __xfer_done(struct ti_ssp *ssp, int port)
{
return !(ssp_port_read(ssp, port, PORT_CFG_1) & SSP_BUSY);
}
int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output)
{
struct ti_ssp *ssp = dev_to_ssp(dev);
int port = dev_to_port(dev);
int ret;
if (pc & ~(0x3f))
return -EINVAL;
/* Grab ssp->lock to serialize rmw on ssp registers */
spin_lock(&ssp->lock);
ssp_port_write(ssp, port, PORT_ADDR, input >> 16);
ssp_port_write(ssp, port, PORT_DATA, input & 0xffff);
ssp_port_rmw(ssp, port, PORT_CFG_1, 0x3f, pc);
/* grab wait queue head lock to avoid race with the isr */
spin_lock_irq(&ssp->wqh.lock);
/* kick off sequence execution in hardware */
ssp_port_set_bits(ssp, port, PORT_CFG_1, SSP_START);
/* drop ssp lock; no register writes beyond this */
spin_unlock(&ssp->lock);
ret = wait_event_interruptible_locked_irq(ssp->wqh,
__xfer_done(ssp, port));
spin_unlock_irq(&ssp->wqh.lock);
if (ret < 0)
return ret;
if (output) {
*output = (ssp_port_read(ssp, port, PORT_ADDR) << 16) |
(ssp_port_read(ssp, port, PORT_DATA) & 0xffff);
}
ret = ssp_port_read(ssp, port, PORT_STATE) & 0x3f; /* stop address */
return ret;
}
EXPORT_SYMBOL(ti_ssp_run);
static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data)
{
struct ti_ssp *ssp = dev_data;
spin_lock(&ssp->wqh.lock);
ssp_write(ssp, REG_INTR_ST, 0x3);
wake_up_locked(&ssp->wqh);
spin_unlock(&ssp->wqh.lock);
return IRQ_HANDLED;
}
static int ti_ssp_probe(struct platform_device *pdev)
{
static struct ti_ssp *ssp;
const struct ti_ssp_data *pdata = dev_get_platdata(&pdev->dev);
int error = 0, prediv = 0xff, id;
unsigned long sysclk;
struct device *dev = &pdev->dev;
struct mfd_cell cells[2];
ssp = kzalloc(sizeof(*ssp), GFP_KERNEL);
if (!ssp) {
dev_err(dev, "cannot allocate device info\n");
return -ENOMEM;
}
ssp->dev = dev;
dev_set_drvdata(dev, ssp);
ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!ssp->res) {
error = -ENODEV;
dev_err(dev, "cannot determine register area\n");
goto error_res;
}
if (!request_mem_region(ssp->res->start, resource_size(ssp->res),
pdev->name)) {
error = -ENOMEM;
dev_err(dev, "cannot claim register memory\n");
goto error_res;
}
ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res));
if (!ssp->regs) {
error = -ENOMEM;
dev_err(dev, "cannot map register memory\n");
goto error_map;
}
ssp->clk = clk_get(dev, NULL);
if (IS_ERR(ssp->clk)) {
error = PTR_ERR(ssp->clk);
dev_err(dev, "cannot claim device clock\n");
goto error_clk;
}
ssp->irq = platform_get_irq(pdev, 0);
if (ssp->irq < 0) {
error = -ENODEV;
dev_err(dev, "unknown irq\n");
goto error_irq;
}
error = request_threaded_irq(ssp->irq, NULL, ti_ssp_interrupt, 0,
dev_name(dev), ssp);
if (error < 0) {
dev_err(dev, "cannot acquire irq\n");
goto error_irq;
}
spin_lock_init(&ssp->lock);
init_waitqueue_head(&ssp->wqh);
/* Power on and initialize SSP */
error = clk_enable(ssp->clk);
if (error) {
dev_err(dev, "cannot enable device clock\n");
goto error_enable;
}
/* Reset registers to a sensible known state */
ssp_write(ssp, REG_IOSEL_1, 0);
ssp_write(ssp, REG_IOSEL_2, 0);
ssp_write(ssp, REG_INTR_EN, 0x3);
ssp_write(ssp, REG_INTR_ST, 0x3);
ssp_write(ssp, REG_TEST_CTRL, 0);
ssp_port_write(ssp, 0, PORT_CFG_1, SSP_PORT_ASL);
ssp_port_write(ssp, 1, PORT_CFG_1, SSP_PORT_ASL);
ssp_port_write(ssp, 0, PORT_CFG_2, SSP_PORT_CFO1);
ssp_port_write(ssp, 1, PORT_CFG_2, SSP_PORT_CFO1);
sysclk = clk_get_rate(ssp->clk);
if (pdata && pdata->out_clock)
prediv = (sysclk / pdata->out_clock) - 1;
prediv = clamp(prediv, 0, 0xff);
ssp_rmw(ssp, REG_PREDIV, 0xff, prediv);
memset(cells, 0, sizeof(cells));
for (id = 0; id < 2; id++) {
const struct ti_ssp_dev_data *data = &pdata->dev_data[id];
cells[id].id = id;
cells[id].name = data->dev_name;
cells[id].platform_data = data->pdata;
}
error = mfd_add_devices(dev, 0, cells, 2, NULL, 0, NULL);
if (error < 0) {
dev_err(dev, "cannot add mfd cells\n");
goto error_enable;
}
return 0;
error_enable:
free_irq(ssp->irq, ssp);
error_irq:
clk_put(ssp->clk);
error_clk:
iounmap(ssp->regs);
error_map:
release_mem_region(ssp->res->start, resource_size(ssp->res));
error_res:
kfree(ssp);
return error;
}
static int ti_ssp_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ti_ssp *ssp = dev_get_drvdata(dev);
mfd_remove_devices(dev);
clk_disable(ssp->clk);
free_irq(ssp->irq, ssp);
clk_put(ssp->clk);
iounmap(ssp->regs);
release_mem_region(ssp->res->start, resource_size(ssp->res));
kfree(ssp);
return 0;
}
static struct platform_driver ti_ssp_driver = {
.probe = ti_ssp_probe,
.remove = ti_ssp_remove,
.driver = {
.name = "ti-ssp",
.owner = THIS_MODULE,
}
};
module_platform_driver(ti_ssp_driver);
MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
MODULE_AUTHOR("Cyril Chemparathy");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ti-ssp");
......@@ -14,7 +14,6 @@
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/io.h>
......@@ -184,12 +183,6 @@ static int ti_tscadc_probe(struct platform_device *pdev)
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no memory resource defined.\n");
return -EINVAL;
}
/* Allocate memory for device */
tscadc = devm_kzalloc(&pdev->dev,
sizeof(struct ti_tscadc_dev), GFP_KERNEL);
......@@ -206,19 +199,10 @@ static int ti_tscadc_probe(struct platform_device *pdev)
} else
tscadc->irq = err;
res = devm_request_mem_region(&pdev->dev,
res->start, resource_size(res), pdev->name);
if (!res) {
dev_err(&pdev->dev, "failed to reserve registers.\n");
return -EBUSY;
}
tscadc->tscadc_base = devm_ioremap(&pdev->dev,
res->start, resource_size(res));
if (!tscadc->tscadc_base) {
dev_err(&pdev->dev, "failed to map registers.\n");
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tscadc->tscadc_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(tscadc->tscadc_base))
return PTR_ERR(tscadc->tscadc_base);
tscadc->regmap_tscadc = devm_regmap_init_mmio(&pdev->dev,
tscadc->tscadc_base, &tscadc_regmap_config);
......
......@@ -715,7 +715,7 @@ static int timb_probe(struct pci_dev *dev,
for (i = 0; i < TIMBERDALE_NR_IRQS; i++)
msix_entries[i].entry = i;
err = pci_enable_msix(dev, msix_entries, TIMBERDALE_NR_IRQS);
err = pci_enable_msix_exact(dev, msix_entries, TIMBERDALE_NR_IRQS);
if (err) {
dev_err(&dev->dev,
"MSI-X init failed: %d, expected entries: %d\n",
......
此差异已折叠。
......@@ -255,8 +255,10 @@ static int tps65910_irq_init(struct tps65910 *tps65910, int irq,
ret = regmap_add_irq_chip(tps65910->regmap, tps65910->chip_irq,
IRQF_ONESHOT, pdata->irq_base,
tps6591x_irqs_chip, &tps65910->irq_data);
if (ret < 0)
if (ret < 0) {
dev_warn(tps65910->dev, "Failed to add irq_chip %d\n", ret);
tps65910->chip_irq = 0;
}
return ret;
}
......@@ -509,6 +511,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
regmap_irq_get_domain(tps65910->irq_data));
if (ret < 0) {
dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret);
tps65910_irq_exit(tps65910);
return ret;
}
......
......@@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/mfd/core.h>
......
......@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/bug.h>
#include <linux/device.h>
#include <linux/interrupt.h>
......
......@@ -282,11 +282,11 @@ static struct reg_default twl4030_49_defaults[] = {
static bool twl4030_49_nop_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case 0:
case 3:
case 40:
case 41:
case 42:
case 0x00:
case 0x03:
case 0x40:
case 0x41:
case 0x42:
return false;
default:
return true;
......
......@@ -27,7 +27,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
......
......@@ -31,7 +31,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/export.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
......
......@@ -661,6 +661,11 @@ static int twl6040_probe(struct i2c_client *client,
init_completion(&twl6040->ready);
twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV);
if (twl6040->rev < 0) {
dev_err(&client->dev, "Failed to read revision register: %d\n",
twl6040->rev);
goto gpio_err;
}
/* ERRATA: Automatic power-up is not possible in ES1.0 */
if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0)
......@@ -703,7 +708,6 @@ static int twl6040_probe(struct i2c_client *client,
}
/* dual-access registers controlled by I2C only */
twl6040_set_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_I2CSEL);
regmap_register_patch(twl6040->regmap, twl6040_patch,
ARRAY_SIZE(twl6040_patch));
......
......@@ -742,9 +742,7 @@ static int ucb1x00_resume(struct device *dev)
}
#endif
static const struct dev_pm_ops ucb1x00_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ucb1x00_suspend, ucb1x00_resume)
};
static SIMPLE_DEV_PM_OPS(ucb1x00_pm_ops, ucb1x00_suspend, ucb1x00_resume);
static struct mcp_driver ucb1x00_driver = {
.drv = {
......
......@@ -16,7 +16,6 @@
#include <linux/bitops.h>
#include <linux/completion.h>
#include <linux/export.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/of.h>
#include <linux/of_device.h>
......@@ -27,7 +26,7 @@
#define VEXPRESS_CONFIG_MAX_BRIDGES 2
struct vexpress_config_bridge {
static struct vexpress_config_bridge {
struct device_node *node;
struct vexpress_config_bridge_info *info;
struct list_head transactions;
......
......@@ -168,7 +168,7 @@ static void *vexpress_sysreg_config_func_get(struct device *dev,
struct device_node *node)
{
struct vexpress_sysreg_config_func *config_func;
u32 site;
u32 site = 0;
u32 position = 0;
u32 dcc = 0;
u32 func_device[2];
......
......@@ -73,6 +73,7 @@ static const struct reg_default wm5102_revb_patch[] = {
{ 0x171, 0x0000 },
{ 0x35E, 0x000C },
{ 0x2D4, 0x0000 },
{ 0x4DC, 0x0900 },
{ 0x80, 0x0000 },
};
......@@ -1839,6 +1840,23 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_DSP1_STATUS_1:
case ARIZONA_DSP1_STATUS_2:
case ARIZONA_DSP1_STATUS_3:
case ARIZONA_DSP1_WDMA_BUFFER_1:
case ARIZONA_DSP1_WDMA_BUFFER_2:
case ARIZONA_DSP1_WDMA_BUFFER_3:
case ARIZONA_DSP1_WDMA_BUFFER_4:
case ARIZONA_DSP1_WDMA_BUFFER_5:
case ARIZONA_DSP1_WDMA_BUFFER_6:
case ARIZONA_DSP1_WDMA_BUFFER_7:
case ARIZONA_DSP1_WDMA_BUFFER_8:
case ARIZONA_DSP1_RDMA_BUFFER_1:
case ARIZONA_DSP1_RDMA_BUFFER_2:
case ARIZONA_DSP1_RDMA_BUFFER_3:
case ARIZONA_DSP1_RDMA_BUFFER_4:
case ARIZONA_DSP1_RDMA_BUFFER_5:
case ARIZONA_DSP1_RDMA_BUFFER_6:
case ARIZONA_DSP1_WDMA_CONFIG_1:
case ARIZONA_DSP1_WDMA_CONFIG_2:
case ARIZONA_DSP1_RDMA_CONFIG_1:
case ARIZONA_DSP1_SCRATCH_0:
case ARIZONA_DSP1_SCRATCH_1:
case ARIZONA_DSP1_SCRATCH_2:
......@@ -1894,9 +1912,27 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg)
case ARIZONA_AOD_IRQ1:
case ARIZONA_AOD_IRQ2:
case ARIZONA_AOD_IRQ_RAW_STATUS:
case ARIZONA_DSP1_CLOCKING_1:
case ARIZONA_DSP1_STATUS_1:
case ARIZONA_DSP1_STATUS_2:
case ARIZONA_DSP1_STATUS_3:
case ARIZONA_DSP1_WDMA_BUFFER_1:
case ARIZONA_DSP1_WDMA_BUFFER_2:
case ARIZONA_DSP1_WDMA_BUFFER_3:
case ARIZONA_DSP1_WDMA_BUFFER_4:
case ARIZONA_DSP1_WDMA_BUFFER_5:
case ARIZONA_DSP1_WDMA_BUFFER_6:
case ARIZONA_DSP1_WDMA_BUFFER_7:
case ARIZONA_DSP1_WDMA_BUFFER_8:
case ARIZONA_DSP1_RDMA_BUFFER_1:
case ARIZONA_DSP1_RDMA_BUFFER_2:
case ARIZONA_DSP1_RDMA_BUFFER_3:
case ARIZONA_DSP1_RDMA_BUFFER_4:
case ARIZONA_DSP1_RDMA_BUFFER_5:
case ARIZONA_DSP1_RDMA_BUFFER_6:
case ARIZONA_DSP1_WDMA_CONFIG_1:
case ARIZONA_DSP1_WDMA_CONFIG_2:
case ARIZONA_DSP1_RDMA_CONFIG_1:
case ARIZONA_DSP1_SCRATCH_0:
case ARIZONA_DSP1_SCRATCH_1:
case ARIZONA_DSP1_SCRATCH_2:
......
此差异已折叠。
......@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/bug.h>
#include <linux/device.h>
......
......@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/bug.h>
#include <linux/device.h>
#include <linux/interrupt.h>
......
......@@ -161,31 +161,19 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8400 *wm8400;
int ret;
wm8400 = devm_kzalloc(&i2c->dev, sizeof(struct wm8400), GFP_KERNEL);
if (wm8400 == NULL) {
ret = -ENOMEM;
goto err;
}
if (!wm8400)
return -ENOMEM;
wm8400->regmap = devm_regmap_init_i2c(i2c, &wm8400_regmap_config);
if (IS_ERR(wm8400->regmap)) {
ret = PTR_ERR(wm8400->regmap);
goto err;
}
if (IS_ERR(wm8400->regmap))
return PTR_ERR(wm8400->regmap);
wm8400->dev = &i2c->dev;
i2c_set_clientdata(i2c, wm8400);
ret = wm8400_init(wm8400, dev_get_platdata(&i2c->dev));
if (ret != 0)
goto err;
return 0;
err:
return ret;
return wm8400_init(wm8400, dev_get_platdata(&i2c->dev));
}
static int wm8400_i2c_remove(struct i2c_client *i2c)
......
此差异已折叠。
......@@ -195,6 +195,18 @@ static inline int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg) {
return twl_i2c_read(mod_no, val, reg, 1);
}
static inline int twl_i2c_write_u16(u8 mod_no, u16 val, u8 reg) {
val = cpu_to_le16(val);
return twl_i2c_write(mod_no, (u8*) &val, reg, 2);
}
static inline int twl_i2c_read_u16(u8 mod_no, u16 *val, u8 reg) {
int ret;
ret = twl_i2c_read(mod_no, (u8*) val, reg, 2);
*val = le16_to_cpu(*val);
return ret;
}
int twl_get_type(void);
int twl_get_version(void);
int twl_get_hfclk_rate(void);
......
......@@ -44,7 +44,7 @@ struct twl4030_madc_conversion_method {
struct twl4030_madc_request {
unsigned long channels;
u16 do_avg;
bool do_avg;
u16 method;
u16 type;
bool active;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部